[gtk-vnc-devel] PATCH: Fix scancode mapping for evdev



The VNC extension for sending raw scancodes assumes that the scancodes 
map to the keycodes with xfree86 layout. This doesn't hold true when
you introduce evdev to the world. Easiest demonstration of the problem
is to press the 'Up' key, and see 'PrintScreen' arrive in the guest.

This patch adds a new mapping table with the evdev data. Although
Ubuntu have a patch like this in their gtkvnc packages for months
(never been submitted back here), it copies from the GPL licensed
VirtualBox - you can argue whether data tables are exempt from this
or not, but I feel its better to not copy it in the first place
since we can generate it easily enough. It also re-probes for whether
its using evdev on every single key press event which is creating 
far too much X traffic.

So I've written this all again. First of all I hacked a quick
perl script to generate  the initial evdev mapping table from the 
master evdev definitions - this is where evdev_keycode_to_pc_keycode
data comes from. When starting up we do a one-time probe for using
evdev and key a reference to the appropriate lookup table, so we're
not doing any serious computation on each key press.

Tested on a host using evdev, and a guest using xfree86, with the 
KVM keyboard extension active, and it does the right thing for
arrow keys.

Daniel

diff --git a/src/gvnc.c b/src/gvnc.c
--- a/src/gvnc.c
+++ b/src/gvnc.c
@@ -38,8 +38,6 @@
 #include <zlib.h>
 
 #include <gdk/gdkkeysyms.h>
-
-#include "vnc_keycodes.h"
 
 struct wait_queue
 {
@@ -164,6 +162,7 @@ struct gvnc
 	int zrle_pi_bits;
 
 	gboolean has_ext_key_event;
+	const uint8_t const *keycode_map;
 };
 
 #define nibhi(a) (((a) >> 4) & 0x0F)
