Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>

Index: new/gtk/channel-main.c
===================================================================
--- new.orig/gtk/channel-main.c	2013-10-07 11:01:52.000000000 +0200
+++ new/gtk/channel-main.c	2013-10-07 11:02:51.000000000 +0200
@@ -191,6 +191,7 @@
     [ VD_AGENT_CAP_DISPLAY_CONFIG      ] = "display config",
     [ VD_AGENT_CAP_CLIPBOARD_BY_DEMAND ] = "clipboard",
     [ VD_AGENT_CAP_CLIPBOARD_SELECTION ] = "clipboard selection",
+    [ VD_AGENT_CAP_KEYVAL              ] = "keyval input extension",
 };
 #define NAME(_a, _i) ((_i) < SPICE_N_ELEMENTS(_a) ? (_a[(_i)] ?: "?") : "?")
 
@@ -1052,6 +1053,40 @@
     agent_msg_queue_many((Channel), (Type), (Data), (Size), NULL)
 
 /**
+ * spice_main_send_keyval:
+ * @channel:
+ *
+ * Send keyboard events to vdagent
+ *
+ * Returns: %TRUE on success.
+ **/
+gboolean spice_main_send_keyval(SpiceMainChannel *channel, uint32_t keyval,  uint32_t flags)
+{
+    SpiceMainChannelPrivate *c;
+    VDAgentKeyval kv;
+
+    g_return_val_if_fail(SPICE_IS_MAIN_CHANNEL(channel), FALSE);
+    c = channel->priv;
+
+    if (!c->agent_connected) {
+        return FALSE;
+    }
+
+    if (!spice_main_agent_test_capability(channel, VD_AGENT_CAP_KEYVAL)) {
+        return FALSE;
+    }
+
+    kv.keyval = keyval;
+    kv.flags = flags;
+
+    agent_msg_queue(channel, VD_AGENT_KEYVAL, sizeof(kv), &kv);
+
+    spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
+
+    return TRUE;
+}
+
+/**
  * spice_main_send_monitor_config:
  * @channel:
  *
@@ -1175,6 +1210,7 @@
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_DISPLAY_CONFIG);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_BY_DEMAND);
     VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_CLIPBOARD_SELECTION);
+    VD_AGENT_SET_CAPABILITY(caps->caps, VD_AGENT_CAP_KEYVAL);
 
     agent_msg_queue(channel, VD_AGENT_ANNOUNCE_CAPABILITIES, size, caps);
     free(caps);
Index: new/gtk/channel-main.h
===================================================================
--- new.orig/gtk/channel-main.h	2013-10-07 11:01:52.000000000 +0200
+++ new/gtk/channel-main.h	2013-10-07 11:02:51.000000000 +0200
@@ -74,6 +74,8 @@
 void spice_main_set_display_enabled(SpiceMainChannel *channel, int id, gboolean enabled);
 gboolean spice_main_send_monitor_config(SpiceMainChannel *channel);
 
+gboolean spice_main_send_keyval(SpiceMainChannel *channel, uint32_t keyval,  uint32_t flags);
+
 void spice_main_clipboard_selection_grab(SpiceMainChannel *channel, guint selection, guint32 *types, int ntypes);
 void spice_main_clipboard_selection_release(SpiceMainChannel *channel, guint selection);
 void spice_main_clipboard_selection_notify(SpiceMainChannel *channel, guint selection, guint32 type, const guchar *data, size_t size);
Index: new/gtk/spice-widget.c
===================================================================
--- new.orig/gtk/spice-widget.c	2013-10-07 11:01:52.000000000 +0200
+++ new/gtk/spice-widget.c	2013-10-07 11:04:12.000000000 +0200
@@ -41,6 +41,7 @@
 #include "spice-widget-priv.h"
 #include "spice-gtk-session-priv.h"
 #include "vncdisplaykeymap.h"
+#include <spice/vd_agent.h>
 
 #include "glib-compat.h"
 
@@ -1335,11 +1336,32 @@
         (scancode & 0xff00);
 #endif
 
+    uint32_t flags = 0;
+    if (key->state & GDK_SHIFT_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_SHIFT;
+    if (key->state & GDK_LOCK_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_LOCK;
+    if (key->state & GDK_CONTROL_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_CONTROL;
+    if (key->state & GDK_MOD1_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_MOD1;
+    if (key->state & GDK_MOD2_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_MOD2;
+    if (key->state & GDK_MOD3_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_MOD3;
+    if (key->state & GDK_MOD4_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_MOD4;
+    if (key->state & GDK_MOD5_MASK)
+        flags |= VD_AGENT_KEYVAL_FLAG_MOD5;
+
     switch (key->type) {
     case GDK_KEY_PRESS:
+        flags |= VD_AGENT_KEYVAL_FLAG_DOWN;
+        spice_main_send_keyval(d->main, key->keyval, flags);
         send_key(display, scancode, SEND_KEY_PRESS, !key->is_modifier);
         break;
     case GDK_KEY_RELEASE:
+        spice_main_send_keyval(d->main, key->keyval, flags);
         send_key(display, scancode, SEND_KEY_RELEASE, !key->is_modifier);
         break;
     default:
Index: new/gtk/map-file
===================================================================
--- new.orig/gtk/map-file	2013-10-07 11:01:52.000000000 +0200
+++ new/gtk/map-file	2013-10-07 11:02:51.000000000 +0200
@@ -67,6 +67,7 @@
 spice_main_clipboard_selection_notify;
 spice_main_clipboard_selection_release;
 spice_main_clipboard_selection_request;
+spice_main_send_keyval;
 spice_main_send_monitor_config;
 spice_main_set_display;
 spice_main_set_display_enabled;
Index: new/gtk/spice-glib-sym-file
===================================================================
--- new.orig/gtk/spice-glib-sym-file	2013-10-07 11:01:52.000000000 +0200
+++ new/gtk/spice-glib-sym-file	2013-10-07 11:02:51.000000000 +0200
@@ -43,6 +43,7 @@
 spice_main_clipboard_selection_notify
 spice_main_clipboard_selection_release
 spice_main_clipboard_selection_request
+spice_main_send_keyval
 spice_main_send_monitor_config
 spice_main_set_display
 spice_main_set_display_enabled

