src/video/x11/SDL_x11keyboard.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 02 Mar 2013 20:44:16 -0800
changeset 6950 1ddb72193079
parent 6885 700f1b25f77f
child 7580 5a924aac594c
permissions -rw-r--r--
Added a mouse ID to the mouse events, which set to the special value SDL_TOUCH_MOUSEID for mouse events simulated by touch input.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 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_config.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* */
    36 static const struct {
    37     KeySym keysym;
    38     SDL_Keycode sdlkey;
    39 } KeySymToSDLKey[] = {
    40     { XK_Return, SDLK_RETURN },
    41     { XK_Escape, SDLK_ESCAPE },
    42     { XK_BackSpace, SDLK_BACKSPACE },
    43     { XK_Tab, SDLK_TAB },
    44     { XK_Caps_Lock, SDLK_CAPSLOCK },
    45     { XK_F1, SDLK_F1 },
    46     { XK_F2, SDLK_F2 },
    47     { XK_F3, SDLK_F3 },
    48     { XK_F4, SDLK_F4 },
    49     { XK_F5, SDLK_F5 },
    50     { XK_F6, SDLK_F6 },
    51     { XK_F7, SDLK_F7 },
    52     { XK_F8, SDLK_F8 },
    53     { XK_F9, SDLK_F9 },
    54     { XK_F10, SDLK_F10 },
    55     { XK_F11, SDLK_F11 },
    56     { XK_F12, SDLK_F12 },
    57     { XK_Print, SDLK_PRINTSCREEN },
    58     { XK_Scroll_Lock, SDLK_SCROLLLOCK },
    59     { XK_Pause, SDLK_PAUSE },
    60     { XK_Insert, SDLK_INSERT },
    61     { XK_Home, SDLK_HOME },
    62     { XK_Prior, SDLK_PAGEUP },
    63     { XK_Delete, SDLK_DELETE },
    64     { XK_End, SDLK_END },
    65     { XK_Next, SDLK_PAGEDOWN },
    66     { XK_Right, SDLK_RIGHT },
    67     { XK_Left, SDLK_LEFT },
    68     { XK_Down, SDLK_DOWN },
    69     { XK_Up, SDLK_UP },
    70     { XK_Num_Lock, SDLK_NUMLOCKCLEAR },
    71     { XK_KP_Divide, SDLK_KP_DIVIDE },
    72     { XK_KP_Multiply, SDLK_KP_MULTIPLY },
    73     { XK_KP_Subtract, SDLK_KP_MINUS },
    74     { XK_KP_Add, SDLK_KP_PLUS },
    75     { XK_KP_Enter, SDLK_KP_ENTER },
    76     { XK_KP_Delete, SDLK_KP_PERIOD },
    77     { XK_KP_End, SDLK_KP_1 },
    78     { XK_KP_Down, SDLK_KP_2 },
    79     { XK_KP_Next, SDLK_KP_3 },
    80     { XK_KP_Left, SDLK_KP_4 },
    81     { XK_KP_Begin, SDLK_KP_5 },
    82     { XK_KP_Right, SDLK_KP_6 },
    83     { XK_KP_Home, SDLK_KP_7 },
    84     { XK_KP_Up, SDLK_KP_8 },
    85     { XK_KP_Prior, SDLK_KP_9 },
    86     { XK_KP_Insert, SDLK_KP_0 },
    87     { XK_KP_Decimal, SDLK_KP_PERIOD },
    88     { XK_KP_1, SDLK_KP_1 },
    89     { XK_KP_2, SDLK_KP_2 },
    90     { XK_KP_3, SDLK_KP_3 },
    91     { XK_KP_4, SDLK_KP_4 },
    92     { XK_KP_5, SDLK_KP_5 },
    93     { XK_KP_6, SDLK_KP_6 },
    94     { XK_KP_7, SDLK_KP_7 },
    95     { XK_KP_8, SDLK_KP_8 },
    96     { XK_KP_9, SDLK_KP_9 },
    97     { XK_KP_0, SDLK_KP_0 },
    98     { XK_KP_Decimal, SDLK_KP_PERIOD },
    99     { XK_Hyper_R, SDLK_APPLICATION },
   100     { XK_KP_Equal, SDLK_KP_EQUALS },
   101     { XK_F13, SDLK_F13 },
   102     { XK_F14, SDLK_F14 },
   103     { XK_F15, SDLK_F15 },
   104     { XK_F16, SDLK_F16 },
   105     { XK_F17, SDLK_F17 },
   106     { XK_F18, SDLK_F18 },
   107     { XK_F19, SDLK_F19 },
   108     { XK_F20, SDLK_F20 },
   109     { XK_F21, SDLK_F21 },
   110     { XK_F22, SDLK_F22 },
   111     { XK_F23, SDLK_F23 },
   112     { XK_F24, SDLK_F24 },
   113     { XK_Execute, SDLK_EXECUTE },
   114     { XK_Help, SDLK_HELP },
   115     { XK_Menu, SDLK_MENU },
   116     { XK_Select, SDLK_SELECT },
   117     { XK_Cancel, SDLK_STOP },
   118     { XK_Redo, SDLK_AGAIN },
   119     { XK_Undo, SDLK_UNDO },
   120     { XK_Find, SDLK_FIND },
   121     { XK_KP_Separator, SDLK_KP_COMMA },
   122     { XK_Sys_Req, SDLK_SYSREQ },
   123     { XK_Control_L, SDLK_LCTRL },
   124     { XK_Shift_L, SDLK_LSHIFT },
   125     { XK_Alt_L, SDLK_LALT },
   126     { XK_Meta_L, SDLK_LGUI },
   127     { XK_Super_L, SDLK_LGUI },
   128     { XK_Control_R, SDLK_RCTRL },
   129     { XK_Shift_R, SDLK_RSHIFT },
   130     { XK_Alt_R, SDLK_RALT },
   131     { XK_Meta_R, SDLK_RGUI },
   132     { XK_Super_R, SDLK_RGUI },
   133     { XK_Mode_switch, SDLK_MODE },
   134 };
   135 
   136 static const struct
   137 {
   138     const 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 static SDL_Keycode
   148 X11_KeyCodeToSDLKey(Display *display, KeyCode keycode)
   149 {
   150     KeySym keysym;
   151     unsigned int ucs4;
   152     int i;
   153 
   154 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
   155     keysym = XkbKeycodeToKeysym(display, keycode, 0, 0);
   156 #else
   157     keysym = XKeycodeToKeysym(display, keycode, 0);
   158 #endif
   159     if (keysym == NoSymbol) {
   160         return SDLK_UNKNOWN;
   161     }
   162 
   163     ucs4 = X11_KeySymToUcs4(keysym);
   164     if (ucs4) {
   165         return (SDL_Keycode) ucs4;
   166     }
   167 
   168     for (i = 0; i < SDL_arraysize(KeySymToSDLKey); ++i) {
   169         if (keysym == KeySymToSDLKey[i].keysym) {
   170             return KeySymToSDLKey[i].sdlkey;
   171         }
   172     }
   173     return SDLK_UNKNOWN;
   174 }
   175 
   176 int
   177 X11_InitKeyboard(_THIS)
   178 {
   179     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   180     int i, j;
   181     int min_keycode, max_keycode;
   182     struct {
   183         SDL_Scancode scancode;
   184         KeySym keysym;
   185         int value;
   186     } fingerprint[] = {
   187         { SDL_SCANCODE_HOME, XK_Home, 0 },
   188         { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
   189         { SDL_SCANCODE_PAGEDOWN, XK_Next, 0 },
   190     };
   191     SDL_bool fingerprint_detected;
   192 
   193     XAutoRepeatOn(data->display);
   194 
   195     /* Try to determine which scancodes are being used based on fingerprint */
   196     fingerprint_detected = SDL_FALSE;
   197     XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
   198     for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
   199         fingerprint[i].value =
   200             XKeysymToKeycode(data->display, fingerprint[i].keysym) -
   201             min_keycode;
   202     }
   203     for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
   204         /* Make sure the scancode set isn't too big */
   205         if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
   206             continue;
   207         }
   208         for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
   209             if (fingerprint[j].value < 0
   210                 || fingerprint[j].value >= scancode_set[i].table_size) {
   211                 break;
   212             }
   213             if (scancode_set[i].table[fingerprint[j].value] !=
   214                 fingerprint[j].scancode) {
   215                 break;
   216             }
   217         }
   218         if (j == SDL_arraysize(fingerprint)) {
   219 #ifdef DEBUG_KEYBOARD
   220             printf("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", i, min_keycode, max_keycode, scancode_set[i].table_size);
   221 #endif
   222             SDL_memcpy(&data->key_layout[min_keycode], scancode_set[i].table,
   223                        sizeof(SDL_Scancode) * scancode_set[i].table_size);
   224             fingerprint_detected = SDL_TRUE;
   225             break;
   226         }
   227     }
   228 
   229     if (!fingerprint_detected) {
   230         SDL_Keycode keymap[SDL_NUM_SCANCODES];
   231 
   232         printf
   233             ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
   234 
   235         /* Determine key_layout - only works on US QWERTY layout */
   236         SDL_GetDefaultKeymap(keymap);
   237         for (i = min_keycode; i <= max_keycode; ++i) {
   238             KeySym sym;
   239 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
   240             sym = XkbKeycodeToKeysym(data->display, i, 0, 0);
   241 #else
   242             sym = XKeycodeToKeysym(data->display, i, 0);
   243 #endif
   244             if (sym != NoSymbol) {
   245                 SDL_Keycode key;
   246                 printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
   247                        (unsigned int) sym, XKeysymToString(sym));
   248                 key = X11_KeyCodeToSDLKey(data->display, i);
   249                 for (j = 0; j < SDL_arraysize(keymap); ++j) {
   250                     if (keymap[j] == key) {
   251                         data->key_layout[i] = (SDL_Scancode) j;
   252                         break;
   253                     }
   254                 }
   255                 if (j == SDL_arraysize(keymap)) {
   256                     printf("scancode not found\n");
   257                 } else {
   258                     printf("scancode = %d (%s)\n", j, SDL_GetScancodeName(j));
   259                 }
   260             }
   261         }
   262     }
   263 
   264     X11_UpdateKeymap(_this);
   265 
   266     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
   267 
   268     return 0;
   269 }
   270 
   271 void
   272 X11_UpdateKeymap(_THIS)
   273 {
   274     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   275     int i;
   276     SDL_Scancode scancode;
   277     SDL_Keycode keymap[SDL_NUM_SCANCODES];
   278 
   279     SDL_zero(keymap);
   280 
   281     for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
   282 
   283         /* Make sure this is a valid scancode */
   284         scancode = data->key_layout[i];
   285         if (scancode == SDL_SCANCODE_UNKNOWN) {
   286             continue;
   287         }
   288 
   289         keymap[scancode] = X11_KeyCodeToSDLKey(data->display, (KeyCode)i);
   290     }
   291     SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
   292 }
   293 
   294 void
   295 X11_QuitKeyboard(_THIS)
   296 {
   297 }
   298 
   299 #endif /* SDL_VIDEO_DRIVER_X11 */
   300 
   301 /* vi: set ts=4 sw=4 expandtab: */