From 9ca313aa0824f2d350a7a6c9b1ef6c47e0408f1d Mon Sep 17 00:00:00 2001
From: aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
Date: Sat, 23 Aug 2008 23:27:37 +0000
Subject: [PATCH] VNC: Support for ExtendedKeyEvent client message

This patch adds support for the ExtendedKeyEvent client message.  This message
allows a client to send raw scan codes directly to the server.  If the client
and server are using the same keymap, then it's unnecessary to use the '-k'
option with QEMU when this extension is supported.

This is extension is currently only implemented by gtk-vnc based clients
(gvncviewer, virt-manager, vinagre, etc.).

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5076 c046a42c-6fe2-441c-8c8c-71466251a162
---
 vnc.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 50 insertions(+), 9 deletions(-)

Index: xen-4.4.4-testing/tools/qemu-xen-traditional-dir-remote/vnc.c
===================================================================
--- xen-4.4.4-testing.orig/tools/qemu-xen-traditional-dir-remote/vnc.c
+++ xen-4.4.4-testing/tools/qemu-xen-traditional-dir-remote/vnc.c
@@ -1285,35 +1285,22 @@ static void press_key_altgr_down(VncStat
     }
 }
 
-static void do_key_event(VncState *vs, int down, uint32_t sym)
+static void do_key_event(VncState *vs, int down, int keycode, int sym, int shift)
 {
-    int keycode;
     int shift_keys = 0;
-    int shift = 0;
     int keypad = 0;
     int altgr = 0;
     int altgr_keys = 0;
 
     if (is_graphic_console()) {
-        if (sym >= 'A' && sym <= 'Z') {
-            sym = sym - 'A' + 'a';
-            shift = 1;
-        }
-        else {
+        if (!shift)
             shift = keysym_is_shift(vs->kbd_layout, sym & 0xFFFF);
-        }
 
         altgr = keysym_is_altgr(vs->kbd_layout, sym & 0xFFFF);
     }
     shift_keys = vs->modifiers_state[0x2a] | vs->modifiers_state[0x36];
     altgr_keys = vs->modifiers_state[0xb8];
 
-    keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
-    if (keycode == 0) {
-        fprintf(stderr, "Key lost : keysym=0x%x(%d)\n", sym, sym);
-        return;
-    }
-
     /* QEMU console switch */
     switch(keycode) {
     case 0x2a:                          /* Left Shift */
@@ -1445,7 +1432,25 @@ static void do_key_event(VncState *vs, i
 
 static void key_event(VncState *vs, int down, uint32_t sym)
 {
-    do_key_event(vs, down, sym);
+    int keycode;
+    int shift = 0;
+
+    if (sym >= 'A' && sym <= 'Z' && is_graphic_console()) {
+       sym = sym - 'A' + 'a';
+       shift = 1;
+    }
+    keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
+    do_key_event(vs, down, keycode, sym, shift);
+}
+
+static void ext_key_event(VncState *vs, int down,
+                          uint32_t sym, uint16_t keycode)
+{
+    /* if the user specifies a keyboard layout, always use it */
+    if (keyboard_layout)
+        key_event(vs, down, sym);
+    else
+        do_key_event(vs, down, keycode, sym, 0);
 }
 
 static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h)
@@ -1534,6 +1539,15 @@ static void framebuffer_update_request(V
     qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock));
 }
 
+static void send_ext_key_event_ack(VncState *vs)
+{
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 0);
+    vnc_write_u16(vs, 1);
+    vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), -258);
+    vnc_flush(vs);
+}
+
 static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
 {
     int i;
@@ -1562,6 +1576,9 @@ static void set_encodings(VncState *vs,
 	case -257:
 	    vs->has_pointer_type_change = 1;
 	    break;
+        case -258:
+            send_ext_key_event_ack(vs);
+            break;
         case 0x574D5669:
             vs->has_WMVi = 1;
 	default:
@@ -1780,6 +1797,24 @@ static int protocol_client_msg(VncState
 
 	client_cut_text(vs, read_u32(data, 4), (char *)(data + 8));
 	break;
+    case 255:
+        if (len == 1)
+            return 2;
+
+        switch (read_u8(data, 1)) {
+        case 0:
+            if (len == 2)
+                return 12;
+
+            ext_key_event(vs, read_u16(data, 2),
+                          read_u32(data, 4), read_u32(data, 8));
+            break;
+        default:
+            printf("Msg: %d\n", read_u16(data, 0));
+            vnc_client_error(vs);
+            break;
+        }
+        break;
     default:
 	printf("Msg: %d\n", data[0]);
 	vnc_client_error(vs);
@@ -2451,10 +2486,11 @@ void vnc_display_init(DisplayState *ds)
 
     vs->ds = ds;
 
-    if (!keyboard_layout)
-	keyboard_layout = "en-us";
+    if (keyboard_layout)
+        vs->kbd_layout = init_keyboard_layout(keyboard_layout);
+    else
+        vs->kbd_layout = init_keyboard_layout("en-us");
 
-    vs->kbd_layout = init_keyboard_layout(keyboard_layout);
     if (!vs->kbd_layout)
 	exit(1);
     vs->modifiers_state[0x45] = 1; /* NumLock on - on boot */
