[gtk-vnc-devel] PATCH: Fix gtk-vnc keymap translation for evdev



This is an update of my previous patch to support evdev in gtk-vnc. The
patch takes the evdev keycode translation tables from the Ubuntu gtk-vnc
patch, but changes the logic so it caches the current keymap, rather than
requerying for evdev on each key event

Daniel

diff --git a/src/gvnc.c b/src/gvnc.c
--- a/src/gvnc.c
+++ b/src/gvnc.c
@@ -50,7 +50,6 @@
 
 #include <gdk/gdkkeysyms.h>
 
-#include "vnc_keycodes.h"
 #include "getaddrinfo.h"
 
 /* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it
@@ -183,6 +182,7 @@ struct gvnc
 	int zrle_pi_bits;
 
 	gboolean has_ext_key_event;
+	const uint8_t const *keycode_map;
 };
 
 #define nibhi(a) (((a) >> 4) & 0x0F)
@@ -936,11 +936,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);
@@ -1956,6 +1954,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,
@@ -2006,7 +2009,7 @@ static void gvnc_framebuffer_update(stru
 		gvnc_xcursor(gvnc, x, y, width, height);
 		break;
 	case GVNC_ENCODING_EXT_KEY_EVENT:
-		gvnc->has_ext_key_event = TRUE;
+		gvnc_ext_key_event(gvnc);
 		break;
 	default:
 		GVNC_DEBUG("Received an unknown encoding type: %d\n", etype);
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,110 +36,139 @@
  * 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 library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.0 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+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 */
+	0,         /* 110  Pause  */
+	0xb7,      /* 111  Print  */
+	0xb5,      /* 112  Divide */
+	0xb8,      /* 113  Alt-R  */
+	0xc6,      /* 114  Break  */
+	0,         /* 115 */
+	0,         /* 116 */
+	0,         /* 117 */
+	0,         /* 118 */
+	0,         /* 119 */
+	0,         /* 120 */
+	0,         /* 121 */
+	0,         /* 122 */
+	0,         /* 123 */
+	0,         /* 124 */
+	0,         /* 125 */
+	0,         /* 126 */
+	0,         /* 127 */
+	0,         /* 128 */
+	0x79,      /* 129 Henkan */
+	0,         /* 130 */
+	0x7b,      /* 131 Muhenkan */
+	0,         /* 132 */
+	0x7d,      /* 133 Yen */
+	0,         /* 134 */
+	0,         /* 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 evdev_keycode_to_pc_keycode[61] = {
+	0,         /*  97 EVDEV - RO   ("Internet" Keyboards) */
+	0,         /*  98 EVDEV - KATA (Katakana) */
+	0,         /*  99 EVDEV - HIRA (Hiragana) */
+	0x79,      /* 100 EVDEV - HENK (Henkan) */
+	0x70,      /* 101 EVDEV - HKTG (Hiragana/Katakana toggle) */
+	0x7b,      /* 102 EVDEV - MUHE (Muhenkan) */
+	0,         /* 103 EVDEV - JPCM (KPJPComma) */
+	0x9c,      /* 104 KPEN */
+	0x9d,      /* 105 RCTL */
+	0xb5,      /* 106 KPDV */
+	0xb7,      /* 107 PRSC */
+	0xb8,      /* 108 RALT */
+	0,         /* 109 EVDEV - LNFD ("Internet" Keyboards) */
+	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 EVDEV - I120 ("Internet" Keyboards) */
+	0,         /* 121 EVDEV - MUTE */
+	0,         /* 122 EVDEV - VOL- */
+	0,         /* 123 EVDEV - VOL+ */
+	0,         /* 124 EVDEV - POWR */
+	0,         /* 125 EVDEV - KPEQ */
+	0,         /* 126 EVDEV - I126 ("Internet" Keyboards) */
+	0,         /* 127 EVDEV - PAUS */
+	0,         /* 128 EVDEV - ???? */
+	0,         /* 129 EVDEV - I129 ("Internet" Keyboards) */
+	0xf1,      /* 130 EVDEV - HNGL (Korean Hangul Latin toggle) */
+	0xf2,      /* 131 EVDEV - HJCV (Korean Hangul Hanja toggle) */
+	0x7d,      /* 132 AE13 (Yen)*/
+	0xdb,      /* 133 EVDEV - LWIN */
+	0xdc,      /* 134 EVDEV - RWIN */
+	0xdd,      /* 135 EVDEV - MENU */
+	0,         /* 136 EVDEV - STOP */
+	0,         /* 137 EVDEV - AGAI */
+	0,         /* 138 EVDEV - PROP */
+	0,         /* 139 EVDEV - UNDO */
+	0,         /* 140 EVDEV - FRNT */
+	0,         /* 141 EVDEV - COPY */
+	0,         /* 142 EVDEV - OPEN */
+	0,         /* 143 EVDEV - PAST */
+	0,         /* 144 EVDEV - FIND */
+	0,         /* 145 EVDEV - CUT  */
+	0,         /* 146 EVDEV - HELP */
+	0,         /* 147 EVDEV - I147 */
+	0,         /* 148 EVDEV - I148 */
+	0,         /* 149 EVDEV - I149 */
+	0,         /* 150 EVDEV - I150 */
+	0,         /* 151 EVDEV - I151 */
+	0,         /* 152 EVDEV - I152 */
+	0,         /* 153 EVDEV - I153 */
+	0,         /* 154 EVDEV - I154 */
+	0,         /* 155 EVDEV - I156 */
+	0,         /* 156 EVDEV - I157 */
+	0,         /* 157 EVDEV - I158 */
+};
 
-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 */
-};
 
 /* keycode translation for sending ISO_Left_Send
  * to vncserver
@@ -138,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 */
@@ -194,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
@@ -24,7 +24,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]