@@ -922,11 +921,9 @@ gboolean gvnc_key_event(struct gvnc *gvn
 {
 	uint8_t pad[2] = {0};
 
+	GVNC_DEBUG("Key event %d %d %d %d", key, scancode, down_flag, gvnc->has_ext_key_event);
 	if (gvnc->has_ext_key_event) {
-		if (key == GDK_Pause)
-			scancode = VKC_PAUSE;
-		else
-			scancode = x_keycode_to_pc_keycode(scancode);
+		scancode = x_keycode_to_pc_keycode(gvnc->keycode_map, scancode);
 
 		gvnc_buffered_write_u8(gvnc, 255);
 		gvnc_buffered_write_u8(gvnc, 0);
@@ -1935,6 +1932,11 @@ static void gvnc_xcursor(struct gvnc *gv
 	g_free(pixbuf);
 }
 
+static void gvnc_ext_key_event(struct gvnc *gvnc)
+{
+	gvnc->has_ext_key_event = TRUE;
+	gvnc->keycode_map = x_keycode_to_pc_keycode_map();
+}
 
 static void gvnc_framebuffer_update(struct gvnc *gvnc, int32_t etype,
 				    uint16_t x, uint16_t y,
diff --git a/src/x_keymap.c b/src/x_keymap.c
--- a/src/x_keymap.c
+++ b/src/x_keymap.c
@@ -1,5 +1,19 @@
 /*
- * QEMU SDL display driver
+ * Copyright (C) 2008  Anthony Liguori <anthony codemonkey ws>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <gdk/gdkkeysyms.h>
+#include "x_keymap.h"
+#include "utils.h"
+#include "vnc_keycodes.h"
+
+/*
+ * This table is taken from QEMU x_keymap.c, under the terms:
  *
  * Copyright (c) 2003 Fabrice Bellard
  *
@@ -22,99 +36,138 @@
  * THE SOFTWARE.
  */
 
-/*
- * Adapted for gtk-vnc from QEMU x_keymap.c revision 1.3 (on 20080113)
- *
- * Copyright (C) 2008  Anthony Liguori <anthony codemonkey ws>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 2 as
- * published by the Free Software Foundation.
+/* Mapping is offset by 97 to save space */
+static const uint8_t x_keycode_to_pc_keycode_table[61] = {
+	0xc7,      /*  97  Home   */
+	0xc8,      /*  98  Up     */
+	0xc9,      /*  99  PgUp   */
+	0xcb,      /* 100  Left   */
+	0x4c,        /* 101  KP-5   */
+	0xcd,      /* 102  Right  */
+	0xcf,      /* 103  End    */
+	0xd0,      /* 104  Down   */
+	0xd1,      /* 105  PgDn   */
+	0xd2,      /* 106  Ins    */
+	0xd3,      /* 107  Del    */
+	0x9c,      /* 108  Enter  */
+	0x9d,      /* 109  Ctrl-R */
+	0x0,       /* 110  Pause  */
+	0xb7,      /* 111  Print  */
+	0xb5,      /* 112  Divide */
+	0xb8,      /* 113  Alt-R  */
+	0xc6,      /* 114  Break  */
+	0x0,         /* 115 */
+	0x0,         /* 116 */
+	0x0,         /* 117 */
+	0x0,         /* 118 */
+	0x0,         /* 119 */
+	0x0,         /* 120 */
+	0x0,         /* 121 */
+	0x0,         /* 122 */
+	0x0,         /* 123 */
+	0x0,         /* 124 */
+	0x0,         /* 125 */
+	0x0,         /* 126 */
+	0x0,         /* 127 */
+	0x0,         /* 128 */
+	0x79,         /* 129 Henkan */
+	0x0,         /* 130 */
+	0x7b,         /* 131 Muhenkan */
+	0x0,         /* 132 */
+	0x7d,         /* 133 Yen */
+	0x0,         /* 134 */
+	0x0,         /* 135 */
+	0x47,         /* 136 KP_7 */
+	0x48,         /* 137 KP_8 */
+	0x49,         /* 138 KP_9 */
+	0x4b,         /* 139 KP_4 */
+	0x4c,         /* 140 KP_5 */
+	0x4d,         /* 141 KP_6 */
+	0x4f,         /* 142 KP_1 */
+	0x50,         /* 143 KP_2 */
+	0x51,         /* 144 KP_3 */
+	0x52,         /* 145 KP_0 */
+	0x53,         /* 146 KP_. */
+	0x47,         /* 147 KP_HOME */
+	0x48,         /* 148 KP_UP */
+	0x49,         /* 149 KP_PgUp */
+	0x4b,         /* 150 KP_Left */
+	0x4c,         /* 151 KP_ */
+	0x4d,         /* 152 KP_Right */
+	0x4f,         /* 153 KP_End */
+	0x50,         /* 154 KP_Down */
+	0x51,         /* 155 KP_PgDn */
+	0x52,         /* 156 KP_Ins */
+	0x53,         /* 157 KP_Del */
+};
+
+/* This table is generated based off the xfree86 -> scancode mapping above
+ * and the keycode mappings in /usr/share/X11/xkb/keycodes/evdev
+ * and  /usr/share/X11/xkb/keycodes/xfree86
  */
 
-#include "x_keymap.h"
-#include <gdk/gdkkeysyms.h>
-
-static const uint8_t x_keycode_to_pc_keycode_table[115] = {
-   0xc7,      /*  97  Home   */
-   0xc8,      /*  98  Up     */
-   0xc9,      /*  99  PgUp   */
-   0xcb,      /* 100  Left   */
-   0x4c,        /* 101  KP-5   */
-   0xcd,      /* 102  Right  */
-   0xcf,      /* 103  End    */
-   0xd0,      /* 104  Down   */
-   0xd1,      /* 105  PgDn   */
-   0xd2,      /* 106  Ins    */
-   0xd3,      /* 107  Del    */
-   0x9c,      /* 108  Enter  */
-   0x9d,      /* 109  Ctrl-R */
-   0x0,       /* 110  Pause  */
-   0xb7,      /* 111  Print  */
-   0xb5,      /* 112  Divide */
-   0xb8,      /* 113  Alt-R  */
-   0xc6,      /* 114  Break  */
-   0x0,         /* 115 */
-   0x0,         /* 116 */
-   0x0,         /* 117 */
-   0x0,         /* 118 */
-   0x0,         /* 119 */
-   0x0,         /* 120 */
-   0x0,         /* 121 */
-   0x0,         /* 122 */
-   0x0,         /* 123 */
-   0x0,         /* 124 */
-   0x0,         /* 125 */
-   0x0,         /* 126 */
-   0x0,         /* 127 */
-   0x0,         /* 128 */
-   0x79,         /* 129 Henkan */
-   0x0,         /* 130 */
-   0x7b,         /* 131 Muhenkan */
-   0x0,         /* 132 */
-   0x7d,         /* 133 Yen */
-   0x0,         /* 134 */
-   0x0,         /* 135 */
-   0x47,         /* 136 KP_7 */
-   0x48,         /* 137 KP_8 */
-   0x49,         /* 138 KP_9 */
-   0x4b,         /* 139 KP_4 */
-   0x4c,         /* 140 KP_5 */
-   0x4d,         /* 141 KP_6 */
-   0x4f,         /* 142 KP_1 */
-   0x50,         /* 143 KP_2 */
-   0x51,         /* 144 KP_3 */
-   0x52,         /* 145 KP_0 */
-   0x53,         /* 146 KP_. */
-   0x47,         /* 147 KP_HOME */
-   0x48,         /* 148 KP_UP */
-   0x49,         /* 149 KP_PgUp */
-   0x4b,         /* 150 KP_Left */
-   0x4c,         /* 151 KP_ */
-   0x4d,         /* 152 KP_Right */
-   0x4f,         /* 153 KP_End */
-   0x50,         /* 154 KP_Down */
-   0x51,         /* 155 KP_PgDn */
-   0x52,         /* 156 KP_Ins */
-   0x53,         /* 157 KP_Del */
-   0x0,         /* 158 */
-   0x0,         /* 159 */
-   0x0,         /* 160 */
-   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 170 */
-   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 180 */
-   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 190 */
-   0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,         /* 200 */
-   0x0,         /* 201 */
-   0x0,         /* 202 */
-   0x0,         /* 203 */
-   0x0,         /* 204 */
-   0x0,         /* 205 */
-   0x0,         /* 206 */
-   0x0,         /* 207 */
-   0x70,         /* 208 Hiragana_Katakana */
-   0x0,         /* 209 */
-   0x0,         /* 210 */
-   0x73,         /* 211 backslash */
+static const uint8_t evdev_keycode_to_pc_keycode[61] = {
+	0,    /* 97 unknown */
+	0,    /* 98 unknown */
+	0,    /* 99 unknown */
+	0,    /* 100 unknown */
+	0,    /* 101 unknown */
+	0,    /* 102 unknown */
+	0,    /* 103 unknown */
+	0x9c, /* 104 KPEN */
+	0x9d, /* 105 RCTL */
+	0xb5, /* 106 KPDV */
+	0xb7, /* 107 PRSC */
+	0xb8, /* 108 RALT */
+	0,    /* 109 unknown */
+	0xc7, /* 110 HOME */
+	0xc8, /* 111 UP */
+	0xc9, /* 112 PGUP */
+	0xcb, /* 113 LEFT */
+	0xcd, /* 114 RGHT */
+	0xcf, /* 115 END */
+	0xd0, /* 116 DOWN */
+	0xd1, /* 117 PGDN */
+	0xd2, /* 118 INS */
+	0xd3, /* 119 DELE */
+	0,    /* 120 unknown */
+	0,    /* 121 unknown */
+	0,    /* 122 unknown */
+	0,    /* 123 unknown */
+	0,    /* 124 unknown */
+	0,    /* 125 unknown */
+	0,    /* 126 unknown */
+	0,    /* 127 unknown */
+	0,    /* 128 unknown */
+	0,    /* 129 unknown */
+	0,    /* 130 unknown */
+	0,    /* 131 unknown */
+	0x7d, /* 132 AE13 */
+	0,    /* 133 unknown */
+	0,    /* 134 unknown */
+	0,    /* 135 unknown */
+	0,    /* 136 unknown */
+	0,    /* 137 unknown */
+	0,    /* 138 unknown */
+	0,    /* 139 unknown */
+	0,    /* 140 unknown */
+	0,    /* 141 unknown */
+	0,    /* 142 unknown */
+	0,    /* 143 unknown */
+	0,    /* 144 unknown */
+	0,    /* 145 unknown */
+	0,    /* 146 unknown */
+	0,    /* 147 unknown */
+	0,    /* 148 unknown */
+	0,    /* 149 unknown */
+	0,    /* 150 unknown */
+	0,    /* 151 unknown */
+	0,    /* 152 unknown */
+	0,    /* 153 unknown */
+	0,    /* 154 unknown */
+	0,    /* 155 unknown */
+	0,    /* 156 unknown */
+	0,    /* 157 unknown */
 };
 
 /* keycode translation for sending ISO_Left_Send
@@ -128,20 +181,81 @@ static struct {
 
 static unsigned int ref_count_for_untranslated_keys = 0;
 
-/* FIXME N.B. on Windows, gtk probably returns PC scan codes */
+/* As best as I can tell, windows passes PC scan codes.  This code definitely
+ * won't compile on windows so let's put in a guard anyway */
 
-uint8_t x_keycode_to_pc_keycode(int keycode)
+#ifndef WIN32
+#include <gdk/gdkx.h>
+#include <X11/XKBlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
+
+static gboolean check_for_evdev(void)
 {
+	XkbDescPtr desc;
+	gboolean has_evdev = FALSE;
+	const gchar *keycodes;
+
+	desc = XkbGetKeyboard(GDK_DISPLAY(), XkbGBN_AllComponentsMask,
+			      XkbUseCoreKbd);
+	if (desc == NULL || desc->names == NULL)
+		return FALSE;
+
+	keycodes = gdk_x11_get_xatom_name(desc->names->keycodes);
+	if (keycodes == NULL)
+		g_warning("could not lookup keycode name\n");
+	else if (STRPREFIX(keycodes, "evdev_"))
+		has_evdev = TRUE;
+	else if (!STRPREFIX(keycodes, "xfree86_"))
+		g_warning("unknown keycodes `%s', please report to gtk-vnc-devel\n",
+			  keycodes);
+
+	XkbFreeClientMap(desc, XkbGBN_AllComponentsMask, True);
+
+	return has_evdev;
+}
+#else
+static gboolean check_for_evdev(void)
+{
+	return FALSE;
+}
+#endif
+
+const uint8_t const *x_keycode_to_pc_keycode_map(void)
+{
+	if (check_for_evdev()) {
+		GVNC_DEBUG("Using evdev keycode mapping");
+		return evdev_keycode_to_pc_keycode;
+	} else {
+		GVNC_DEBUG("Using xfree86 keycode mapping");
+		return x_keycode_to_pc_keycode_table;
+	}
+}
+
+uint16_t x_keycode_to_pc_keycode(const uint8_t const *keycode_map,
+				 uint16_t keycode)
+{
+	if (keycode == GDK_Pause)
+		return VKC_PAUSE;
+
 	if (keycode < 9)
-		keycode = 0;
-	else if (keycode < 97)
-		keycode -= 8; /* just an offset */
-	else if (keycode < 212)
-		keycode = x_keycode_to_pc_keycode_table[keycode - 97];
-	else
-		keycode = 0;
+		return 0;
 
-	return keycode;
+	if (keycode < 97)
+		return keycode - 8; /* just an offset */
+
+	if (keycode < 158)
+		return keycode_map[keycode - 97];
+
+	if (keycode == 208) /* Hiragana_Katakana */
+		return 0x70;
+
+	if (keycode == 211) /* backslash */
+		return 0x73;
+
+	return 0;
 }
 
 /* Set the keymap entries */
@@ -184,3 +298,10 @@ guint x_keymap_get_keyval_from_keycode(g
 
 	return keyval;
 }
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/x_keymap.h b/src/x_keymap.h
--- a/src/x_keymap.h
+++ b/src/x_keymap.h
@@ -4,7 +4,9 @@
 #include <stdint.h>
 #include <gdk/gdk.h>
 
-uint8_t x_keycode_to_pc_keycode(int keycode);
+const uint8_t const *x_keycode_to_pc_keycode_map(void);
+uint16_t x_keycode_to_pc_keycode(const uint8_t *keycode_map,
+				 uint16_t keycode);
 void x_keymap_set_keymap_entries(void);
 void x_keymap_free_keymap_entries(void);
 guint x_keymap_get_keyval_from_keycode(guint keycode, guint keyval);

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]