diff --git a/src/gvnc.c b/src/gvnc.c --- a/src/gvnc.c +++ b/src/gvnc.c @@ -38,8 +38,6 @@ #include #include - -#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, @@ -1985,7 +1987,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 + * + * 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 +#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 - * - * 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 was put together by VirtualBox. It's based on the information in + * /usr/share/X11/xkb/keycodes/evdev using the x_keycode_to_pc_keycode table + * to get the pc keycodes. */ -#include "x_keymap.h" -#include - -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 +#include +#include +#include + +#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 #include -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);