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

Index: new/gtk/channel-inputs.c
===================================================================
--- new.orig/gtk/channel-inputs.c	2013-10-03 11:11:56.000000000 +0200
+++ new/gtk/channel-inputs.c	2013-10-11 11:59:07.000000000 +0200
@@ -451,6 +451,48 @@
     spice_msg_out_send(msg);
 }
 
+static uint8_t assemble_scancodes(uint8_t *code, guint code_down, guint code_up)
+{
+    uint8_t code_len = 0;
+
+    if (code_down) {
+        if (code_down < 0x100) {
+            code[code_len++] =  spice_make_scancode(code_down, FALSE);
+        } else {
+            guint16 scancode = spice_make_scancode(code_down, FALSE);
+            code[code_len++] = scancode & 0xff;
+            code[code_len++] = scancode >> 8;
+        }
+    }
+    if (code_up) {
+        if (code_up < 0x100) {
+            code[code_len++] =  spice_make_scancode(code_up, FALSE);
+        } else {
+            guint16 scancode = spice_make_scancode(code_up, FALSE);
+            code[code_len++] = scancode & 0xff;
+            code[code_len++] = scancode >> 8;
+        }
+    }
+
+    return code_len;
+}
+
+static void spice_inputs_key_x11_keysym(SpiceInputsChannel *channel, guint keysym, guint flags,
+                                        guint code_down, guint code_up)
+{
+    SpiceMsgOut *msg;
+    uint8_t code[32];
+    uint8_t code_len = assemble_scancodes(code, code_down, code_up);
+
+    msg = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_INPUTS_KEY_X11_KEYSYM);
+    spice_marshaller_add_uint32(msg->marshaller, keysym);
+    spice_marshaller_add_uint32(msg->marshaller, flags);
+    spice_marshaller_add_uint8(msg->marshaller, code_len);
+    uint8_t *buf = (guint8*)spice_marshaller_reserve_space(msg->marshaller, code_len);
+    memcpy(buf, code, code_len);
+    spice_msg_out_send(msg);
+}
+
 /**
  * spice_inputs_key_press:
  * @channel:
@@ -458,7 +500,7 @@
  *
  * Press a key.
  **/
-void spice_inputs_key_press(SpiceInputsChannel *channel, guint scancode)
+void spice_inputs_key_press(SpiceInputsChannel *channel, guint scancode, guint keysym)
 {
     SpiceMsgcKeyDown down;
     SpiceMsgOut *msg;
@@ -470,10 +512,14 @@
     if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
         return;
 
-    down.code = spice_make_scancode(scancode, FALSE);
-    msg = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_INPUTS_KEY_DOWN);
-    msg->marshallers->msgc_inputs_key_down(msg->marshaller, &down);
-    spice_msg_out_send(msg);
+    if (spice_channel_test_capability(SPICE_CHANNEL(channel), SPICE_INPUTS_CAP_KEY_X11_KEYSYM)) {
+        spice_inputs_key_x11_keysym(channel, keysym, SPICE_KEYBOARD_FLAG_DOWN, scancode, 0);
+    } else {
+        down.code = spice_make_scancode(scancode, FALSE);
+        msg = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_INPUTS_KEY_DOWN);
+        msg->marshallers->msgc_inputs_key_down(msg->marshaller, &down);
+        spice_msg_out_send(msg);
+    }
 }
 
 /**
@@ -483,7 +529,7 @@
  *
  * Release a key.
  **/
-void spice_inputs_key_release(SpiceInputsChannel *channel, guint scancode)
+void spice_inputs_key_release(SpiceInputsChannel *channel, guint scancode, guint keysym)
 {
     SpiceMsgcKeyUp up;
     SpiceMsgOut *msg;
@@ -495,10 +541,14 @@
     if (spice_channel_get_read_only(SPICE_CHANNEL(channel)))
         return;
 
-    up.code = spice_make_scancode(scancode, TRUE);
-    msg = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_INPUTS_KEY_UP);
-    msg->marshallers->msgc_inputs_key_up(msg->marshaller, &up);
-    spice_msg_out_send(msg);
+    if (spice_channel_test_capability(SPICE_CHANNEL(channel), SPICE_INPUTS_CAP_KEY_X11_KEYSYM)) {
+        spice_inputs_key_x11_keysym(channel, keysym, SPICE_KEYBOARD_FLAG_UP, 0, scancode);
+    } else {
+        up.code = spice_make_scancode(scancode, TRUE);
+        msg = spice_msg_out_new(SPICE_CHANNEL(channel), SPICE_MSGC_INPUTS_KEY_UP);
+        msg->marshallers->msgc_inputs_key_up(msg->marshaller, &up);
+        spice_msg_out_send(msg);
+    }
 }
 
 /**
@@ -510,7 +560,7 @@
  *
  * Since: 0.13
  **/
