src/video/x11/SDL_x11keyboard.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 07 Feb 2008 15:31:09 +0000
changeset 2305 fbe8ff44c519
parent 2299 a7cbc25071b6
child 2306 1a8bab15a45d
permissions -rw-r--r--
First pass of new SDL scancode concept for X11.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 #include "SDL_x11video.h"
    25 
    26 #include "../../events/SDL_keyboard_c.h"
    27 #include "../../events/scancodes_darwin.h"
    28 #include "../../events/scancodes_xfree86.h"
    29 
    30 #include <X11/keysym.h>
    31 
    32 #include "imKStoUCS.h"
    33 
    34 static KeySym XKeySymTable[SDL_NUM_SCANCODES] = {
    35     0, 0, 0, 0,
    36     XK_a,
    37     XK_b,
    38     XK_c,
    39     XK_d,
    40     XK_e,
    41     XK_f,
    42     XK_g,
    43     XK_h,
    44     XK_i,
    45     XK_j,
    46     XK_k,
    47     XK_l,
    48     XK_m,
    49     XK_n,
    50     XK_o,
    51     XK_p,
    52     XK_q,
    53     XK_r,
    54     XK_s,
    55     XK_t,
    56     XK_u,
    57     XK_v,
    58     XK_w,
    59     XK_x,
    60     XK_y,
    61     XK_z,
    62     XK_1,
    63     XK_2,
    64     XK_3,
    65     XK_4,
    66     XK_5,
    67     XK_6,
    68     XK_7,
    69     XK_8,
    70     XK_9,
    71     XK_0,
    72     XK_Return,
    73     XK_Escape,
    74     XK_BackSpace,
    75     XK_Tab,
    76     XK_space,
    77     XK_minus,
    78     XK_equal,
    79     XK_bracketleft,
    80     XK_bracketright,
    81     XK_backslash,
    82     0,                          /* SDL_SCANCODE_NONUSHASH ? */
    83     XK_semicolon,
    84     XK_apostrophe,
    85     XK_grave,
    86     XK_comma,
    87     XK_period,
    88     XK_slash,
    89     XK_Caps_Lock,
    90     XK_F1,
    91     XK_F2,
    92     XK_F3,
    93     XK_F4,
    94     XK_F5,
    95     XK_F6,
    96     XK_F7,
    97     XK_F8,
    98     XK_F9,
    99     XK_F10,
   100     XK_F11,
   101     XK_F12,
   102     XK_Print,
   103     XK_Scroll_Lock,
   104     XK_Pause,
   105     XK_Insert,
   106     XK_Home,
   107     XK_Prior,
   108     XK_Delete,
   109     XK_End,
   110     XK_Next,
   111     XK_Right,
   112     XK_Left,
   113     XK_Down,
   114     XK_Up,
   115     XK_Num_Lock,
   116     XK_KP_Divide,
   117     XK_KP_Multiply,
   118     XK_KP_Subtract,
   119     XK_KP_Add,
   120     XK_KP_Enter,
   121     XK_KP_1,
   122     XK_KP_2,
   123     XK_KP_3,
   124     XK_KP_4,
   125     XK_KP_5,
   126     XK_KP_6,
   127     XK_KP_7,
   128     XK_KP_8,
   129     XK_KP_9,
   130     XK_KP_0,
   131     XK_KP_Decimal,
   132     0,                          /* SDL_SCANCODE_NONUSBACKSLASH ? */
   133     XK_Hyper_R,
   134     0,                          /* SDL_SCANCODE_POWER ? */
   135     XK_KP_Equal,
   136     XK_F13,
   137     XK_F14,
   138     XK_F15,
   139     XK_F16,
   140     XK_F17,
   141     XK_F18,
   142     XK_F19,
   143     XK_F20,
   144     XK_F21,
   145     XK_F22,
   146     XK_F23,
   147     XK_F24,
   148     XK_Execute,
   149     XK_Help,
   150     XK_Menu,
   151     XK_Select,
   152     XK_Cancel,
   153     XK_Redo,
   154     XK_Undo,
   155     0,                          /* SDL_SCANCODE_CUT ? */
   156     0,                          /* SDL_SCANCODE_COPY ? */
   157     0,                          /* SDL_SCANCODE_PASTE ? */
   158     XK_Find,
   159     0,                          /* SDL_SCANCODE_MUTE ? */
   160     0,                          /* SDL_SCANCODE_VOLUMEUP ? */
   161     0,                          /* SDL_SCANCODE_VOLUMEDOWN ? */
   162     0, 0, 0,
   163     XK_KP_Separator,
   164     0,                          /* SDL_SCANCODE_KP_EQUALSAS400 ? */
   165     0,                          /* SDL_SCANCODE_INTERNATIONAL1 ? */
   166     0,                          /* SDL_SCANCODE_INTERNATIONAL2 ? */
   167     0,                          /* SDL_SCANCODE_INTERNATIONAL3 ? */
   168     0,                          /* SDL_SCANCODE_INTERNATIONAL4 ? */
   169     0,                          /* SDL_SCANCODE_INTERNATIONAL5 ? */
   170     0,                          /* SDL_SCANCODE_INTERNATIONAL6 ? */
   171     0,                          /* SDL_SCANCODE_INTERNATIONAL7 ? */
   172     0,                          /* SDL_SCANCODE_INTERNATIONAL8 ? */
   173     0,                          /* SDL_SCANCODE_INTERNATIONAL9 ? */
   174     0,                          /* SDL_SCANCODE_LANG1 ? */
   175     0,                          /* SDL_SCANCODE_LANG2 ? */
   176     0,                          /* SDL_SCANCODE_LANG3 ? */
   177     0,                          /* SDL_SCANCODE_LANG4 ? */
   178     0,                          /* SDL_SCANCODE_LANG5 ? */
   179     0,                          /* SDL_SCANCODE_LANG6 ? */
   180     0,                          /* SDL_SCANCODE_LANG7 ? */
   181     0,                          /* SDL_SCANCODE_LANG8 ? */
   182     0,                          /* SDL_SCANCODE_LANG9 ? */
   183     0,                          /* SDL_SCANCODE_ALTERASE ? */
   184     XK_Sys_Req,
   185     0,                          /* SDL_SCANCODE_CANCEL ? - XK_Cancel was used above... */
   186     0,                          /* SDL_SCANCODE_CLEAR ? */
   187     0,                          /* SDL_SCANCODE_PRIOR ? - XK_Prior was used above... */
   188     0,                          /* SDL_SCANCODE_RETURN2 ? */
   189     0,                          /* SDL_SCANCODE_SEPARATOR ? */
   190     0,                          /* SDL_SCANCODE_OUT ? */
   191     0,                          /* SDL_SCANCODE_OPER ? */
   192     0,                          /* SDL_SCANCODE_CLEARAGAIN ? */
   193     0,                          /* SDL_SCANCODE_CRSEL ? */
   194     0,                          /* SDL_SCANCODE_EXSEL ? */
   195     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   196     0,                          /* SDL_SCANCODE_KP_00 ? */
   197     0,                          /* SDL_SCANCODE_KP_000 ? */
   198     0,                          /* SDL_SCANCODE_THOUSANDSSEPARATOR ? */
   199     0,                          /* SDL_SCANCODE_DECIMALSEPARATOR ? */
   200     0,                          /* SDL_SCANCODE_CURRENCYUNIT ? */
   201     0,                          /* SDL_SCANCODE_CURRENCYSUBUNIT ? */
   202     0,                          /* SDL_SCANCODE_KP_LEFTPAREN ? */
   203     0,                          /* SDL_SCANCODE_KP_RIGHTPAREN ? */
   204     0,                          /* SDL_SCANCODE_KP_LEFTBRACE ? */
   205     0,                          /* SDL_SCANCODE_KP_RIGHTBRACE ? */
   206     0,                          /* SDL_SCANCODE_KP_TAB ? */
   207     0,                          /* SDL_SCANCODE_KP_BACKSPACE ? */
   208     0,                          /* SDL_SCANCODE_KP_A ? */
   209     0,                          /* SDL_SCANCODE_KP_B ? */
   210     0,                          /* SDL_SCANCODE_KP_C ? */
   211     0,                          /* SDL_SCANCODE_KP_D ? */
   212     0,                          /* SDL_SCANCODE_KP_E ? */
   213     0,                          /* SDL_SCANCODE_KP_F ? */
   214     0,                          /* SDL_SCANCODE_KP_XOR ? */
   215     0,                          /* SDL_SCANCODE_KP_POWER ? */
   216     0,                          /* SDL_SCANCODE_KP_PERCENT ? */
   217     0,                          /* SDL_SCANCODE_KP_LESS ? */
   218     0,                          /* SDL_SCANCODE_KP_GREATER ? */
   219     0,                          /* SDL_SCANCODE_KP_AMPERSAND ? */
   220     0,                          /* SDL_SCANCODE_KP_DBLAMPERSAND ? */
   221     0,                          /* SDL_SCANCODE_KP_VERTICALBAR ? */
   222     0,                          /* SDL_SCANCODE_KP_DBLVERTICALBAR ? */
   223     0,                          /* SDL_SCANCODE_KP_COLON ? */
   224     0,                          /* SDL_SCANCODE_KP_HASH ? */
   225     0,                          /* SDL_SCANCODE_KP_SPACE ? */
   226     0,                          /* SDL_SCANCODE_KP_AT ? */
   227     0,                          /* SDL_SCANCODE_KP_EXCLAM ? */
   228     0,                          /* SDL_SCANCODE_KP_MEMSTORE ? */
   229     0,                          /* SDL_SCANCODE_KP_MEMRECALL ? */
   230     0,                          /* SDL_SCANCODE_KP_MEMCLEAR ? */
   231     0,                          /* SDL_SCANCODE_KP_MEMADD ? */
   232     0,                          /* SDL_SCANCODE_KP_MEMSUBTRACT ? */
   233     0,                          /* SDL_SCANCODE_KP_MEMMULTIPLY ? */
   234     0,                          /* SDL_SCANCODE_KP_MEMDIVIDE ? */
   235     0,                          /* SDL_SCANCODE_KP_PLUSMINUS ? */
   236     0,                          /* SDL_SCANCODE_KP_CLEAR ? */
   237     0,                          /* SDL_SCANCODE_KP_CLEARENTRY ? */
   238     0,                          /* SDL_SCANCODE_KP_BINARY ? */
   239     0,                          /* SDL_SCANCODE_KP_OCTAL ? */
   240     0,                          /* SDL_SCANCODE_KP_DECIMAL ? */
   241     0,                          /* SDL_SCANCODE_KP_HEXADECIMAL ? */
   242     0, 0,
   243     XK_Control_L,
   244     XK_Shift_L,
   245     XK_Alt_L,
   246     XK_Meta_L,
   247     XK_Control_R,
   248     XK_Shift_R,
   249     XK_Alt_R,
   250     XK_Meta_R,
   251     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   252     XK_Mode_switch /*XK_ISO_Level3_Shift */ ,
   253     0,                          /* SDL_SCANCODE_AUDIONEXT ? */
   254     0,                          /* SDL_SCANCODE_AUDIOPREV ? */
   255     0,                          /* SDL_SCANCODE_AUDIOSTOP ? */
   256     0,                          /* SDL_SCANCODE_AUDIOPLAY ? */
   257     0,                          /* SDL_SCANCODE_AUDIOMUTE ? */
   258     0,                          /* SDL_SCANCODE_MEDIASELECT ? */
   259     0,                          /* SDL_SCANCODE_WWW ? */
   260     0,                          /* SDL_SCANCODE_MAIL ? */
   261     0,                          /* SDL_SCANCODE_CALCULATOR ? */
   262     0,                          /* SDL_SCANCODE_COMPUTER ? */
   263     0,                          /* SDL_SCANCODE_AC_SEARCH ? */
   264     0,                          /* SDL_SCANCODE_AC_HOME ? */
   265     0,                          /* SDL_SCANCODE_AC_BACK ? */
   266     0,                          /* SDL_SCANCODE_AC_FORWARD ? */
   267     0,                          /* SDL_SCANCODE_AC_STOP ? */
   268     0,                          /* SDL_SCANCODE_AC_REFRESH ? */
   269     0,                          /* SDL_SCANCODE_AC_BOOKMARKS ? */
   270     0,                          /* SDL_SCANCODE_BRIGHTNESSDOWN ? */
   271     0,                          /* SDL_SCANCODE_BRIGHTNESSUP ? */
   272     0,                          /* SDL_SCANCODE_DISPLAYSWITCH ? */
   273     0,                          /* SDL_SCANCODE_KBDILLUMTOGGLE ? */
   274     0,                          /* SDL_SCANCODE_KBDILLUMDOWN ? */
   275     0,                          /* SDL_SCANCODE_KBDILLUMUP ? */
   276     0,                          /* SDL_SCANCODE_EJECT ? */
   277     0,                          /* SDL_SCANCODE_SLEEP ? */
   278 };
   279 
   280 static struct
   281 {
   282     SDL_scancode *table;
   283     int table_size;
   284 } scancode_set[] = {
   285     {
   286     darwin_scancode_table, SDL_arraysize(darwin_scancode_table)}, {
   287 xfree86_scancode_table, SDL_arraysize(xfree86_scancode_table)},};
   288 
   289 int
   290 X11_InitKeyboard(_THIS)
   291 {
   292     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   293     SDL_Keyboard keyboard;
   294     int i, j;
   295     int min_keycode, max_keycode;
   296     SDL_scancode fingerprint_scancodes[] = {
   297         SDL_SCANCODE_HOME,
   298         SDL_SCANCODE_PAGEUP,
   299         SDL_SCANCODE_PAGEDOWN
   300     };
   301     int fingerprint[3];
   302     SDL_bool fingerprint_detected;
   303 
   304     XAutoRepeatOn(data->display);
   305 
   306     /* Try to determine which scancodes are being used based on fingerprint */
   307     fingerprint_detected = SDL_FALSE;
   308     XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
   309     for (i = 0; i < SDL_arraysize(fingerprint_scancodes); ++i) {
   310         fingerprint[i] =
   311             XKeysymToKeycode(data->display,
   312                              XKeySymTable[fingerprint_scancodes[i]]) -
   313             min_keycode;
   314     }
   315     for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
   316         /* Make sure the scancode set isn't too big */
   317         if ((max_keycode - min_keycode + 1) <= scancode_set[i].table_size) {
   318             continue;
   319         }
   320         for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
   321             if (fingerprint[j] < 0
   322                 || fingerprint[j] >= scancode_set[i].table_size) {
   323                 break;
   324             }
   325             if (scancode_set[i].table[fingerprint[j]] !=
   326                 fingerprint_scancodes[j]) {
   327                 break;
   328             }
   329         }
   330         if (j == SDL_arraysize(fingerprint)) {
   331             printf("Using scancode set %d\n", i);
   332             SDL_memcpy(&data->key_layout[min_keycode], scancode_set[i].table,
   333                        sizeof(SDL_scancode) * scancode_set[i].table_size);
   334             fingerprint_detected = SDL_TRUE;
   335             break;
   336         }
   337     }
   338 
   339     if (!fingerprint_detected) {
   340         printf
   341             ("Keyboard layout unknown, please send the following to the SDL mailing list (sdl@libsdl.org):\n");
   342 
   343         /* Determine key_layout - only works on US QWERTY layout */
   344         for (i = min_keycode; i <= max_keycode; ++i) {
   345             KeySym sym;
   346             sym = XKeycodeToKeysym(data->display, i, 0);
   347             if (sym) {
   348                 printf("code = %d, sym = 0x%X (%s) ", i - min_keycode, sym,
   349                        XKeysymToString(sym));
   350                 for (j = 0; j < SDL_arraysize(XKeySymTable); ++j) {
   351                     if (XKeySymTable[j] == sym) {
   352                         data->key_layout[i] = (SDL_scancode) j;
   353                         break;
   354                     }
   355                 }
   356                 if (j == SDL_arraysize(XKeySymTable)) {
   357                     printf("scancode not found\n");
   358                 } else {
   359                     printf("scancode = %d (%s)\n", j, SDL_GetScancodeName(j));
   360                 }
   361             }
   362         }
   363     }
   364 
   365     SDL_zero(keyboard);
   366     data->keyboard = SDL_AddKeyboard(&keyboard, -1);
   367     X11_UpdateKeymap(this);
   368 
   369     SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
   370 
   371     return 0;
   372 }
   373 
   374 void
   375 X11_UpdateKeymap(_THIS)
   376 {
   377     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   378     int i;
   379     SDL_scancode scancode;
   380     SDLKey keymap[SDL_NUM_SCANCODES];
   381 
   382     SDL_GetDefaultKeymap(keymap);
   383 
   384     for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
   385 
   386         /* Make sure this scancode is a valid character scancode */
   387         scancode = data->key_layout[i];
   388         if (scancode == SDL_SCANCODE_UNKNOWN ||
   389             (keymap[scancode] & SDLK_SCANCODE_MASK)) {
   390             continue;
   391         }
   392 
   393         keymap[scancode] =
   394             (SDLKey) X11_KeySymToUcs4(XKeycodeToKeysym(data->display, i, 0));
   395     }
   396     SDL_SetKeymap(data->keyboard, 0, keymap, SDL_NUM_SCANCODES);
   397 }
   398 
   399 void
   400 X11_QuitKeyboard(_THIS)
   401 {
   402     SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
   403 
   404     SDL_DelKeyboard(data->keyboard);
   405 }
   406 
   407 /* vi: set ts=4 sw=4 expandtab: */