SDL_x11keyboard.c (11144B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../../SDL_internal.h" 22 23#if SDL_VIDEO_DRIVER_X11 24 25#include "SDL_x11video.h" 26 27#include "../../events/SDL_keyboard_c.h" 28#include "../../events/scancodes_darwin.h" 29#include "../../events/scancodes_xfree86.h" 30 31#include <X11/keysym.h> 32 33#include "imKStoUCS.h" 34 35/* *INDENT-OFF* */ 36static const struct { 37 KeySym keysym; 38 SDL_Scancode scancode; 39} KeySymToSDLScancode[] = { 40 { XK_Return, SDL_SCANCODE_RETURN }, 41 { XK_Escape, SDL_SCANCODE_ESCAPE }, 42 { XK_BackSpace, SDL_SCANCODE_BACKSPACE }, 43 { XK_Tab, SDL_SCANCODE_TAB }, 44 { XK_Caps_Lock, SDL_SCANCODE_CAPSLOCK }, 45 { XK_F1, SDL_SCANCODE_F1 }, 46 { XK_F2, SDL_SCANCODE_F2 }, 47 { XK_F3, SDL_SCANCODE_F3 }, 48 { XK_F4, SDL_SCANCODE_F4 }, 49 { XK_F5, SDL_SCANCODE_F5 }, 50 { XK_F6, SDL_SCANCODE_F6 }, 51 { XK_F7, SDL_SCANCODE_F7 }, 52 { XK_F8, SDL_SCANCODE_F8 }, 53 { XK_F9, SDL_SCANCODE_F9 }, 54 { XK_F10, SDL_SCANCODE_F10 }, 55 { XK_F11, SDL_SCANCODE_F11 }, 56 { XK_F12, SDL_SCANCODE_F12 }, 57 { XK_Print, SDL_SCANCODE_PRINTSCREEN }, 58 { XK_Scroll_Lock, SDL_SCANCODE_SCROLLLOCK }, 59 { XK_Pause, SDL_SCANCODE_PAUSE }, 60 { XK_Insert, SDL_SCANCODE_INSERT }, 61 { XK_Home, SDL_SCANCODE_HOME }, 62 { XK_Prior, SDL_SCANCODE_PAGEUP }, 63 { XK_Delete, SDL_SCANCODE_DELETE }, 64 { XK_End, SDL_SCANCODE_END }, 65 { XK_Next, SDL_SCANCODE_PAGEDOWN }, 66 { XK_Right, SDL_SCANCODE_RIGHT }, 67 { XK_Left, SDL_SCANCODE_LEFT }, 68 { XK_Down, SDL_SCANCODE_DOWN }, 69 { XK_Up, SDL_SCANCODE_UP }, 70 { XK_Num_Lock, SDL_SCANCODE_NUMLOCKCLEAR }, 71 { XK_KP_Divide, SDL_SCANCODE_KP_DIVIDE }, 72 { XK_KP_Multiply, SDL_SCANCODE_KP_MULTIPLY }, 73 { XK_KP_Subtract, SDL_SCANCODE_KP_MINUS }, 74 { XK_KP_Add, SDL_SCANCODE_KP_PLUS }, 75 { XK_KP_Enter, SDL_SCANCODE_KP_ENTER }, 76 { XK_KP_Delete, SDL_SCANCODE_KP_PERIOD }, 77 { XK_KP_End, SDL_SCANCODE_KP_1 }, 78 { XK_KP_Down, SDL_SCANCODE_KP_2 }, 79 { XK_KP_Next, SDL_SCANCODE_KP_3 }, 80 { XK_KP_Left, SDL_SCANCODE_KP_4 }, 81 { XK_KP_Begin, SDL_SCANCODE_KP_5 }, 82 { XK_KP_Right, SDL_SCANCODE_KP_6 }, 83 { XK_KP_Home, SDL_SCANCODE_KP_7 }, 84 { XK_KP_Up, SDL_SCANCODE_KP_8 }, 85 { XK_KP_Prior, SDL_SCANCODE_KP_9 }, 86 { XK_KP_Insert, SDL_SCANCODE_KP_0 }, 87 { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD }, 88 { XK_KP_1, SDL_SCANCODE_KP_1 }, 89 { XK_KP_2, SDL_SCANCODE_KP_2 }, 90 { XK_KP_3, SDL_SCANCODE_KP_3 }, 91 { XK_KP_4, SDL_SCANCODE_KP_4 }, 92 { XK_KP_5, SDL_SCANCODE_KP_5 }, 93 { XK_KP_6, SDL_SCANCODE_KP_6 }, 94 { XK_KP_7, SDL_SCANCODE_KP_7 }, 95 { XK_KP_8, SDL_SCANCODE_KP_8 }, 96 { XK_KP_9, SDL_SCANCODE_KP_9 }, 97 { XK_KP_0, SDL_SCANCODE_KP_0 }, 98 { XK_KP_Decimal, SDL_SCANCODE_KP_PERIOD }, 99 { XK_Hyper_R, SDL_SCANCODE_APPLICATION }, 100 { XK_KP_Equal, SDL_SCANCODE_KP_EQUALS }, 101 { XK_F13, SDL_SCANCODE_F13 }, 102 { XK_F14, SDL_SCANCODE_F14 }, 103 { XK_F15, SDL_SCANCODE_F15 }, 104 { XK_F16, SDL_SCANCODE_F16 }, 105 { XK_F17, SDL_SCANCODE_F17 }, 106 { XK_F18, SDL_SCANCODE_F18 }, 107 { XK_F19, SDL_SCANCODE_F19 }, 108 { XK_F20, SDL_SCANCODE_F20 }, 109 { XK_F21, SDL_SCANCODE_F21 }, 110 { XK_F22, SDL_SCANCODE_F22 }, 111 { XK_F23, SDL_SCANCODE_F23 }, 112 { XK_F24, SDL_SCANCODE_F24 }, 113 { XK_Execute, SDL_SCANCODE_EXECUTE }, 114 { XK_Help, SDL_SCANCODE_HELP }, 115 { XK_Menu, SDL_SCANCODE_MENU }, 116 { XK_Select, SDL_SCANCODE_SELECT }, 117 { XK_Cancel, SDL_SCANCODE_STOP }, 118 { XK_Redo, SDL_SCANCODE_AGAIN }, 119 { XK_Undo, SDL_SCANCODE_UNDO }, 120 { XK_Find, SDL_SCANCODE_FIND }, 121 { XK_KP_Separator, SDL_SCANCODE_KP_COMMA }, 122 { XK_Sys_Req, SDL_SCANCODE_SYSREQ }, 123 { XK_Control_L, SDL_SCANCODE_LCTRL }, 124 { XK_Shift_L, SDL_SCANCODE_LSHIFT }, 125 { XK_Alt_L, SDL_SCANCODE_LALT }, 126 { XK_Meta_L, SDL_SCANCODE_LGUI }, 127 { XK_Super_L, SDL_SCANCODE_LGUI }, 128 { XK_Control_R, SDL_SCANCODE_RCTRL }, 129 { XK_Shift_R, SDL_SCANCODE_RSHIFT }, 130 { XK_Alt_R, SDL_SCANCODE_RALT }, 131 { XK_Meta_R, SDL_SCANCODE_RGUI }, 132 { XK_Super_R, SDL_SCANCODE_RGUI }, 133 { XK_Mode_switch, SDL_SCANCODE_MODE }, 134}; 135 136static const struct 137{ 138 SDL_Scancode const *table; 139 int table_size; 140} scancode_set[] = { 141 { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) }, 142 { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) }, 143 { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) }, 144}; 145/* *INDENT-OFF* */ 146 147/* This function only works for keyboards in US QWERTY layout */ 148static SDL_Scancode 149X11_KeyCodeToSDLScancode(Display *display, KeyCode keycode) 150{ 151 KeySym keysym; 152 int i; 153 154#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 155 keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); 156#else 157 keysym = XKeycodeToKeysym(display, keycode, 0); 158#endif 159 if (keysym == NoSymbol) { 160 return SDL_SCANCODE_UNKNOWN; 161 } 162 163 if (keysym >= XK_A && keysym <= XK_Z) { 164 return SDL_SCANCODE_A + (keysym - XK_A); 165 } 166 167 if (keysym >= XK_0 && keysym <= XK_9) { 168 return SDL_SCANCODE_0 + (keysym - XK_0); 169 } 170 171 for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) { 172 if (keysym == KeySymToSDLScancode[i].keysym) { 173 return KeySymToSDLScancode[i].scancode; 174 } 175 } 176 return SDL_SCANCODE_UNKNOWN; 177} 178 179static Uint32 180X11_KeyCodeToUcs4(Display *display, KeyCode keycode) 181{ 182 KeySym keysym; 183 184#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 185 keysym = X11_XkbKeycodeToKeysym(display, keycode, 0, 0); 186#else 187 keysym = XKeycodeToKeysym(display, keycode, 0); 188#endif 189 if (keysym == NoSymbol) { 190 return 0; 191 } 192 193 return X11_KeySymToUcs4(keysym); 194} 195 196int 197X11_InitKeyboard(_THIS) 198{ 199 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 200 int i = 0; 201 int j = 0; 202 int min_keycode, max_keycode; 203 struct { 204 SDL_Scancode scancode; 205 KeySym keysym; 206 int value; 207 } fingerprint[] = { 208 { SDL_SCANCODE_HOME, XK_Home, 0 }, 209 { SDL_SCANCODE_PAGEUP, XK_Prior, 0 }, 210 { SDL_SCANCODE_UP, XK_Up, 0 }, 211 { SDL_SCANCODE_LEFT, XK_Left, 0 }, 212 { SDL_SCANCODE_DELETE, XK_Delete, 0 }, 213 { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 }, 214 }; 215 int best_distance; 216 int best_index; 217 int distance; 218 219 X11_XAutoRepeatOn(data->display); 220 221 /* Try to determine which scancodes are being used based on fingerprint */ 222 best_distance = SDL_arraysize(fingerprint) + 1; 223 best_index = -1; 224 X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode); 225 for (i = 0; i < SDL_arraysize(fingerprint); ++i) { 226 fingerprint[i].value = 227 X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) - 228 min_keycode; 229 } 230 for (i = 0; i < SDL_arraysize(scancode_set); ++i) { 231 /* Make sure the scancode set isn't too big */ 232 if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) { 233 continue; 234 } 235 distance = 0; 236 for (j = 0; j < SDL_arraysize(fingerprint); ++j) { 237 if (fingerprint[j].value < 0 238 || fingerprint[j].value >= scancode_set[i].table_size) { 239 distance += 1; 240 } else if (scancode_set[i].table[fingerprint[j].value] != fingerprint[j].scancode) { 241 distance += 1; 242 } 243 } 244 if (distance < best_distance) { 245 best_distance = distance; 246 best_index = i; 247 } 248 } 249 if (best_index >= 0 && best_distance <= 2) { 250#ifdef DEBUG_KEYBOARD 251 printf("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, scancode_set[best_index].table_size); 252#endif 253 SDL_memcpy(&data->key_layout[min_keycode], scancode_set[best_index].table, 254 sizeof(SDL_Scancode) * scancode_set[best_index].table_size); 255 } 256 else { 257 SDL_Keycode keymap[SDL_NUM_SCANCODES]; 258 259 printf 260 ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n"); 261 262 /* Determine key_layout - only works on US QWERTY layout */ 263 SDL_GetDefaultKeymap(keymap); 264 for (i = min_keycode; i <= max_keycode; ++i) { 265 KeySym sym; 266#if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 267 sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0); 268#else 269 sym = XKeycodeToKeysym(data->display, i, 0); 270#endif 271 if (sym != NoSymbol) { 272 SDL_Scancode scancode; 273 printf("code = %d, sym = 0x%X (%s) ", i - min_keycode, 274 (unsigned int) sym, X11_XKeysymToString(sym)); 275 scancode = X11_KeyCodeToSDLScancode(data->display, i); 276 data->key_layout[i] = scancode; 277 if (scancode == SDL_SCANCODE_UNKNOWN) { 278 printf("scancode not found\n"); 279 } else { 280 printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode)); 281 } 282 } 283 } 284 } 285 286 X11_UpdateKeymap(_this); 287 288 SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu"); 289 290#ifdef SDL_USE_IBUS 291 SDL_IBus_Init(); 292#endif 293 294 return 0; 295} 296 297void 298X11_UpdateKeymap(_THIS) 299{ 300 SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; 301 int i; 302 SDL_Scancode scancode; 303 SDL_Keycode keymap[SDL_NUM_SCANCODES]; 304 305 SDL_GetDefaultKeymap(keymap); 306 for (i = 0; i < SDL_arraysize(data->key_layout); i++) { 307 Uint32 key; 308 309 /* Make sure this is a valid scancode */ 310 scancode = data->key_layout[i]; 311 if (scancode == SDL_SCANCODE_UNKNOWN) { 312 continue; 313 } 314 315 /* See if there is a UCS keycode for this scancode */ 316 key = X11_KeyCodeToUcs4(data->display, (KeyCode)i); 317 if (key) { 318 keymap[scancode] = key; 319 } 320 } 321 SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); 322} 323 324void 325X11_QuitKeyboard(_THIS) 326{ 327#ifdef SDL_USE_IBUS 328 SDL_IBus_Quit(); 329#endif 330} 331 332void 333X11_StartTextInput(_THIS) 334{ 335 336} 337 338void 339X11_StopTextInput(_THIS) 340{ 341#ifdef SDL_USE_IBUS 342 SDL_IBus_Reset(); 343#endif 344} 345 346void 347X11_SetTextInputRect(_THIS, SDL_Rect *rect) 348{ 349 if (!rect) { 350 SDL_InvalidParamError("rect"); 351 return; 352 } 353 354#ifdef SDL_USE_IBUS 355 SDL_IBus_UpdateTextRect(rect); 356#endif 357} 358 359#endif /* SDL_VIDEO_DRIVER_X11 */ 360 361/* vi: set ts=4 sw=4 expandtab: */