src/video/x11/SDL_x11keyboard.c
changeset 2295 dbc6d1893869
parent 1950 a344e42bce3b
child 2296 0869721b488f
--- a/src/video/x11/SDL_x11keyboard.c	Thu Jan 03 06:07:30 2008 +0000
+++ b/src/video/x11/SDL_x11keyboard.c	Tue Jan 08 00:10:46 2008 +0000
@@ -25,14 +25,993 @@
 
 #include "../../events/SDL_keyboard_c.h"
 
-void
+#include <X11/keysym.h>
+
+#include "imKStoUCS.h"
+
+/* Used for two purposes: - by X11_GetLayoutKey(), with physical =
+    false, to convert a KeySym to the corresponding layout key code
+    (SDLK_ ones and some character ones - most character KeySyms are
+    handled by X11_KeySymToUcs4() after this function returns
+    SDLK_UNKNOWN for them).  - by X11_InitKeyboard(), with physical =
+    true, to build a makeshift translation table based on the KeySyms
+    when none of the predefined KeyCode- to-SDLKey tables fits. This
+    is *not* correct anywhere but on a US layout, since the
+    translation table deals with physical key codes, while the X11
+    KeySym corresponds to our concept of a layout key code, but it's
+    better than nothing.
+*/
+
+/* KeyCode-to-SDLKey translation tables for various X servers. Which one to use
+   is decided in X11_InitKeyboard().
+*/
+
+static SDLKey macKeyCodeToSDLK[];
+static SDLKey xorgLinuxKeyCodeToSDLK[];
+
+static SDLKey *keyCodeToSDLKeyTables[] = {
+    xorgLinuxKeyCodeToSDLK,
+    macKeyCodeToSDLK,
+    NULL
+};
+
+/* *INDENT-OFF* */
+
+/* These are just Mac virtual key codes + 8 (see SDL/src/video/cocoa/
+   SDL_cocoakeys.h for more info). Observed to work with Apple X11 on
+   Mac OS X 10.4. May also work on older Linux distributions on Mac
+   hardware.
+*/
+static SDLKey macKeyCodeToSDLK[] = {
+    /*   0 */   SDLK_UNKNOWN,
+    /*   1 */   SDLK_UNKNOWN,
+    /*   2 */   SDLK_UNKNOWN,
+    /*   3 */   SDLK_UNKNOWN,
+    /*   4 */   SDLK_UNKNOWN,
+    /*   5 */   SDLK_UNKNOWN,
+    /*   6 */   SDLK_UNKNOWN,
+    /*   7 */   SDLK_UNKNOWN,
+    /*   8 */   SDLK_A,
+    /*   9 */   SDLK_S,
+    /*  10 */   SDLK_D,
+    /*  11 */   SDLK_F,
+    /*  12 */   SDLK_H,
+    /*  13 */   SDLK_G,
+    /*  14 */   SDLK_Z,
+    /*  15 */   SDLK_X,
+    /*  16 */   SDLK_C,
+    /*  17 */   SDLK_V,
+    /*  18 */   SDLK_GRAVE,
+    /*  19 */   SDLK_B,
+    /*  20 */   SDLK_Q,
+    /*  21 */   SDLK_W,
+    /*  22 */   SDLK_E,
+    /*  23 */   SDLK_R,
+    /*  24 */   SDLK_Y,
+    /*  25 */   SDLK_T,
+    /*  26 */   SDLK_1,
+    /*  27 */   SDLK_2,
+    /*  28 */   SDLK_3,
+    /*  29 */   SDLK_4,
+    /*  30 */   SDLK_6,
+    /*  31 */   SDLK_5,
+    /*  32 */   SDLK_EQUALS,
+    /*  33 */   SDLK_9,
+    /*  34 */   SDLK_7,
+    /*  35 */   SDLK_HYPHENMINUS,
+    /*  36 */   SDLK_8,
+    /*  37 */   SDLK_0,
+    /*  38 */   SDLK_RIGHTBRACKET,
+    /*  39 */   SDLK_O,
+    /*  40 */   SDLK_U,
+    /*  41 */   SDLK_LEFTBRACKET,
+    /*  42 */   SDLK_I,
+    /*  43 */   SDLK_P,
+    /*  44 */   SDLK_RETURN,
+    /*  45 */   SDLK_L,
+    /*  46 */   SDLK_J,
+    /*  47 */   SDLK_APOSTROPHE,
+    /*  48 */   SDLK_K,
+    /*  49 */   SDLK_SEMICOLON,
+    /*  50 */   SDLK_BACKSLASH,
+    /*  51 */   SDLK_COMMA,
+    /*  52 */   SDLK_SLASH,
+    /*  53 */   SDLK_N,
+    /*  54 */   SDLK_M,
+    /*  55 */   SDLK_PERIOD,
+    /*  56 */   SDLK_TAB,
+    /*  57 */   SDLK_SPACE,
+    /*  58 */   SDLK_NONUSBACKSLASH,
+    /*  59 */   SDLK_BACKSPACE,
+    /*  60 */   SDLK_KP_ENTER,
+    /*  61 */   SDLK_ESCAPE,
+    /*  62 */   SDLK_RMETA,
+    /*  63 */   SDLK_LMETA,
+    /*  64 */   SDLK_LSHIFT,
+    /*  65 */   SDLK_CAPSLOCK,
+    /*  66 */   SDLK_LALT,
+    /*  67 */   SDLK_LCTRL,
+    /*  68 */   SDLK_RSHIFT,
+    /*  69 */   SDLK_RALT,
+    /*  70 */   SDLK_RCTRL,
+    /*  71 */   SDLK_NONE,
+    /*  72 */   SDLK_UNKNOWN,
+    /*  73 */   SDLK_KP_PERIOD,
+    /*  74 */   SDLK_UNKNOWN,
+    /*  75 */   SDLK_KP_MULTIPLY,
+    /*  76 */   SDLK_UNKNOWN,
+    /*  77 */   SDLK_KP_PLUS,
+    /*  78 */   SDLK_UNKNOWN,
+    /*  79 */   SDLK_KP_NUMLOCKCLEAR,
+    /*  80 */   SDLK_VOLUMEUP,
+    /*  81 */   SDLK_VOLUMEDOWN,
+    /*  82 */   SDLK_MUTE,
+    /*  83 */   SDLK_KP_DIVIDE,
+    /*  84 */   SDLK_KP_ENTER,
+    /*  85 */   SDLK_UNKNOWN,
+    /*  86 */   SDLK_KP_MINUS,
+    /*  87 */   SDLK_UNKNOWN,
+    /*  88 */   SDLK_UNKNOWN,
+    /*  89 */   SDLK_KP_EQUALS,
+    /*  90 */   SDLK_KP_0,
+    /*  91 */   SDLK_KP_1,
+    /*  92 */   SDLK_KP_2,
+    /*  93 */   SDLK_KP_3,
+    /*  94 */   SDLK_KP_4,
+    /*  95 */   SDLK_KP_5,
+    /*  96 */   SDLK_KP_6,
+    /*  97 */   SDLK_KP_7,
+    /*  98 */   SDLK_UNKNOWN,
+    /*  99 */   SDLK_KP_8,
+    /* 100 */   SDLK_KP_9,
+    /* 101 */   SDLK_INTERNATIONAL3,
+    /* 102 */   SDLK_INTERNATIONAL1,
+    /* 103 */   SDLK_KP_COMMA,
+    /* 104 */   SDLK_F5,
+    /* 105 */   SDLK_F6,
+    /* 106 */   SDLK_F7,
+    /* 107 */   SDLK_F3,
+    /* 108 */   SDLK_F8,
+    /* 109 */   SDLK_F9,
+    /* 110 */   SDLK_LANG2,
+    /* 111 */   SDLK_F11,
+    /* 112 */   SDLK_LANG1,
+    /* 113 */   SDLK_PRINTSCREEN,
+    /* 114 */   SDLK_F16,
+    /* 115 */   SDLK_SCROLLLOCK,
+    /* 116 */   SDLK_UNKNOWN,
+    /* 117 */   SDLK_F10,
+    /* 118 */   SDLK_APPLICATION,
+    /* 119 */   SDLK_F12,
+    /* 120 */   SDLK_UNKNOWN,
+    /* 121 */   SDLK_PAUSE,
+    /* 122 */   SDLK_INSERT,
+    /* 123 */   SDLK_HOME,
+    /* 124 */   SDLK_PAGEUP,
+    /* 125 */   SDLK_DELETE,
+    /* 126 */   SDLK_F4,
+    /* 127 */   SDLK_END,
+    /* 128 */   SDLK_F2,
+    /* 129 */   SDLK_PAGEDOWN,
+    /* 130 */   SDLK_F1,
+    /* 131 */   SDLK_LEFT,
+    /* 132 */   SDLK_RIGHT,
+    /* 133 */   SDLK_DOWN,
+    /* 134 */   SDLK_UP,
+    /* 135 */   SDLK_POWER,
+    /* 136 */   SDLK_UNKNOWN, /* codes higher than 135 shouldn't occur as Mac virtual keycodes only go to 127 */
+    /* 137 */   SDLK_UNKNOWN,
+    /* 138 */   SDLK_UNKNOWN,
+    /* 139 */   SDLK_UNKNOWN,
+    /* 140 */   SDLK_UNKNOWN,
+    /* 141 */   SDLK_UNKNOWN,
+    /* 142 */   SDLK_UNKNOWN,
+    /* 143 */   SDLK_UNKNOWN,
+    /* 144 */   SDLK_UNKNOWN,
+    /* 145 */   SDLK_UNKNOWN,
+    /* 146 */   SDLK_UNKNOWN,
+    /* 147 */   SDLK_UNKNOWN,
+    /* 148 */   SDLK_UNKNOWN,
+    /* 149 */   SDLK_UNKNOWN,
+    /* 150 */   SDLK_UNKNOWN,
+    /* 151 */   SDLK_UNKNOWN,
+    /* 152 */   SDLK_UNKNOWN,
+    /* 153 */   SDLK_UNKNOWN,
+    /* 154 */   SDLK_UNKNOWN,
+    /* 155 */   SDLK_UNKNOWN,
+    /* 156 */   SDLK_UNKNOWN,
+    /* 157 */   SDLK_UNKNOWN,
+    /* 158 */   SDLK_UNKNOWN,
+    /* 159 */   SDLK_UNKNOWN,
+    /* 160 */   SDLK_UNKNOWN,
+    /* 161 */   SDLK_UNKNOWN,
+    /* 162 */   SDLK_UNKNOWN,
+    /* 163 */   SDLK_UNKNOWN,
+    /* 164 */   SDLK_UNKNOWN,
+    /* 165 */   SDLK_UNKNOWN,
+    /* 166 */   SDLK_UNKNOWN,
+    /* 167 */   SDLK_UNKNOWN,
+    /* 168 */   SDLK_UNKNOWN,
+    /* 169 */   SDLK_UNKNOWN,
+    /* 170 */   SDLK_UNKNOWN,
+    /* 171 */   SDLK_UNKNOWN,
+    /* 172 */   SDLK_UNKNOWN,
+    /* 173 */   SDLK_UNKNOWN,
+    /* 174 */   SDLK_UNKNOWN,
+    /* 175 */   SDLK_UNKNOWN,
+    /* 176 */   SDLK_UNKNOWN,
+    /* 177 */   SDLK_UNKNOWN,
+    /* 178 */   SDLK_UNKNOWN,
+    /* 179 */   SDLK_UNKNOWN,
+    /* 180 */   SDLK_UNKNOWN,
+    /* 181 */   SDLK_UNKNOWN,
+    /* 182 */   SDLK_UNKNOWN,
+    /* 183 */   SDLK_UNKNOWN,
+    /* 184 */   SDLK_UNKNOWN,
+    /* 185 */   SDLK_UNKNOWN,
+    /* 186 */   SDLK_UNKNOWN,
+    /* 187 */   SDLK_UNKNOWN,
+    /* 188 */   SDLK_UNKNOWN,
+    /* 189 */   SDLK_UNKNOWN,
+    /* 190 */   SDLK_UNKNOWN,
+    /* 191 */   SDLK_UNKNOWN,
+    /* 192 */   SDLK_UNKNOWN,
+    /* 193 */   SDLK_UNKNOWN,
+    /* 194 */   SDLK_UNKNOWN,
+    /* 195 */   SDLK_UNKNOWN,
+    /* 196 */   SDLK_UNKNOWN,
+    /* 197 */   SDLK_UNKNOWN,
+    /* 198 */   SDLK_UNKNOWN,
+    /* 199 */   SDLK_UNKNOWN,
+    /* 200 */   SDLK_UNKNOWN,
+    /* 201 */   SDLK_UNKNOWN,
+    /* 202 */   SDLK_UNKNOWN,
+    /* 203 */   SDLK_UNKNOWN,
+    /* 204 */   SDLK_UNKNOWN,
+    /* 205 */   SDLK_UNKNOWN,
+    /* 206 */   SDLK_UNKNOWN,
+    /* 207 */   SDLK_UNKNOWN,
+    /* 208 */   SDLK_UNKNOWN,
+    /* 209 */   SDLK_UNKNOWN,
+    /* 210 */   SDLK_UNKNOWN,
+    /* 211 */   SDLK_UNKNOWN,
+    /* 212 */   SDLK_UNKNOWN,
+    /* 213 */   SDLK_UNKNOWN,
+    /* 214 */   SDLK_UNKNOWN,
+    /* 215 */   SDLK_UNKNOWN,
+    /* 216 */   SDLK_UNKNOWN,
+    /* 217 */   SDLK_UNKNOWN,
+    /* 218 */   SDLK_UNKNOWN,
+    /* 219 */   SDLK_UNKNOWN,
+    /* 220 */   SDLK_UNKNOWN,
+    /* 221 */   SDLK_UNKNOWN,
+    /* 222 */   SDLK_UNKNOWN,
+    /* 223 */   SDLK_UNKNOWN,
+    /* 224 */   SDLK_UNKNOWN,
+    /* 225 */   SDLK_UNKNOWN,
+    /* 226 */   SDLK_UNKNOWN,
+    /* 227 */   SDLK_UNKNOWN,
+    /* 228 */   SDLK_UNKNOWN,
+    /* 229 */   SDLK_UNKNOWN,
+    /* 230 */   SDLK_UNKNOWN,
+    /* 231 */   SDLK_UNKNOWN,
+    /* 232 */   SDLK_UNKNOWN,
+    /* 233 */   SDLK_UNKNOWN,
+    /* 234 */   SDLK_UNKNOWN,
+    /* 235 */   SDLK_UNKNOWN,
+    /* 236 */   SDLK_UNKNOWN,
+    /* 237 */   SDLK_UNKNOWN,
+    /* 238 */   SDLK_UNKNOWN,
+    /* 239 */   SDLK_UNKNOWN,
+    /* 240 */   SDLK_UNKNOWN,
+    /* 241 */   SDLK_UNKNOWN,
+    /* 242 */   SDLK_UNKNOWN,
+    /* 243 */   SDLK_UNKNOWN,
+    /* 244 */   SDLK_UNKNOWN,
+    /* 245 */   SDLK_UNKNOWN,
+    /* 246 */   SDLK_UNKNOWN,
+    /* 247 */   SDLK_UNKNOWN,
+    /* 248 */   SDLK_UNKNOWN,
+    /* 249 */   SDLK_UNKNOWN,
+    /* 250 */   SDLK_UNKNOWN,
+    /* 251 */   SDLK_UNKNOWN,
+    /* 252 */   SDLK_UNKNOWN,
+    /* 253 */   SDLK_UNKNOWN,
+    /* 254 */   SDLK_UNKNOWN,
+    /* 255 */   SDLK_UNKNOWN
+};
+
+/* Found mostly by experimentation with X.org on Linux (Fedora Core 4 and
+   Ubuntu Dapper) on PC and PPC Mac hardware, some parts (especially about
+   the "multimedia"/"internet" keys) from various sources on the web.
+*/
+static SDLKey xorgLinuxKeyCodeToSDLK[] = {
+    /*   0 */   SDLK_UNKNOWN,
+    /*   1 */   SDLK_UNKNOWN,
+    /*   2 */   SDLK_UNKNOWN,
+    /*   3 */   SDLK_UNKNOWN,
+    /*   4 */   SDLK_UNKNOWN,
+    /*   5 */   SDLK_UNKNOWN,
+    /*   6 */   SDLK_UNKNOWN,
+    /*   7 */   SDLK_UNKNOWN,
+    /*   8 */   SDLK_UNKNOWN,
+    /*   9 */   SDLK_ESCAPE,
+    /*  10 */   SDLK_1,
+    /*  11 */   SDLK_2,
+    /*  12 */   SDLK_3,
+    /*  13 */   SDLK_4,
+    /*  14 */   SDLK_5,
+    /*  15 */   SDLK_6,
+    /*  16 */   SDLK_7,
+    /*  17 */   SDLK_8,
+    /*  18 */   SDLK_9,
+    /*  19 */   SDLK_0,
+    /*  20 */   SDLK_HYPHENMINUS,
+    /*  21 */   SDLK_EQUALS,
+    /*  22 */   SDLK_BACKSPACE,
+    /*  23 */   SDLK_TAB,
+    /*  24 */   SDLK_Q,
+    /*  25 */   SDLK_W,
+    /*  26 */   SDLK_E,
+    /*  27 */   SDLK_R,
+    /*  28 */   SDLK_T,
+    /*  29 */   SDLK_Y,
+    /*  30 */   SDLK_U,
+    /*  31 */   SDLK_I,
+    /*  32 */   SDLK_O,
+    /*  33 */   SDLK_P,
+    /*  34 */   SDLK_LEFTBRACKET,
+    /*  35 */   SDLK_RIGHTBRACKET,
+    /*  36 */   SDLK_RETURN,
+    /*  37 */   SDLK_LCTRL,
+    /*  38 */   SDLK_A,
+    /*  39 */   SDLK_S,
+    /*  40 */   SDLK_D,
+    /*  41 */   SDLK_F,
+    /*  42 */   SDLK_G,
+    /*  43 */   SDLK_H,
+    /*  44 */   SDLK_J,
+    /*  45 */   SDLK_K,
+    /*  46 */   SDLK_L,
+    /*  47 */   SDLK_SEMICOLON,
+    /*  48 */   SDLK_APOSTROPHE,
+    /*  49 */   SDLK_GRAVE,
+    /*  50 */   SDLK_LSHIFT,
+    /*  51 */   SDLK_BACKSLASH,
+    /*  52 */   SDLK_Z,
+    /*  53 */   SDLK_X,
+    /*  54 */   SDLK_C,
+    /*  55 */   SDLK_V,
+    /*  56 */   SDLK_B,
+    /*  57 */   SDLK_N,
+    /*  58 */   SDLK_M,
+    /*  59 */   SDLK_COMMA,
+    /*  60 */   SDLK_PERIOD,
+    /*  61 */   SDLK_SLASH,
+    /*  62 */   SDLK_RSHIFT,
+    /*  63 */   SDLK_KP_MULTIPLY,
+    /*  64 */   SDLK_LALT,
+    /*  65 */   SDLK_SPACE,
+    /*  66 */   SDLK_CAPSLOCK,
+    /*  67 */   SDLK_F1,
+    /*  68 */   SDLK_F2,
+    /*  69 */   SDLK_F3,
+    /*  70 */   SDLK_F4,
+    /*  71 */   SDLK_F5,
+    /*  72 */   SDLK_F6,
+    /*  73 */   SDLK_F7,
+    /*  74 */   SDLK_F8,
+    /*  75 */   SDLK_F9,
+    /*  76 */   SDLK_F10,
+    /*  77 */   SDLK_KP_NUMLOCKCLEAR,
+    /*  78 */   SDLK_SCROLLLOCK,
+    /*  79 */   SDLK_KP_7,
+    /*  80 */   SDLK_KP_8,
+    /*  81 */   SDLK_KP_9,
+    /*  82 */   SDLK_KP_MINUS,
+    /*  83 */   SDLK_KP_4,
+    /*  84 */   SDLK_KP_5,
+    /*  85 */   SDLK_KP_6,
+    /*  86 */   SDLK_KP_PLUS,
+    /*  87 */   SDLK_KP_1,
+    /*  88 */   SDLK_KP_2,
+    /*  89 */   SDLK_KP_3,
+    /*  90 */   SDLK_KP_0,
+    /*  91 */   SDLK_KP_PERIOD,
+    /*  92 */   SDLK_SYSREQ,
+    /*  93 */   SDLK_MODE, /* is translated to XK_Mode_switch by my X server, but I have no keyboard that generates this code, so I'm not sure if this is correct */
+    /*  94 */   SDLK_NONUSBACKSLASH,
+    /*  95 */   SDLK_F11,
+    /*  96 */   SDLK_F12,
+    /*  97 */   SDLK_HOME,
+    /*  98 */   SDLK_UP,
+    /*  99 */   SDLK_PAGEUP,
+    /* 100 */   SDLK_LEFT,
+    /* 101 */   SDLK_BRIGHTNESSDOWN, /* on PowerBook G4 */
+    /* 102 */   SDLK_RIGHT,
+    /* 103 */   SDLK_END,
+    /* 104 */   SDLK_DOWN,
+    /* 105 */   SDLK_PAGEDOWN,
+    /* 106 */   SDLK_INSERT,
+    /* 107 */   SDLK_DELETE,
+    /* 108 */   SDLK_KP_ENTER,
+    /* 109 */   SDLK_RCTRL,
+    /* 110 */   SDLK_PAUSE,
+    /* 111 */   SDLK_PRINTSCREEN,
+    /* 112 */   SDLK_KP_DIVIDE,
+    /* 113 */   SDLK_RALT,
+    /* 114 */   SDLK_UNKNOWN,
+    /* 115 */   SDLK_LMETA,
+    /* 116 */   SDLK_RMETA,
+    /* 117 */   SDLK_APPLICATION,
+    /* 118 */   SDLK_F13,
+    /* 119 */   SDLK_F14,
+    /* 120 */   SDLK_F15,
+    /* 121 */   SDLK_F16,
+    /* 122 */   SDLK_F17,
+    /* 123 */   SDLK_UNKNOWN,
+    /* 124 */   SDLK_UNKNOWN, /* is translated to XK_ISO_Level3_Shift by my X server, but I have no keyboard that generates this code, so I don't know what the correct SDLK_* for it is */
+    /* 125 */   SDLK_UNKNOWN,
+    /* 126 */   SDLK_KP_EQUALS,
+    /* 127 */   SDLK_UNKNOWN,
+    /* 128 */   SDLK_UNKNOWN,
+    /* 129 */   SDLK_UNKNOWN,
+    /* 130 */   SDLK_UNKNOWN,
+    /* 131 */   SDLK_UNKNOWN,
+    /* 132 */   SDLK_UNKNOWN,
+    /* 133 */   SDLK_INTERNATIONAL3, /* Yen */
+    /* 134 */   SDLK_UNKNOWN,
+    /* 135 */   SDLK_AGAIN,
+    /* 136 */   SDLK_UNDO,
+    /* 137 */   SDLK_UNKNOWN,
+    /* 138 */   SDLK_UNKNOWN,
+    /* 139 */   SDLK_UNKNOWN,
+    /* 140 */   SDLK_UNKNOWN,
+    /* 141 */   SDLK_UNKNOWN,
+    /* 142 */   SDLK_UNKNOWN,
+    /* 143 */   SDLK_UNKNOWN,
+    /* 144 */   SDLK_AUDIOPREV,
+    /* 145 */   SDLK_UNKNOWN,
+    /* 146 */   SDLK_UNKNOWN,
+    /* 147 */   SDLK_UNKNOWN,
+    /* 148 */   SDLK_UNKNOWN,
+    /* 149 */   SDLK_UNKNOWN,
+    /* 150 */   SDLK_UNKNOWN,
+    /* 151 */   SDLK_UNKNOWN,
+    /* 152 */   SDLK_UNKNOWN,
+    /* 153 */   SDLK_AUDIONEXT,
+    /* 154 */   SDLK_UNKNOWN,
+    /* 155 */   SDLK_UNKNOWN,
+    /* 156 */   SDLK_UNKNOWN,
+    /* 157 */   SDLK_KP_EQUALS, /* on PowerBook G4 */
+    /* 158 */   SDLK_UNKNOWN,
+    /* 159 */   SDLK_UNKNOWN,
+    /* 160 */   SDLK_MUTE,
+    /* 161 */   SDLK_CALC,
+    /* 162 */   SDLK_AUDIOPLAY,
+    /* 163 */   SDLK_UNKNOWN,
+    /* 164 */   SDLK_AUDIOSTOP,
+    /* 165 */   SDLK_UNKNOWN,
+    /* 166 */   SDLK_UNKNOWN,
+    /* 167 */   SDLK_UNKNOWN,
+    /* 168 */   SDLK_UNKNOWN,
+    /* 169 */   SDLK_UNKNOWN,
+    /* 170 */   SDLK_UNKNOWN,
+    /* 171 */   SDLK_UNKNOWN,
+    /* 172 */   SDLK_UNKNOWN,
+    /* 173 */   SDLK_UNKNOWN,
+    /* 174 */   SDLK_VOLUMEDOWN,
+    /* 175 */   SDLK_UNKNOWN,
+    /* 176 */   SDLK_VOLUMEUP,
+    /* 177 */   SDLK_UNKNOWN,
+    /* 178 */   SDLK_WWW,
+    /* 179 */   SDLK_UNKNOWN,
+    /* 180 */   SDLK_UNKNOWN,
+    /* 181 */   SDLK_UNKNOWN,
+    /* 182 */   SDLK_UNKNOWN,
+    /* 183 */   SDLK_UNKNOWN,
+    /* 184 */   SDLK_UNKNOWN,
+    /* 185 */   SDLK_UNKNOWN,
+    /* 186 */   SDLK_UNKNOWN,
+    /* 187 */   SDLK_HELP,
+    /* 188 */   SDLK_UNKNOWN,
+    /* 189 */   SDLK_UNKNOWN,
+    /* 190 */   SDLK_UNKNOWN,
+    /* 191 */   SDLK_UNKNOWN,
+    /* 192 */   SDLK_UNKNOWN,
+    /* 193 */   SDLK_UNKNOWN,
+    /* 194 */   SDLK_UNKNOWN,
+    /* 195 */   SDLK_UNKNOWN,
+    /* 196 */   SDLK_UNKNOWN,
+    /* 197 */   SDLK_UNKNOWN,
+    /* 198 */   SDLK_UNKNOWN,
+    /* 199 */   SDLK_UNKNOWN,
+    /* 200 */   SDLK_UNKNOWN,
+    /* 201 */   SDLK_UNKNOWN,
+    /* 202 */   SDLK_UNKNOWN,
+    /* 203 */   SDLK_UNKNOWN,
+    /* 204 */   SDLK_EJECT, /* on PowerBook G4 */
+    /* 205 */   SDLK_UNKNOWN,
+    /* 206 */   SDLK_UNKNOWN,
+    /* 207 */   SDLK_UNKNOWN,
+    /* 208 */   SDLK_UNKNOWN,
+    /* 209 */   SDLK_UNKNOWN,
+    /* 210 */   SDLK_UNKNOWN,
+    /* 211 */   SDLK_UNKNOWN,
+    /* 212 */   SDLK_BRIGHTNESSUP, /* on PowerBook G4 */
+    /* 213 */   SDLK_UNKNOWN,
+    /* 214 */   SDLK_DISPLAYSWITCH, /* on PowerBook G4 */
+    /* 215 */   SDLK_KBDILLUMTOGGLE,
+    /* 216 */   SDLK_KBDILLUMDOWN,
+    /* 217 */   SDLK_KBDILLUMUP,
+    /* 218 */   SDLK_UNKNOWN,
+    /* 219 */   SDLK_UNKNOWN,
+    /* 220 */   SDLK_UNKNOWN,
+    /* 221 */   SDLK_UNKNOWN,
+    /* 222 */   SDLK_POWER,
+    /* 223 */   SDLK_SLEEP,
+    /* 224 */   SDLK_UNKNOWN,
+    /* 225 */   SDLK_UNKNOWN,
+    /* 226 */   SDLK_UNKNOWN,
+    /* 227 */   SDLK_UNKNOWN,
+    /* 228 */   SDLK_UNKNOWN,
+    /* 229 */   SDLK_SEARCH,
+    /* 230 */   SDLK_BOOKMARKS,
+    /* 231 */   SDLK_BROWSERRELOAD,
+    /* 232 */   SDLK_BROWSERSTOP,
+    /* 233 */   SDLK_BROWSERFORWARD,
+    /* 234 */   SDLK_BROWSERBACK,
+    /* 235 */   SDLK_COMPUTER,
+    /* 236 */   SDLK_EMAIL,
+    /* 237 */   SDLK_MEDIA,
+    /* 238 */   SDLK_UNKNOWN,
+    /* 239 */   SDLK_UNKNOWN,
+    /* 240 */   SDLK_UNKNOWN,
+    /* 241 */   SDLK_UNKNOWN,
+    /* 242 */   SDLK_UNKNOWN,
+    /* 243 */   SDLK_UNKNOWN,
+    /* 244 */   SDLK_UNKNOWN,
+    /* 245 */   SDLK_UNKNOWN,
+    /* 246 */   SDLK_UNKNOWN,
+    /* 247 */   SDLK_UNKNOWN,
+    /* 248 */   SDLK_UNKNOWN,
+    /* 249 */   SDLK_UNKNOWN,
+    /* 250 */   SDLK_UNKNOWN,
+    /* 251 */   SDLK_UNKNOWN,
+    /* 252 */   SDLK_UNKNOWN,
+    /* 253 */   SDLK_UNKNOWN,
+    /* 254 */   SDLK_UNKNOWN,
+    /* 255 */   SDLK_UNKNOWN
+};
+
+/* *INDENT-ON* */
+
+/*---------------------------------------------------------------------------*/
+
+/* Used by X11_KeySymToSDLKey(). This is a hybrid of a KeySym-to-layout-key
+    mapping (needed in X11_GetLayoutKey()) and a fallback KeySym-to-physical-key
+    mapping under the assumption of a US keyboard layout (needed in
+    X11_InitKeyboard()). If for a given KeySym...
+    - the layout and physical codes are the same (must be an SDLK_ constant):
+      there is one entry,
+    - the layout and physical codes differ: there are two entries, with the
+      layout one first,
+    - there is only a physical code in the table (must be an SDLK_ constant):
+      it's marked by X11_KEY_PHYSICAL_ONLY_BIT (this is the case when the layout
+      key code is handled by KeySymToUcs4()),
+    - there is only a layout code in the table (can't be an SDLK_ constant):
+      recognizable by the absence of SDL_KEY_CAN_BE_PHYSICAL_BIT.
+    This list is sorted by KeySym to allow a binary search.
+*/
+#define X11_KEY_PHYSICAL_ONLY_BIT SDL_KEY_LAYOUT_SPECIAL_BIT
+/* SDL_KEY_LAYOUT_SPECIAL_BIT cannot possibly occur in an SDLK_ constant, so we may repurpose that bit for our own use. */
+static struct
+{
+    KeySym sym;
+    SDLKey key;
+} keySymToSDLKey[] = {
+    /* 0x00xx */
+    {
+    XK_space, SDLK_SPACE}, {
+    XK_apostrophe, SDLK_APOSTROPHE | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_comma, SDLK_COMMA | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_minus, SDLK_HYPHENMINUS | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_period, SDLK_PERIOD | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_slash, SDLK_SLASH | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_0, SDLK_0 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_1, SDLK_1 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_2, SDLK_2 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_3, SDLK_3 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_4, SDLK_4 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_5, SDLK_5 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_6, SDLK_6 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_7, SDLK_7 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_8, SDLK_8 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_9, SDLK_9 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_semicolon, SDLK_SEMICOLON | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_less, SDLK_NONUSBACKSLASH | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_equal, SDLK_EQUALS | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_bracketleft, SDLK_LEFTBRACKET | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_backslash, SDLK_BACKSLASH | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_bracketright, SDLK_RIGHTBRACKET | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_grave, SDLK_GRAVE | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_a, SDLK_A | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_b, SDLK_B | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_c, SDLK_C | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_d, SDLK_D | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_e, SDLK_E | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_f, SDLK_F | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_g, SDLK_G | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_h, SDLK_H | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_i, SDLK_I | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_j, SDLK_J | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_k, SDLK_K | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_l, SDLK_L | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_m, SDLK_M | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_n, SDLK_N | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_o, SDLK_O | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_p, SDLK_P | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_q, SDLK_Q | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_r, SDLK_R | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_s, SDLK_S | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_t, SDLK_T | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_u, SDLK_U | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_v, SDLK_V | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_w, SDLK_W | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_x, SDLK_X | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_y, SDLK_Y | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_z, SDLK_Z | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_section, SDLK_NONUSBACKSLASH | X11_KEY_PHYSICAL_ONLY_BIT},
+        /* 0xFExx */
+    {
+    XK_ISO_Level3_Shift, SDLK_RALT}, {
+    XK_dead_grave, '`'}, {
+    XK_dead_acute, 0xB4}, {
+    XK_dead_circumflex, '^'}, {
+    XK_dead_tilde, '~'}, {
+    XK_dead_macron, 0xAF}, {
+    XK_dead_breve, 0x2D8}, {
+    XK_dead_abovedot, 0x2D9}, {
+    XK_dead_diaeresis, 0xA8}, {
+    XK_dead_abovering, 0x2DA}, {
+    XK_dead_doubleacute, 0x2DD}, {
+    XK_dead_caron, 0x2C7}, {
+    XK_dead_cedilla, 0xB8}, {
+    XK_dead_ogonek, 0x2DB}, {
+    XK_dead_iota, 0x3B9}, {
+    XK_dead_voiced_sound, 0x309B}, {
+    XK_dead_semivoiced_sound, 0x309C}, {
+    XK_dead_belowdot, 0xB7},    /* that's actually MIDDLE DOT, but I haven't found a non-combining DOT BELOW */
+        /* XK_dead_hook, XK_dead_horn: I haven't found non-combining HOOK and HORN characters */
+        /* 0xFFxx */
+    {
+    XK_BackSpace, SDLK_BACKSPACE}, {
+    XK_Tab, SDLK_TAB}, {
+    XK_Return, SDLK_RETURN}, {
+    XK_Pause, SDLK_PAUSE}, {
+    XK_Scroll_Lock, SDLK_SCROLLLOCK}, {
+    XK_Escape, SDLK_ESCAPE}, {
+    XK_Home, SDLK_HOME}, {
+    XK_Left, SDLK_LEFT}, {
+    XK_Up, SDLK_UP}, {
+    XK_Right, SDLK_RIGHT}, {
+    XK_Down, SDLK_DOWN}, {
+    XK_Page_Up, SDLK_PAGEUP}, {
+    XK_Page_Down, SDLK_PAGEDOWN}, {
+    XK_End, SDLK_END}, {
+    XK_Print, SDLK_PRINTSCREEN}, {
+    XK_Insert, SDLK_INSERT}, {
+    XK_Menu, SDLK_APPLICATION}, {
+    XK_Break, SDLK_PAUSE}, {
+    XK_Mode_switch, SDLK_MODE}, {
+    XK_Num_Lock, SDLK_KP_NUMLOCKCLEAR}, {
+    XK_KP_Enter, SDLK_KP_ENTER}, {
+    XK_KP_Home, SDLK_KP_7 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Left, SDLK_KP_4 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Up, SDLK_KP_8 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Right, SDLK_KP_6 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Down, SDLK_KP_2 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Page_Up, SDLK_KP_9 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Page_Down, SDLK_KP_3 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_End, SDLK_KP_1 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Begin, SDLK_KP_5 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Insert, SDLK_KP_0 | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Delete, SDLK_KP_PERIOD | X11_KEY_PHYSICAL_ONLY_BIT}, {
+    XK_KP_Multiply, '*'}, {
+    XK_KP_Multiply, SDLK_KP_MULTIPLY}, {
+    XK_KP_Add, '+'}, {
+    XK_KP_Add, SDLK_KP_PLUS}, {
+    XK_KP_Separator, '.'}, {
+    XK_KP_Separator, SDLK_KP_PERIOD}, {
+    XK_KP_Subtract, '-'}, {
+    XK_KP_Subtract, SDLK_KP_MINUS}, {
+    XK_KP_Decimal, '.'}, {
+    XK_KP_Decimal, SDLK_KP_PERIOD}, {
+    XK_KP_Divide, '/'}, {
+    XK_KP_Divide, SDLK_KP_DIVIDE}, {
+    XK_KP_0, '0'}, {
+    XK_KP_0, SDLK_KP_0}, {
+    XK_KP_1, '1'}, {
+    XK_KP_1, SDLK_KP_1}, {
+    XK_KP_2, '2'}, {
+    XK_KP_2, SDLK_KP_2}, {
+    XK_KP_3, '3'}, {
+    XK_KP_3, SDLK_KP_3}, {
+    XK_KP_4, '4'}, {
+    XK_KP_4, SDLK_KP_4}, {
+    XK_KP_5, '5'}, {
+    XK_KP_5, SDLK_KP_5}, {
+    XK_KP_6, '6'}, {
+    XK_KP_6, SDLK_KP_6}, {
+    XK_KP_7, '7'}, {
+    XK_KP_7, SDLK_KP_7}, {
+    XK_KP_8, '8'}, {
+    XK_KP_8, SDLK_KP_8}, {
+    XK_KP_9, '9'}, {
+    XK_KP_9, SDLK_KP_9}, {
+    XK_KP_Equal, '='}, {
+    XK_KP_Equal, SDLK_KP_EQUALS}, {
+    XK_F1, SDLK_F1}, {
+    XK_F2, SDLK_F2}, {
+    XK_F3, SDLK_F3}, {
+    XK_F4, SDLK_F4}, {
+    XK_F5, SDLK_F5}, {
+    XK_F6, SDLK_F6}, {
+    XK_F7, SDLK_F7}, {
+    XK_F8, SDLK_F8}, {
+    XK_F9, SDLK_F9}, {
+    XK_F10, SDLK_F10}, {
+    XK_F11, SDLK_F11}, {
+    XK_F12, SDLK_F12}, {
+    XK_F13, SDLK_F13}, {
+    XK_F14, SDLK_F14}, {
+    XK_F15, SDLK_F15}, {
+    XK_F16, SDLK_F16}, {
+    XK_F17, SDLK_F17}, {
+    XK_F18, SDLK_F18}, {
+    XK_F19, SDLK_F19}, {
+    XK_F20, SDLK_F20}, {
+    XK_F21, SDLK_F21}, {
+    XK_F22, SDLK_F22}, {
+    XK_F23, SDLK_F23}, {
+    XK_F24, SDLK_F24}, {
+    XK_Shift_L, SDLK_LSHIFT}, {
+    XK_Shift_R, SDLK_RSHIFT}, {
+    XK_Control_L, SDLK_LCTRL}, {
+    XK_Control_R, SDLK_RCTRL}, {
+    XK_Caps_Lock, SDLK_CAPSLOCK}, {
+    XK_Shift_Lock, SDLK_CAPSLOCK}, {
+    XK_Meta_L, SDLK_LMETA}, {
+    XK_Meta_R, SDLK_RMETA}, {
+    XK_Alt_L, SDLK_LALT}, {
+    XK_Alt_R, SDLK_RALT}, {
+    XK_Super_L, SDLK_LMETA}, {
+    XK_Super_R, SDLK_RMETA}, {
+    XK_Hyper_L, SDLK_LMETA}, {
+    XK_Hyper_R, SDLK_RMETA}, {
+    XK_Delete, SDLK_DELETE}, {
+    0x1000003, SDLK_KP_ENTER}   /* keyboard enter on Mac OS X */
+};
+
+static SDLKey
+X11_KeySymToSDLKey(KeySym sym, SDL_bool physical)
+{
+    /* Do a binary search for sym in the keySymToSDLKey table */
+    SDLKey key = SDLK_UNKNOWN;
+    int start = -1;
+    int end = SDL_arraysize(keySymToSDLKey);
+    int i;
+    /* Invariant: keySymToSDLKey[start].sym < sym <
+       keySymToSDLKey[end].sym (imagine ...[-1] = -inf and
+       ...[arraysize] = inf, these entries needn't be there in reality
+       because they're never accessed) */
+    while (end > start + 1) {
+        i = (start + end) / 2;
+        if (keySymToSDLKey[i].sym == sym) {
+            /* found an entry, if it's the second of two back up to the first */
+            if (keySymToSDLKey[i - 1].sym == sym)
+                i--;
+            /* if there are two, the physical one is the second */
+            if (physical && keySymToSDLKey[i + 1].sym == sym)
+                i++;
+            key = keySymToSDLKey[i].key;
+            break;
+        } else if (keySymToSDLKey[i].sym < sym)
+            start = i;
+        else
+            end = i;
+    }
+
+    /* if we're being asked for a layout key code, but the table only
+       has a physical one, or vice versa, return SDLK_UNKNOWN) */
+
+    if (!physical && ((key & X11_KEY_PHYSICAL_ONLY_BIT) != 0)
+        || physical && ((key & SDL_KEY_CAN_BE_PHYSICAL_BIT) == 0))
+        key = SDLK_UNKNOWN;
+    key &= ~X11_KEY_PHYSICAL_ONLY_BIT;
+    return key;
+}
+
+int
 X11_InitKeyboard(_THIS)
 {
     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
     SDL_Keyboard keyboard;
+    SDLKey **table;
+    SDLKey *foundTable;
+    int i;
+    int code;
+    SDLKey sdlkey;
+
+    /* A random collection of KeySym/SDLKey pairs that should be valid
+       in any keyboard layout (if this isn't the case on yours,
+       please adjust). Using XKeysymToKeycode on these KeySyms
+       creates a "fingerprint" of the X server's key-to-KeyCode
+       mapping which is then matched against all our predefined
+       KeyCodeToSDLK tables to find the right one (if any).
+     */
+    struct
+    {
+        KeySym sym;
+        SDLKey key;
+    } fingerprint[] = {
+        {
+        XK_Tab, SDLK_TAB}, {
+        XK_Return, SDLK_RETURN}, {
+        XK_Escape, SDLK_ESCAPE}, {
+        XK_space, SDLK_SPACE}
+    };
 
     SDL_zero(keyboard);
     data->keyboard = SDL_AddKeyboard(&keyboard, -1);
+
+    /* Determine which X11 KeyCode to SDL physical key code table to use */
+
+    foundTable = NULL;
+    table = keyCodeToSDLKeyTables;
+    while ((NULL == foundTable) && (NULL != (*table))) {
+        foundTable = *table;
+        for (i = 0; i < SDL_arraysize(fingerprint); i++) {
+            code = XKeysymToKeycode(data->display, fingerprint[i].sym);
+            if ((code != 0) && ((*table)[code] != fingerprint[i].key)) {
+                foundTable = NULL;
+                break;
+            }
+        }
+        table++;
+    }
+
+    if (NULL != foundTable) {
+        /* Found a suitable one among the predefined tables */
+        data->keyCodeToSDLKTable = foundTable;
+    } else {
+        /* No suitable table found - build a makeshift table based on
+           the KeySyms, assuming a US keyboard layout */
+
+#if 1
+        fprintf(stderr,
+                "The key codes of your X server are unknown to SDL. Keys may not be recognized properly. To help get this fixed, report this to the SDL mailing list <sdl@libsdl.org> or to Christian Walther <cwalther@gmx.ch>.\n");
+#endif
+        data->keyCodeToSDLKTable =
+            SDL_malloc(SDL_arraysize(xorgLinuxKeyCodeToSDLK));
+        if (data->keyCodeToSDLKTable == NULL) {
+            SDL_OutOfMemory();
+            return -1;
+        }
+        for (code = SDL_arraysize(xorgLinuxKeyCodeToSDLK); code >= 0; code--) {
+            data->keyCodeToSDLKTable[code] =
+                X11_KeySymToSDLKey(XKeycodeToKeysym(data->display, code, 0),
+                                   SDL_TRUE);
+        }
+    }
+
+    /* Set some non-default key names */
+
+    for (code = 0; code < SDL_arraysize(xorgLinuxKeyCodeToSDLK); code++) {
+        sdlkey = data->keyCodeToSDLKTable[code];
+        switch (sdlkey) {
+            /* The SDLK_*META keys are used as XK_Meta_* by some X
+               servers, as XK_Super_* by others */
+        case SDLK_LMETA:
+        case SDLK_RMETA:
+            switch (XKeycodeToKeysym(data->display, code, 0)) {
+                /* nothing to do for XK_Meta_* because that's already the default name */
+            case XK_Super_L:
+                SDL_SetKeyName(sdlkey, "left super");
+                break;
+            case XK_Super_R:
+                SDL_SetKeyName(sdlkey, "right super");
+                break;
+            }
+            break;
+        }
+    }
+    SDL_SetKeyName(SDLK_APPLICATION, "menu");
+
+    return 0;
+}
+
+SDLKey
+X11_GetLayoutKey(_THIS, SDLKey physicalKey)
+{
+    SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
+    int code = 0;
+    KeySym sym;
+    SDLKey layoutKey;
+
+    switch (physicalKey) {
+    case SDLK_UNKNOWN:
+        return physicalKey;
+
+        /* Shortcut handling of keypad numbers because on my PC their
+           primary KeySyms are not the numbers that I want but
+           XK_KP_Home, XK_KP_Up etc. The downside is that this gets us
+           latin numerals even on e.g. an Arabic layout. */
+    case SDLK_KP_1:
+        return '1';
+    case SDLK_KP_2:
+        return '2';
+    case SDLK_KP_3:
+        return '3';
+    case SDLK_KP_4:
+        return '4';
+    case SDLK_KP_5:
+        return '5';
+    case SDLK_KP_6:
+        return '6';
+    case SDLK_KP_7:
+        return '7';
+    case SDLK_KP_8:
+        return '8';
+    case SDLK_KP_9:
+        return '9';
+    case SDLK_KP_0:
+        return '0';
+    case SDLK_KP_PERIOD:
+        return '.';
+    default:
+        break;                  /* just to avoid a compiler warning */
+    }
+
+    /* Look up physicalKey to get an X11 KeyCode - linear search isn't
+       terribly efficient, this might have to be optimized. */
+    while ((code < SDL_arraysize(xorgLinuxKeyCodeToSDLK) && physicalKey)
+           != data->keyCodeToSDLKTable[code]) {
+        code++;
+    }
+
+    if (code == SDL_arraysize(xorgLinuxKeyCodeToSDLK)) {
+        return physicalKey;
+    }
+    /* Get the corresponding KeySym - this is where the keyboard
+       layout comes into play */
+    sym = XKeycodeToKeysym(data->display, code, 0);
+
+    /* Try our own KeySym-to-layout-key-code table: it handles all
+       keys whose layout code is an SDLK_ one, including a few where
+       X11_KeySymToUcs4() would yield a character, but not a suitable
+       one as a key name (e.g. space), and some that are character
+       keys for our purposes, but aren't handled by X11_KeySymToUcs4()
+       (dead keys, keypad operations). */
+
+    layoutKey = X11_KeySymToSDLKey(sym, SDL_FALSE);
+
+    /* If it wasn't handled by X11_KeySymToSDLKey(), it's most
+       probably a plain character KeySym that X11_KeySymToUcs4()
+       (ripped from X.org) knows. */
+
+    if (layoutKey == SDLK_UNKNOWN) {
+        unsigned int ucs = X11_KeySymToUcs4(sym);
+        if (ucs != 0)
+            layoutKey = (SDLKey) ucs;
+    }
+
+    /* Still no success? Give up. */
+    if (layoutKey == SDLK_UNKNOWN) {
+        return physicalKey;
+    }
+
+    return layoutKey;
 }
 
 void
@@ -40,6 +1019,18 @@
 {
     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
 
+    if (data->keyCodeToSDLKTable != NULL) {
+        /* If it's not one of the predefined tables, it was malloced
+           and must be freed */
+        SDLKey **table = keyCodeToSDLKeyTables;
+        while (*table != NULL && *table != data->keyCodeToSDLKTable) {
+            table++;
+        }
+        if (*table == NULL)
+            SDL_free(data->keyCodeToSDLKTable);
+        data->keyCodeToSDLKTable = NULL;
+    }
+
     SDL_DelKeyboard(data->keyboard);
 }