forward messages if the agent is connected and has VD_AGENT_CAP_KEYSYM

Index: new/server/inputs_channel.c
===================================================================
--- new.orig/server/inputs_channel.c	2013-10-14 13:36:58.000000000 +0200
+++ new/server/inputs_channel.c	2013-10-14 15:04:19.000000000 +0200
@@ -361,7 +361,9 @@
     }
     case SPICE_MSGC_INPUTS_KEY_X11_KEYSYM: {
         SpiceMsgcKeyX11KeySym *msg = (SpiceMsgcKeyX11KeySym *)buf;
-        kbd_push_x11_keysym(keyboard, msg->keysym, msg->flags, msg->code_len, msg->code);
+        if (!reds_handle_agent_keysm(msg->keysym, msg->flags)) {
+            kbd_push_x11_keysym(keyboard, msg->keysym, msg->flags, msg->code_len, msg->code);
+        }
         break;
     }
     case SPICE_MSGC_INPUTS_MOUSE_MOTION: {
Index: new/server/reds-private.h
===================================================================
--- new.orig/server/reds-private.h	2013-10-14 12:58:49.000000000 +0200
+++ new/server/reds-private.h	2013-10-14 13:36:58.000000000 +0200
@@ -75,6 +75,7 @@
     VDAgentMessage header;
     union {
         VDAgentMouseState mouse_state;
+        VDAgentKeySym keysym_msg;
     }
     u;
 } VDInternalBuf;
Index: new/server/reds.c
===================================================================
--- new.orig/server/reds.c	2013-10-14 12:58:49.000000000 +0200
+++ new/server/reds.c	2013-10-14 15:03:56.000000000 +0200
@@ -888,6 +888,43 @@
     return !!vdagent;
 }
 
+int reds_handle_agent_keysm(uint32_t keysym, uint32_t flags)
+{
+    SpiceCharDeviceWriteBuffer *char_dev_buf;
+    VDInternalBuf *internal_buf;
+    uint32_t total_msg_size;
+
+    if (!vdagent || !inputs_inited() || !reds->agent_state.base || !reds->agent_state.read_filter.send_keysym) {
+        return 0;
+    }
+
+    total_msg_size = sizeof(VDIChunkHeader) + sizeof(VDAgentMessage) +
+        sizeof(VDAgentKeySym);
+
+    char_dev_buf = spice_char_device_write_buffer_get(reds->agent_state.base,
+                                                      NULL, total_msg_size);
+
+    if (!char_dev_buf) {
+        // fixme: how should we handle this?
+        return 0;
+    }
+
+    internal_buf = (VDInternalBuf *)char_dev_buf->buf;
+    internal_buf->chunk_header.port = VDP_SERVER_PORT;
+    internal_buf->chunk_header.size = sizeof(VDAgentMessage) + sizeof(VDAgentKeySym);
+    internal_buf->header.protocol = VD_AGENT_PROTOCOL;
+    internal_buf->header.type = VD_AGENT_KEYSYM_MESSAGE;
+    internal_buf->header.opaque = 0;
+    internal_buf->header.size = sizeof(VDAgentKeySym);
+    internal_buf->u.keysym_msg.keysym = keysym;
+    internal_buf->u.keysym_msg.flags = flags;
+
+    char_dev_buf->buf_used = total_msg_size;
+    spice_char_device_write_buffer_add(reds->agent_state.base, char_dev_buf);
+
+    return 1;
+}
+
 void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state)
 {
     SpiceCharDeviceWriteBuffer *char_dev_buf;
Index: new/server/reds.h
===================================================================
--- new.orig/server/reds.h	2013-10-14 12:58:49.000000000 +0200
+++ new/server/reds.h	2013-10-14 15:01:48.000000000 +0200
@@ -132,6 +132,7 @@
 int reds_get_agent_mouse(void); // used by inputs_channel
 int reds_has_vdagent(void); // used by inputs channel
 void reds_handle_agent_mouse_event(const VDAgentMouseState *mouse_state); // used by inputs_channel
+int reds_handle_agent_keysm(uint32_t keysym, uint32_t flags);
 
 extern struct SpiceCoreInterface *core;
 
Index: new/server/agent-msg-filter.c
===================================================================
--- new.orig/server/agent-msg-filter.c	2013-10-14 12:58:49.000000000 +0200
+++ new/server/agent-msg-filter.c	2013-10-14 15:08:56.000000000 +0200
@@ -52,7 +52,9 @@
             spice_printerr("invalid agent message: data exceeds size from header");
             return AGENT_MSG_FILTER_PROTO_ERROR;
         }
+
         filter->msg_data_to_read -= len;
+
         return filter->result;
     }
 
@@ -98,6 +100,16 @@
                 filter->result = AGENT_MSG_FILTER_OK;
             }
             break;
+        case VD_AGENT_ANNOUNCE_CAPABILITIES:
+            // fixme: this only works if we receive the whole message at once!
+             if (len >= 8) {
+                VDAgentAnnounceCapabilities *caps = (VDAgentAnnounceCapabilities *)(data + sizeof(msg_header));
+                if (VD_AGENT_HAS_CAPABILITY(caps->caps, 1, VD_AGENT_CAP_KEYSYM)) {
+                    filter->send_keysym = 1;
+                }
+            }
+            filter->result = AGENT_MSG_FILTER_OK;
+            break;
         default:
             filter->result = AGENT_MSG_FILTER_OK;
         }
Index: new/server/agent-msg-filter.h
===================================================================
--- new.orig/server/agent-msg-filter.h	2013-10-14 12:58:49.000000000 +0200
+++ new/server/agent-msg-filter.h	2013-10-14 14:44:20.000000000 +0200
@@ -38,6 +38,7 @@
     int copy_paste_enabled;
     int file_xfer_enabled;
     int discard_all;
+    int send_keysym;
 } AgentMsgFilter;
 
 void agent_msg_filter_init(struct AgentMsgFilter *filter,

