src/video/x11/SDL_x11keyboard.c
author Sam Lantinga
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8093 b43765095a6f
child 8667 fb44c438a3e5
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     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_PAGEDOWN, XK_Next, 0 },
   211     };
   212     SDL_bool fingerprint_detected;
   213 
   214     X11_XAutoRepeatOn(data->display);
   215 
   216     /* Try to determine which scancodes are being used based on fingerprint */
   217     fingerprint_detected = SDL_FALSE;
   218     X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
   219     for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
   220         fingerprint[i].value =
   221             X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) -
   222             min_keycode;
   223     }
   224     for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
   225         /* Make sure the scancode set isn't too big */
   226         if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
   227             continue;
   228         }
   229         for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
   230             if (fingerprint[j].value < 0
   231                 || fingerprint[j].value >= scancode_set[i].table_size) {
   232                 break;
   233             }
   234             if (scancode_set[i].table[fingerprint[j].value] !=
   235                 fingerprint[j].scancode) {
   236                 break;
   237             }
   238         }
   239         if (j == SDL_arraysize(fingerprint)) {
   240 #ifdef DEBUG_KEYBOARD
   241             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);
   242 #endif
   243             SDL_memcpy(&data->key_layout[min_keycode], scancode_set[i].table,
   244                        sizeof(SDL_Scancode) * scancode_set[i].table_size);
   245             fingerprint_detected = SDL_TRUE;
   246             break;
   247         }
   248     }
   249 
   250     if (!fingerprint_detected) {
   251         SDL_Keycode keymap[SDL_NUM_SCANCODES];
   252 
   253         printf
   254             ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
   255 
   256         /* Determine key_layout - only works on US QWERTY layout */
   257         SDL_GetDefaultKeymap(keymap);
   258         for (i = min_keycode; i <= max_keycode; ++i) {
   259             KeySym sym;
   260 #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
   261             sym = X11_XkbKeycodeToKeysym(data->display, i, 0, 0);
   262 #else
   263             sym = XKeycodeToKeysym(data->display, i, 0);
   264 #endif
   265             if (sym != NoSymbol) {
   266                 SDL_Scancode scancode;
   267                 printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
   268                        (unsigned int) sym, X11_XKeysymToString(sym));
   269                 scancode = X11_KeyCodeToSDLScancode(data->display, i);
   270                 data->key_layout[i] = scancode;
   271                 if (scancode == SDL_SCANCODE_UNKNOWN) {
   272                     printf("scancode not found\n");
   273                 } else {
   274                     printf("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
   275                 }
   276             }
   277         }
   278     }
   279 
   280     X11_UpdateKeymap(_this);
   281 
   282     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
   283 
   284     return 0;
   285 }
   286 
   287 void
   288 X11_UpdateKeymap(_THIS)
   289 {
   290     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   291     int i;
   292     SDL_Scancode scancode;
   293     SDL_Keycode keymap[SDL_NUM_SCANCODES];
   294 
   295     SDL_GetDefaultKeymap(keymap);
   296     for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
   297         Uint32 key;
   298 
   299         /* Make sure this is a valid scancode */
   300         scancode = data->key_layout[i];
   301         if (scancode == SDL_SCANCODE_UNKNOWN) {
   302             continue;
   303         }
   304 
   305         /* See if there is a UCS keycode for this scancode */
   306         key = X11_KeyCodeToUcs4(data->display, (KeyCode)i);
   307         if (key) {
   308             keymap[scancode] = key;
   309         }
   310     }
   311     SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
   312 }
   313 
   314 void
   315 X11_QuitKeyboard(_THIS)
   316 {
   317 }
   318 
   319 #endif /* SDL_VIDEO_DRIVER_X11 */
   320 
   321 /* vi: set ts=4 sw=4 expandtab: */