-void spice_inputs_key_press_and_release(SpiceInputsChannel *input_channel, guint scancode)
+void spice_inputs_key_press_and_release(SpiceInputsChannel *input_channel, guint scancode, guint keysym)
 {
     SpiceChannel *channel = SPICE_CHANNEL(input_channel);
 
@@ -522,30 +572,25 @@
     if (spice_channel_get_read_only(channel))
         return;
 
-    if (spice_channel_test_capability(channel, SPICE_INPUTS_CAP_KEY_SCANCODE)) {
+    if (spice_channel_test_capability(channel, SPICE_INPUTS_CAP_KEY_X11_KEYSYM)) {
+        spice_inputs_key_x11_keysym(input_channel, keysym,
+                                    SPICE_KEYBOARD_FLAG_DOWN|SPICE_KEYBOARD_FLAG_UP,
+                                    scancode, scancode);
+    } else if (spice_channel_test_capability(channel, SPICE_INPUTS_CAP_KEY_SCANCODE)) {
         SpiceMsgOut *msg;
-        guint16 code;
-        guint8 *buf;
+
+        uint8_t code[32];
+        uint8_t code_len = assemble_scancodes(code, scancode, scancode);
 
         msg = spice_msg_out_new(channel, SPICE_MSGC_INPUTS_KEY_SCANCODE);
-        if (scancode < 0x100) {
-            buf = (guint8*)spice_marshaller_reserve_space(msg->marshaller, 2);
-            buf[0] = spice_make_scancode(scancode, FALSE);
-            buf[1] = spice_make_scancode(scancode, TRUE);
-        } else {
-            buf = (guint8*)spice_marshaller_reserve_space(msg->marshaller, 4);
-            code = spice_make_scancode(scancode, FALSE);
-            buf[0] = code & 0xff;
-            buf[1] = code >> 8;
-            code = spice_make_scancode(scancode, TRUE);
-            buf[2] = code & 0xff;
-            buf[3] = code >> 8;
-        }
+        uint8_t *buf = (guint8*)spice_marshaller_reserve_space(msg->marshaller, code_len);
+        memcpy(buf, code, code_len);
+
         spice_msg_out_send(msg);
     } else {
         CHANNEL_DEBUG(channel, "The server doesn't support atomic press and release");
-        spice_inputs_key_press(input_channel, scancode);
-        spice_inputs_key_release(input_channel, scancode);
+        spice_inputs_key_press(input_channel, scancode, keysym);
+        spice_inputs_key_release(input_channel, scancode, keysym);
     }
 }
 
Index: new/gtk/channel-inputs.h
===================================================================
--- new.orig/gtk/channel-inputs.h	2013-10-03 11:11:56.000000000 +0200
+++ new/gtk/channel-inputs.h	2013-10-11 11:16:45.000000000 +0200
@@ -79,10 +79,10 @@
                                gint button_state);
 void spice_inputs_button_release(SpiceInputsChannel *channel, gint button,
                                  gint button_state);
-void spice_inputs_key_press(SpiceInputsChannel *channel, guint scancode);
-void spice_inputs_key_release(SpiceInputsChannel *channel, guint scancode);
+void spice_inputs_key_press(SpiceInputsChannel *channel, guint scancode, guint keysym);
+void spice_inputs_key_release(SpiceInputsChannel *channel, guint scancode, guint keysym);
 void spice_inputs_set_key_locks(SpiceInputsChannel *channel, guint locks);
-void spice_inputs_key_press_and_release(SpiceInputsChannel *channel, guint scancode);
+void spice_inputs_key_press_and_release(SpiceInputsChannel *channel, guint scancode, guint keysym);
 
 G_END_DECLS
 
Index: new/gtk/spice-widget-priv.h
===================================================================
--- new.orig/gtk/spice-widget-priv.h	2013-10-03 11:11:56.000000000 +0200
+++ new/gtk/spice-widget-priv.h	2013-10-11 11:16:45.000000000 +0200
@@ -108,6 +108,7 @@
     size_t                  keycode_maplen;
     uint32_t                key_state[512 / 32];
     int                     key_delayed_scancode;
