src/video/x11/SDL_x11keyboard.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 12 Mar 2011 13:21:57 -0800
changeset 5481 22dfc3958dc3
parent 5262 b530ef003506
child 5535 96594ac5fd1a
permissions -rw-r--r--
Fixed so code will compile with SDL_config_minimal.h
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_DRIVER_X11
    25 
    26 #include "SDL_x11video.h"
    27 
    28 #include "../../events/SDL_keyboard_c.h"
    29 #include "../../events/scancodes_darwin.h"
    30 #include "../../events/scancodes_xfree86.h"
    31 
    32 #include <X11/keysym.h>
    33 
    34 #include "imKStoUCS.h"
    35 
    36 /* *INDENT-OFF* */
    37 static const struct {
    38     KeySym keysym;
    39     SDL_Keycode sdlkey;
    40 } KeySymToSDLKey[] = {
    41     { XK_Return, SDLK_RETURN },
    42     { XK_Escape, SDLK_ESCAPE },
    43     { XK_BackSpace, SDLK_BACKSPACE },
    44     { XK_Tab, SDLK_TAB },
    45     { XK_Caps_Lock, SDLK_CAPSLOCK },
    46     { XK_F1, SDLK_F1 },
    47     { XK_F2, SDLK_F2 },
    48     { XK_F3, SDLK_F3 },
    49     { XK_F4, SDLK_F4 },
    50     { XK_F5, SDLK_F5 },
    51     { XK_F6, SDLK_F6 },
    52     { XK_F7, SDLK_F7 },
    53     { XK_F8, SDLK_F8 },
    54     { XK_F9, SDLK_F9 },
    55     { XK_F10, SDLK_F10 },
    56     { XK_F11, SDLK_F11 },
    57     { XK_F12, SDLK_F12 },
    58     { XK_Print, SDLK_PRINTSCREEN },
    59     { XK_Scroll_Lock, SDLK_SCROLLLOCK },
    60     { XK_Pause, SDLK_PAUSE },
    61     { XK_Insert, SDLK_INSERT },
    62     { XK_Home, SDLK_HOME },
    63     { XK_Prior, SDLK_PAGEUP },
    64     { XK_Delete, SDLK_DELETE },
    65     { XK_End, SDLK_END },
    66     { XK_Next, SDLK_PAGEDOWN },
    67     { XK_Right, SDLK_RIGHT },
    68     { XK_Left, SDLK_LEFT },
    69     { XK_Down, SDLK_DOWN },
    70     { XK_Up, SDLK_UP },
    71     { XK_Num_Lock, SDLK_NUMLOCKCLEAR },
    72     { XK_KP_Divide, SDLK_KP_DIVIDE },
    73     { XK_KP_Multiply, SDLK_KP_MULTIPLY },
    74     { XK_KP_Subtract, SDLK_KP_MINUS },
    75     { XK_KP_Add, SDLK_KP_PLUS },
    76     { XK_KP_Enter, SDLK_KP_ENTER },
    77     { XK_KP_Delete, SDLK_KP_PERIOD },
    78     { XK_KP_End, SDLK_KP_1 },
    79     { XK_KP_Down, SDLK_KP_2 },
    80     { XK_KP_Next, SDLK_KP_3 },
    81     { XK_KP_Left, SDLK_KP_4 },
    82     { XK_KP_Begin, SDLK_KP_5 },
    83     { XK_KP_Right, SDLK_KP_6 },
    84     { XK_KP_Home, SDLK_KP_7 },
    85     { XK_KP_Up, SDLK_KP_8 },
    86     { XK_KP_Prior, SDLK_KP_9 },
    87     { XK_KP_Insert, SDLK_KP_0 },
    88     { XK_KP_Decimal, SDLK_KP_PERIOD },
    89     { XK_KP_1, SDLK_KP_1 },
    90     { XK_KP_2, SDLK_KP_2 },
    91     { XK_KP_3, SDLK_KP_3 },
    92     { XK_KP_4, SDLK_KP_4 },
    93     { XK_KP_5, SDLK_KP_5 },
    94     { XK_KP_6, SDLK_KP_6 },
    95     { XK_KP_7, SDLK_KP_7 },
    96     { XK_KP_8, SDLK_KP_8 },
    97     { XK_KP_9, SDLK_KP_9 },
    98     { XK_KP_0, SDLK_KP_0 },
    99     { XK_KP_Decimal, SDLK_KP_PERIOD },
   100     { XK_Hyper_R, SDLK_APPLICATION },
   101     { XK_KP_Equal, SDLK_KP_EQUALS },
   102     { XK_F13, SDLK_F13 },
   103     { XK_F14, SDLK_F14 },
   104     { XK_F15, SDLK_F15 },
   105     { XK_F16, SDLK_F16 },
   106     { XK_F17, SDLK_F17 },
   107     { XK_F18, SDLK_F18 },
   108     { XK_F19, SDLK_F19 },
   109     { XK_F20, SDLK_F20 },
   110     { XK_F21, SDLK_F21 },
   111     { XK_F22, SDLK_F22 },
   112     { XK_F23, SDLK_F23 },
   113     { XK_F24, SDLK_F24 },
   114     { XK_Execute, SDLK_EXECUTE },
   115     { XK_Help, SDLK_HELP },
   116     { XK_Menu, SDLK_MENU },
   117     { XK_Select, SDLK_SELECT },
   118     { XK_Cancel, SDLK_STOP },
   119     { XK_Redo, SDLK_AGAIN },
   120     { XK_Undo, SDLK_UNDO },
   121     { XK_Find, SDLK_FIND },
   122     { XK_KP_Separator, SDLK_KP_COMMA },
   123     { XK_Sys_Req, SDLK_SYSREQ },
   124     { XK_Control_L, SDLK_LCTRL },
   125     { XK_Shift_L, SDLK_LSHIFT },
   126     { XK_Alt_L, SDLK_LALT },
   127     { XK_Meta_L, SDLK_LGUI },
   128     { XK_Super_L, SDLK_LGUI },
   129     { XK_Control_R, SDLK_RCTRL },
   130     { XK_Shift_R, SDLK_RSHIFT },
   131     { XK_Alt_R, SDLK_RALT },
   132     { XK_Meta_R, SDLK_RGUI },
   133     { XK_Super_R, SDLK_RGUI },
   134     { XK_Mode_switch, SDLK_MODE },
   135 };
   136 
   137 static const struct
   138 {
   139     const SDL_Scancode const *table;
   140     int table_size;
   141 } scancode_set[] = {
   142     { darwin_scancode_table, SDL_arraysize(darwin_scancode_table) },
   143     { xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table) },
   144     { xfree86_scancode_table2, SDL_arraysize(xfree86_scancode_table2) },
   145 };
   146 /* *INDENT-OFF* */
   147 
   148 static SDL_Keycode
   149 X11_KeyCodeToSDLKey(Display *display, KeyCode keycode)
   150 {
   151     KeySym keysym;
   152     unsigned int ucs4;
   153     int i;
   154 
   155     keysym = XKeycodeToKeysym(display, keycode, 0);
   156     if (keysym == NoSymbol) {
   157         return SDLK_UNKNOWN;
   158     }
   159 
   160     ucs4 = X11_KeySymToUcs4(keysym);
   161     if (ucs4) {
   162         return (SDL_Keycode) ucs4;
   163     }
   164 
   165     for (i = 0; i < SDL_arraysize(KeySymToSDLKey); ++i) {
   166         if (keysym == KeySymToSDLKey[i].keysym) {
   167             return KeySymToSDLKey[i].sdlkey;
   168         }
   169     }
   170     return SDLK_UNKNOWN;
   171 }
   172 
   173 int
   174 X11_InitKeyboard(_THIS)
   175 {
   176     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   177     int i, j;
   178     int min_keycode, max_keycode;
   179     struct {
   180         SDL_Scancode scancode;
   181         KeySym keysym;
   182         int value;
   183     } fingerprint[] = {
   184         { SDL_SCANCODE_HOME, XK_Home, 0 },
   185         { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
   186         { SDL_SCANCODE_PAGEDOWN, XK_Next, 0 },
   187     };
   188     SDL_bool fingerprint_detected;
   189 
   190     XAutoRepeatOn(data->display);
   191 
   192     /* Try to determine which scancodes are being used based on fingerprint */
   193     fingerprint_detected = SDL_FALSE;
   194     XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
   195     for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
   196         fingerprint[i].value =
   197             XKeysymToKeycode(data->display, fingerprint[i].keysym) -
   198             min_keycode;
   199     }
   200     for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
   201         /* Make sure the scancode set isn't too big */
   202         if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
   203             continue;
   204         }
   205         for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
   206             if (fingerprint[j].value < 0
   207                 || fingerprint[j].value >= scancode_set[i].table_size) {
   208                 break;
   209             }
   210             if (scancode_set[i].table[fingerprint[j].value] !=
   211                 fingerprint[j].scancode) {
   212                 break;
   213             }
   214         }
   215         if (j == SDL_arraysize(fingerprint)) {
   216 #ifdef DEBUG_KEYBOARD
   217             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);
   218 #endif
   219             SDL_memcpy(&data->key_layout[min_keycode], scancode_set[i].table,
   220                        sizeof(SDL_Scancode) * scancode_set[i].table_size);
   221             fingerprint_detected = SDL_TRUE;
   222             break;
   223         }
   224     }
   225 
   226     if (!fingerprint_detected) {
   227         SDL_Keycode keymap[SDL_NUM_SCANCODES];
   228 
   229         printf
   230             ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
   231 
   232         /* Determine key_layout - only works on US QWERTY layout */
   233         SDL_GetDefaultKeymap(keymap);
   234         for (i = min_keycode; i <= max_keycode; ++i) {
   235             KeySym sym;
   236             sym = XKeycodeToKeysym(data->display, i, 0);
   237             if (sym != NoSymbol) {
   238                 SDL_Keycode key;
   239                 printf("code = %d, sym = 0x%X (%s) ", i - min_keycode,
   240                        (unsigned int) sym, XKeysymToString(sym));
   241                 key = X11_KeyCodeToSDLKey(data->display, i);
   242                 for (j = 0; j < SDL_arraysize(keymap); ++j) {
   243                     if (keymap[j] == key) {
   244                         data->key_layout[i] = (SDL_Scancode) j;
   245                         break;
   246                     }
   247                 }
   248                 if (j == SDL_arraysize(keymap)) {
   249                     printf("scancode not found\n");
   250                 } else {
   251                     printf("scancode = %d (%s)\n", j, SDL_GetScancodeName(j));
   252                 }
   253             }
   254         }
   255     }
   256 
   257     X11_UpdateKeymap(_this);
   258 
   259     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
   260 
   261     return 0;
   262 }
   263 
   264 void
   265 X11_UpdateKeymap(_THIS)
   266 {
   267     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   268     int i;
   269     SDL_Scancode scancode;
   270     SDL_Keycode keymap[SDL_NUM_SCANCODES];
   271 
   272     SDL_zero(keymap);
   273 
   274     for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
   275 
   276         /* Make sure this is a valid scancode */
   277         scancode = data->key_layout[i];
   278         if (scancode == SDL_SCANCODE_UNKNOWN) {
   279             continue;
   280         }
   281 
   282         keymap[scancode] = X11_KeyCodeToSDLKey(data->display, (KeyCode)i);
   283     }
   284     SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES);
   285 }
   286 
   287 void
   288 X11_QuitKeyboard(_THIS)
   289 {
   290 }
   291 
   292 #endif /* SDL_VIDEO_DRIVER_X11 */
   293 
   294 /* vi: set ts=4 sw=4 expandtab: */