src/video/x11/SDL_x11keyboard.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 06 Apr 2015 00:10:54 -0400
changeset 9458 543298b36b28
parent 9096 6454f71d6f15
child 9619 b94b6d0bff0f
permissions -rw-r--r--
This function can be static.
     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* */
    36 static 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 
   136 static 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 */
   148 static SDL_Scancode
   149 X11_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 
   179 static Uint32
   180 X11_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 
   196 int
   197 X11_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 
   297 void
   298 X11_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 
   324 void
   325 X11_QuitKeyboard(_THIS)
   326 {
   327 #ifdef SDL_USE_IBUS
   328     SDL_IBus_Quit();
   329 #endif
   330 }
   331 
   332 void
   333 X11_StartTextInput(_THIS)
   334 {
   335 
   336 }
   337 
   338 void
   339 X11_StopTextInput(_THIS)
   340 {
   341 #ifdef SDL_USE_IBUS
   342     SDL_IBus_Reset();
   343 #endif
   344 }
   345 
   346 void
   347 X11_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: */