+    guint                   key_delayed_keysym;
     guint                   key_delayed_id;
     SpiceGrabSequence         *grabseq; /* the configured key sequence */
     gboolean                *activeseq; /* the currently pressed keys */
Index: new/gtk/spice-widget.c
===================================================================
--- new.orig/gtk/spice-widget.c	2013-10-11 11:16:30.000000000 +0200
+++ new/gtk/spice-widget.c	2013-10-11 11:55:29.000000000 +0200
@@ -1153,8 +1153,9 @@
     if (d->key_delayed_scancode == 0)
         return;
 
-    spice_inputs_key_press_and_release(d->inputs, d->key_delayed_scancode);
+    spice_inputs_key_press_and_release(d->inputs, d->key_delayed_scancode, d->key_delayed_keysym);
     d->key_delayed_scancode = 0;
+    d->key_delayed_keysym = 0;
 
     if (d->key_delayed_id) {
         g_source_remove(d->key_delayed_id);
@@ -1169,8 +1170,9 @@
     if (d->key_delayed_scancode == 0)
         return FALSE;
 
-    spice_inputs_key_press(d->inputs, d->key_delayed_scancode);
+    spice_inputs_key_press(d->inputs, d->key_delayed_scancode, d->key_delayed_keysym);
     d->key_delayed_scancode = 0;
+    d->key_delayed_keysym = 0;
 
     if (d->key_delayed_id) {
         g_source_remove(d->key_delayed_id);
@@ -1180,7 +1182,7 @@
     return FALSE;
 }
 
-static void send_key(SpiceDisplay *display, int scancode, SendKeyType type, gboolean press_delayed)
+static void send_key(SpiceDisplay *display, int scancode, guint keysym, SendKeyType type, gboolean press_delayed)
 {
     SpiceDisplayPrivate *d = SPICE_DISPLAY_GET_PRIVATE(display);
     uint32_t i, b, m;
@@ -1209,8 +1211,9 @@
             g_warn_if_fail(d->key_delayed_id == 0);
             d->key_delayed_id = g_timeout_add(d->keypress_delay, key_press_delayed, display);
             d->key_delayed_scancode = scancode;
+            d->key_delayed_keysym = keysym;
         } else
-            spice_inputs_key_press(d->inputs, scancode);
+            spice_inputs_key_press(d->inputs, scancode, keysym);
 
         d->key_state[i] |= m;
         break;
@@ -1224,7 +1227,7 @@
         else {
             /* ensure delayed key is pressed before other key are released */
             key_press_delayed(display);
-            spice_inputs_key_release(d->inputs, scancode);
+            spice_inputs_key_release(d->inputs, scancode, keysym);
         }
 
         d->key_state[i] &= ~m;
@@ -1246,7 +1249,8 @@
             continue;
         }
         for (b = 0; b < 32; b++) {
-            send_key(display, i * 32 + b, SEND_KEY_RELEASE, FALSE);
+            // note: using keysym 0 here, because we do not have this information
+            send_key(display, i * 32 + b, 0, SEND_KEY_RELEASE, FALSE);
         }
     }
 }
@@ -1337,10 +1341,10 @@
 
     switch (key->type) {
     case GDK_KEY_PRESS:
-        send_key(display, scancode, SEND_KEY_PRESS, !key->is_modifier);
+        send_key(display, scancode, key->keyval, SEND_KEY_PRESS, !key->is_modifier);
         break;
     case GDK_KEY_RELEASE:
-        send_key(display, scancode, SEND_KEY_RELEASE, !key->is_modifier);
+        send_key(display, scancode, key->keyval, SEND_KEY_RELEASE, !key->is_modifier);
         break;
     default:
         g_warn_if_reached();
@@ -1393,12 +1397,12 @@
 
     if (kind & SPICE_DISPLAY_KEY_EVENT_PRESS) {
         for (i = 0 ; i < nkeyvals ; i++)
-            send_key(display, get_scancode_from_keyval(display, keyvals[i]), SEND_KEY_PRESS, FALSE);
+            send_key(display, get_scancode_from_keyval(display, keyvals[i]), keyvals[i], SEND_KEY_PRESS, FALSE);
     }
 
     if (kind & SPICE_DISPLAY_KEY_EVENT_RELEASE) {
         for (i = (nkeyvals-1) ; i >= 0 ; i--)
-            send_key(display, get_scancode_from_keyval(display, keyvals[i]), SEND_KEY_RELEASE, FALSE);
+            send_key(display, get_scancode_from_keyval(display, keyvals[i]), keyvals[i], SEND_KEY_RELEASE, FALSE);
     }
 }
 

