src/events/SDL_keyboard.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 28 May 2015 12:48:20 -0700
changeset 9678 9e8323b058d6
parent 9619 b94b6d0bff0f
child 9973 4d8a561cf978
permissions -rw-r--r--
Fixed bug 2096 - Mapping from scancode to keycode doesn't work for remapped modifier keys

Jacob Lee

If a user has a non-standard keyboard mapping -- say, their caps lock key has been mapped to Ctrl -- then SDL_GetModState() is no longer accurate: it only considers the unmapped keys. This is a regression from SDL 1.2.

I think there are two parts to this bug: first, GetModState should use keycodes, rather than scancodes, which is easy enough.

Unfortunately, on my system, SDL considers Caps Lock, even when mapped as Control, to be both SDL_SCANCODE_CAPSLOCK and SDLK_CAPSLOCK. The output from checkkeys for it is:

INFO: Key pressed : scancode 57 = CapsLock, keycode 0x40000039 = CapsLock modifiers: CAPS

Whereas the output for xev is:

KeyPress event, serial 41, synthetic NO, window 0x4a00001,
root 0x9a, subw 0x0, time 40218333, (144,177), root:(1458,222),
state 0x10, keycode 66 (keysym 0xffe3, Control_L), same_screen YES,
XKeysymToKeycode returns keycode: 37
XLookupString gives 0 bytes:
XmbLookupString gives 0 bytes:
XFilterEvent returns: False

I think the problem is that X11_UpdateKeymap in SDL_x11keyboard.c only builds a mapping for keycodes associated with a Unicode character (anything where X11_KeyCodeToUcs returns a value). In the case of caps lock, SDL scancode 57 becomes x11 keycode 66, which becomes x11 keysym 65507(Control_L), which does not have a unicode value.

To fix this, I suspect that SDL needs a mapping of the rest of the x11 keysyms to their corresponding SDL key codes.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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 /* General keyboard handling code for SDL */
    24 
    25 #include "SDL_timer.h"
    26 #include "SDL_events.h"
    27 #include "SDL_events_c.h"
    28 #include "SDL_assert.h"
    29 #include "../video/SDL_sysvideo.h"
    30 
    31 
    32 /* #define DEBUG_KEYBOARD */
    33 
    34 /* Global keyboard information */
    35 
    36 typedef struct SDL_Keyboard SDL_Keyboard;
    37 
    38 struct SDL_Keyboard
    39 {
    40     /* Data common to all keyboards */
    41     SDL_Window *focus;
    42     Uint16 modstate;
    43     Uint8 keystate[SDL_NUM_SCANCODES];
    44     SDL_Keycode keymap[SDL_NUM_SCANCODES];
    45 };
    46 
    47 static SDL_Keyboard SDL_keyboard;
    48 
    49 static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
    50     0, 0, 0, 0,
    51     'a',
    52     'b',
    53     'c',
    54     'd',
    55     'e',
    56     'f',
    57     'g',
    58     'h',
    59     'i',
    60     'j',
    61     'k',
    62     'l',
    63     'm',
    64     'n',
    65     'o',
    66     'p',
    67     'q',
    68     'r',
    69     's',
    70     't',
    71     'u',
    72     'v',
    73     'w',
    74     'x',
    75     'y',
    76     'z',
    77     '1',
    78     '2',
    79     '3',
    80     '4',
    81     '5',
    82     '6',
    83     '7',
    84     '8',
    85     '9',
    86     '0',
    87     SDLK_RETURN,
    88     SDLK_ESCAPE,
    89     SDLK_BACKSPACE,
    90     SDLK_TAB,
    91     SDLK_SPACE,
    92     '-',
    93     '=',
    94     '[',
    95     ']',
    96     '\\',
    97     '#',
    98     ';',
    99     '\'',
   100     '`',
   101     ',',
   102     '.',
   103     '/',
   104     SDLK_CAPSLOCK,
   105     SDLK_F1,
   106     SDLK_F2,
   107     SDLK_F3,
   108     SDLK_F4,
   109     SDLK_F5,
   110     SDLK_F6,
   111     SDLK_F7,
   112     SDLK_F8,
   113     SDLK_F9,
   114     SDLK_F10,
   115     SDLK_F11,
   116     SDLK_F12,
   117     SDLK_PRINTSCREEN,
   118     SDLK_SCROLLLOCK,
   119     SDLK_PAUSE,
   120     SDLK_INSERT,
   121     SDLK_HOME,
   122     SDLK_PAGEUP,
   123     SDLK_DELETE,
   124     SDLK_END,
   125     SDLK_PAGEDOWN,
   126     SDLK_RIGHT,
   127     SDLK_LEFT,
   128     SDLK_DOWN,
   129     SDLK_UP,
   130     SDLK_NUMLOCKCLEAR,
   131     SDLK_KP_DIVIDE,
   132     SDLK_KP_MULTIPLY,
   133     SDLK_KP_MINUS,
   134     SDLK_KP_PLUS,
   135     SDLK_KP_ENTER,
   136     SDLK_KP_1,
   137     SDLK_KP_2,
   138     SDLK_KP_3,
   139     SDLK_KP_4,
   140     SDLK_KP_5,
   141     SDLK_KP_6,
   142     SDLK_KP_7,
   143     SDLK_KP_8,
   144     SDLK_KP_9,
   145     SDLK_KP_0,
   146     SDLK_KP_PERIOD,
   147     0,
   148     SDLK_APPLICATION,
   149     SDLK_POWER,
   150     SDLK_KP_EQUALS,
   151     SDLK_F13,
   152     SDLK_F14,
   153     SDLK_F15,
   154     SDLK_F16,
   155     SDLK_F17,
   156     SDLK_F18,
   157     SDLK_F19,
   158     SDLK_F20,
   159     SDLK_F21,
   160     SDLK_F22,
   161     SDLK_F23,
   162     SDLK_F24,
   163     SDLK_EXECUTE,
   164     SDLK_HELP,
   165     SDLK_MENU,
   166     SDLK_SELECT,
   167     SDLK_STOP,
   168     SDLK_AGAIN,
   169     SDLK_UNDO,
   170     SDLK_CUT,
   171     SDLK_COPY,
   172     SDLK_PASTE,
   173     SDLK_FIND,
   174     SDLK_MUTE,
   175     SDLK_VOLUMEUP,
   176     SDLK_VOLUMEDOWN,
   177     0, 0, 0,
   178     SDLK_KP_COMMA,
   179     SDLK_KP_EQUALSAS400,
   180     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   181     SDLK_ALTERASE,
   182     SDLK_SYSREQ,
   183     SDLK_CANCEL,
   184     SDLK_CLEAR,
   185     SDLK_PRIOR,
   186     SDLK_RETURN2,
   187     SDLK_SEPARATOR,
   188     SDLK_OUT,
   189     SDLK_OPER,
   190     SDLK_CLEARAGAIN,
   191     SDLK_CRSEL,
   192     SDLK_EXSEL,
   193     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   194     SDLK_KP_00,
   195     SDLK_KP_000,
   196     SDLK_THOUSANDSSEPARATOR,
   197     SDLK_DECIMALSEPARATOR,
   198     SDLK_CURRENCYUNIT,
   199     SDLK_CURRENCYSUBUNIT,
   200     SDLK_KP_LEFTPAREN,
   201     SDLK_KP_RIGHTPAREN,
   202     SDLK_KP_LEFTBRACE,
   203     SDLK_KP_RIGHTBRACE,
   204     SDLK_KP_TAB,
   205     SDLK_KP_BACKSPACE,
   206     SDLK_KP_A,
   207     SDLK_KP_B,
   208     SDLK_KP_C,
   209     SDLK_KP_D,
   210     SDLK_KP_E,
   211     SDLK_KP_F,
   212     SDLK_KP_XOR,
   213     SDLK_KP_POWER,
   214     SDLK_KP_PERCENT,
   215     SDLK_KP_LESS,
   216     SDLK_KP_GREATER,
   217     SDLK_KP_AMPERSAND,
   218     SDLK_KP_DBLAMPERSAND,
   219     SDLK_KP_VERTICALBAR,
   220     SDLK_KP_DBLVERTICALBAR,
   221     SDLK_KP_COLON,
   222     SDLK_KP_HASH,
   223     SDLK_KP_SPACE,
   224     SDLK_KP_AT,
   225     SDLK_KP_EXCLAM,
   226     SDLK_KP_MEMSTORE,
   227     SDLK_KP_MEMRECALL,
   228     SDLK_KP_MEMCLEAR,
   229     SDLK_KP_MEMADD,
   230     SDLK_KP_MEMSUBTRACT,
   231     SDLK_KP_MEMMULTIPLY,
   232     SDLK_KP_MEMDIVIDE,
   233     SDLK_KP_PLUSMINUS,
   234     SDLK_KP_CLEAR,
   235     SDLK_KP_CLEARENTRY,
   236     SDLK_KP_BINARY,
   237     SDLK_KP_OCTAL,
   238     SDLK_KP_DECIMAL,
   239     SDLK_KP_HEXADECIMAL,
   240     0, 0,
   241     SDLK_LCTRL,
   242     SDLK_LSHIFT,
   243     SDLK_LALT,
   244     SDLK_LGUI,
   245     SDLK_RCTRL,
   246     SDLK_RSHIFT,
   247     SDLK_RALT,
   248     SDLK_RGUI,
   249     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,
   250     SDLK_MODE,
   251     SDLK_AUDIONEXT,
   252     SDLK_AUDIOPREV,
   253     SDLK_AUDIOSTOP,
   254     SDLK_AUDIOPLAY,
   255     SDLK_AUDIOMUTE,
   256     SDLK_MEDIASELECT,
   257     SDLK_WWW,
   258     SDLK_MAIL,
   259     SDLK_CALCULATOR,
   260     SDLK_COMPUTER,
   261     SDLK_AC_SEARCH,
   262     SDLK_AC_HOME,
   263     SDLK_AC_BACK,
   264     SDLK_AC_FORWARD,
   265     SDLK_AC_STOP,
   266     SDLK_AC_REFRESH,
   267     SDLK_AC_BOOKMARKS,
   268     SDLK_BRIGHTNESSDOWN,
   269     SDLK_BRIGHTNESSUP,
   270     SDLK_DISPLAYSWITCH,
   271     SDLK_KBDILLUMTOGGLE,
   272     SDLK_KBDILLUMDOWN,
   273     SDLK_KBDILLUMUP,
   274     SDLK_EJECT,
   275     SDLK_SLEEP,
   276 };
   277 
   278 static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
   279     NULL, NULL, NULL, NULL,
   280     "A",
   281     "B",
   282     "C",
   283     "D",
   284     "E",
   285     "F",
   286     "G",
   287     "H",
   288     "I",
   289     "J",
   290     "K",
   291     "L",
   292     "M",
   293     "N",
   294     "O",
   295     "P",
   296     "Q",
   297     "R",
   298     "S",
   299     "T",
   300     "U",
   301     "V",
   302     "W",
   303     "X",
   304     "Y",
   305     "Z",
   306     "1",
   307     "2",
   308     "3",
   309     "4",
   310     "5",
   311     "6",
   312     "7",
   313     "8",
   314     "9",
   315     "0",
   316     "Return",
   317     "Escape",
   318     "Backspace",
   319     "Tab",
   320     "Space",
   321     "-",
   322     "=",
   323     "[",
   324     "]",
   325     "\\",
   326     "#",
   327     ";",
   328     "'",
   329     "`",
   330     ",",
   331     ".",
   332     "/",
   333     "CapsLock",
   334     "F1",
   335     "F2",
   336     "F3",
   337     "F4",
   338     "F5",
   339     "F6",
   340     "F7",
   341     "F8",
   342     "F9",
   343     "F10",
   344     "F11",
   345     "F12",
   346     "PrintScreen",
   347     "ScrollLock",
   348     "Pause",
   349     "Insert",
   350     "Home",
   351     "PageUp",
   352     "Delete",
   353     "End",
   354     "PageDown",
   355     "Right",
   356     "Left",
   357     "Down",
   358     "Up",
   359     "Numlock",
   360     "Keypad /",
   361     "Keypad *",
   362     "Keypad -",
   363     "Keypad +",
   364     "Keypad Enter",
   365     "Keypad 1",
   366     "Keypad 2",
   367     "Keypad 3",
   368     "Keypad 4",
   369     "Keypad 5",
   370     "Keypad 6",
   371     "Keypad 7",
   372     "Keypad 8",
   373     "Keypad 9",
   374     "Keypad 0",
   375     "Keypad .",
   376     NULL,
   377     "Application",
   378     "Power",
   379     "Keypad =",
   380     "F13",
   381     "F14",
   382     "F15",
   383     "F16",
   384     "F17",
   385     "F18",
   386     "F19",
   387     "F20",
   388     "F21",
   389     "F22",
   390     "F23",
   391     "F24",
   392     "Execute",
   393     "Help",
   394     "Menu",
   395     "Select",
   396     "Stop",
   397     "Again",
   398     "Undo",
   399     "Cut",
   400     "Copy",
   401     "Paste",
   402     "Find",
   403     "Mute",
   404     "VolumeUp",
   405     "VolumeDown",
   406     NULL, NULL, NULL,
   407     "Keypad ,",
   408     "Keypad = (AS400)",
   409     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   410     NULL, NULL, NULL, NULL, NULL, NULL,
   411     "AltErase",
   412     "SysReq",
   413     "Cancel",
   414     "Clear",
   415     "Prior",
   416     "Return",
   417     "Separator",
   418     "Out",
   419     "Oper",
   420     "Clear / Again",
   421     "CrSel",
   422     "ExSel",
   423     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   424     "Keypad 00",
   425     "Keypad 000",
   426     "ThousandsSeparator",
   427     "DecimalSeparator",
   428     "CurrencyUnit",
   429     "CurrencySubUnit",
   430     "Keypad (",
   431     "Keypad )",
   432     "Keypad {",
   433     "Keypad }",
   434     "Keypad Tab",
   435     "Keypad Backspace",
   436     "Keypad A",
   437     "Keypad B",
   438     "Keypad C",
   439     "Keypad D",
   440     "Keypad E",
   441     "Keypad F",
   442     "Keypad XOR",
   443     "Keypad ^",
   444     "Keypad %",
   445     "Keypad <",
   446     "Keypad >",
   447     "Keypad &",
   448     "Keypad &&",
   449     "Keypad |",
   450     "Keypad ||",
   451     "Keypad :",
   452     "Keypad #",
   453     "Keypad Space",
   454     "Keypad @",
   455     "Keypad !",
   456     "Keypad MemStore",
   457     "Keypad MemRecall",
   458     "Keypad MemClear",
   459     "Keypad MemAdd",
   460     "Keypad MemSubtract",
   461     "Keypad MemMultiply",
   462     "Keypad MemDivide",
   463     "Keypad +/-",
   464     "Keypad Clear",
   465     "Keypad ClearEntry",
   466     "Keypad Binary",
   467     "Keypad Octal",
   468     "Keypad Decimal",
   469     "Keypad Hexadecimal",
   470     NULL, NULL,
   471     "Left Ctrl",
   472     "Left Shift",
   473     "Left Alt",
   474     "Left GUI",
   475     "Right Ctrl",
   476     "Right Shift",
   477     "Right Alt",
   478     "Right GUI",
   479     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   480     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   481     NULL,
   482     "ModeSwitch",
   483     "AudioNext",
   484     "AudioPrev",
   485     "AudioStop",
   486     "AudioPlay",
   487     "AudioMute",
   488     "MediaSelect",
   489     "WWW",
   490     "Mail",
   491     "Calculator",
   492     "Computer",
   493     "AC Search",
   494     "AC Home",
   495     "AC Back",
   496     "AC Forward",
   497     "AC Stop",
   498     "AC Refresh",
   499     "AC Bookmarks",
   500     "BrightnessDown",
   501     "BrightnessUp",
   502     "DisplaySwitch",
   503     "KBDIllumToggle",
   504     "KBDIllumDown",
   505     "KBDIllumUp",
   506     "Eject",
   507     "Sleep",
   508 };
   509 
   510 /* Taken from SDL_iconv() */
   511 char *
   512 SDL_UCS4ToUTF8(Uint32 ch, char *dst)
   513 {
   514     Uint8 *p = (Uint8 *) dst;
   515     if (ch <= 0x7F) {
   516         *p = (Uint8) ch;
   517         ++dst;
   518     } else if (ch <= 0x7FF) {
   519         p[0] = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
   520         p[1] = 0x80 | (Uint8) (ch & 0x3F);
   521         dst += 2;
   522     } else if (ch <= 0xFFFF) {
   523         p[0] = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
   524         p[1] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   525         p[2] = 0x80 | (Uint8) (ch & 0x3F);
   526         dst += 3;
   527     } else if (ch <= 0x1FFFFF) {
   528         p[0] = 0xF0 | (Uint8) ((ch >> 18) & 0x07);
   529         p[1] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
   530         p[2] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   531         p[3] = 0x80 | (Uint8) (ch & 0x3F);
   532         dst += 4;
   533     } else if (ch <= 0x3FFFFFF) {
   534         p[0] = 0xF8 | (Uint8) ((ch >> 24) & 0x03);
   535         p[1] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
   536         p[2] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
   537         p[3] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   538         p[4] = 0x80 | (Uint8) (ch & 0x3F);
   539         dst += 5;
   540     } else {
   541         p[0] = 0xFC | (Uint8) ((ch >> 30) & 0x01);
   542         p[1] = 0x80 | (Uint8) ((ch >> 24) & 0x3F);
   543         p[2] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
   544         p[3] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
   545         p[4] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   546         p[5] = 0x80 | (Uint8) (ch & 0x3F);
   547         dst += 6;
   548     }
   549     return dst;
   550 }
   551 
   552 /* Public functions */
   553 int
   554 SDL_KeyboardInit(void)
   555 {
   556     SDL_Keyboard *keyboard = &SDL_keyboard;
   557 
   558     /* Set the default keymap */
   559     SDL_memcpy(keyboard->keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
   560     return (0);
   561 }
   562 
   563 void
   564 SDL_ResetKeyboard(void)
   565 {
   566     SDL_Keyboard *keyboard = &SDL_keyboard;
   567     SDL_Scancode scancode;
   568 
   569 #ifdef DEBUG_KEYBOARD
   570     printf("Resetting keyboard\n");
   571 #endif
   572     for (scancode = 0; scancode < SDL_NUM_SCANCODES; ++scancode) {
   573         if (keyboard->keystate[scancode] == SDL_PRESSED) {
   574             SDL_SendKeyboardKey(SDL_RELEASED, scancode);
   575         }
   576     }
   577 }
   578 
   579 void
   580 SDL_GetDefaultKeymap(SDL_Keycode * keymap)
   581 {
   582     SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
   583 }
   584 
   585 void
   586 SDL_SetKeymap(int start, SDL_Keycode * keys, int length)
   587 {
   588     SDL_Keyboard *keyboard = &SDL_keyboard;
   589 
   590     if (start < 0 || start + length > SDL_NUM_SCANCODES) {
   591         return;
   592     }
   593 
   594     SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
   595 }
   596 
   597 void
   598 SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
   599 {
   600     SDL_scancode_names[scancode] = name;
   601 }
   602 
   603 SDL_Window *
   604 SDL_GetKeyboardFocus(void)
   605 {
   606     SDL_Keyboard *keyboard = &SDL_keyboard;
   607 
   608     return keyboard->focus;
   609 }
   610 
   611 void
   612 SDL_SetKeyboardFocus(SDL_Window * window)
   613 {
   614     SDL_Keyboard *keyboard = &SDL_keyboard;
   615 
   616     if (keyboard->focus && !window) {
   617         /* We won't get anymore keyboard messages, so reset keyboard state */
   618         SDL_ResetKeyboard();
   619     }
   620 
   621     /* See if the current window has lost focus */
   622     if (keyboard->focus && keyboard->focus != window) {
   623 
   624         /* new window shouldn't think it has mouse captured. */
   625         SDL_assert(!window || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE));
   626 
   627         /* old window must lose an existing mouse capture. */
   628         if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
   629             SDL_CaptureMouse(SDL_FALSE);  /* drop the capture. */
   630             SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
   631         }
   632 
   633         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST,
   634                             0, 0);
   635 
   636         /* Ensures IME compositions are committed */
   637         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   638             SDL_VideoDevice *video = SDL_GetVideoDevice();
   639             if (video && video->StopTextInput) {
   640                 video->StopTextInput(video);
   641             }
   642         }
   643     }
   644 
   645     keyboard->focus = window;
   646 
   647     if (keyboard->focus) {
   648         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED,
   649                             0, 0);
   650 
   651         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   652             SDL_VideoDevice *video = SDL_GetVideoDevice();
   653             if (video && video->StartTextInput) {
   654                 video->StartTextInput(video);
   655             }
   656         }
   657     }
   658 }
   659 
   660 int
   661 SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
   662 {
   663     SDL_Keyboard *keyboard = &SDL_keyboard;
   664     int posted;
   665     SDL_Keymod modifier;
   666     SDL_Keycode keycode;
   667     Uint16 modstate;
   668     Uint32 type;
   669     Uint8 repeat;
   670 
   671     if (!scancode) {
   672         return 0;
   673     }
   674 #ifdef DEBUG_KEYBOARD
   675     printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
   676            state == SDL_PRESSED ? "pressed" : "released");
   677 #endif
   678 
   679     /* Figure out what type of event this is */
   680     switch (state) {
   681     case SDL_PRESSED:
   682         type = SDL_KEYDOWN;
   683         break;
   684     case SDL_RELEASED:
   685         type = SDL_KEYUP;
   686         break;
   687     default:
   688         /* Invalid state -- bail */
   689         return 0;
   690     }
   691 
   692     /* Drop events that don't change state */
   693     repeat = (state && keyboard->keystate[scancode]);
   694     if (keyboard->keystate[scancode] == state && !repeat) {
   695 #if 0
   696         printf("Keyboard event didn't change state - dropped!\n");
   697 #endif
   698         return 0;
   699     }
   700 
   701     /* Update internal keyboard state */
   702     keyboard->keystate[scancode] = state;
   703 
   704     keycode = keyboard->keymap[scancode];
   705 
   706     /* Update modifiers state if applicable */
   707     switch (keycode) {
   708     case SDLK_LCTRL:
   709         modifier = KMOD_LCTRL;
   710         break;
   711     case SDLK_RCTRL:
   712         modifier = KMOD_RCTRL;
   713         break;
   714     case SDLK_LSHIFT:
   715         modifier = KMOD_LSHIFT;
   716         break;
   717     case SDLK_RSHIFT:
   718         modifier = KMOD_RSHIFT;
   719         break;
   720     case SDLK_LALT:
   721         modifier = KMOD_LALT;
   722         break;
   723     case SDLK_RALT:
   724         modifier = KMOD_RALT;
   725         break;
   726     case SDLK_LGUI:
   727         modifier = KMOD_LGUI;
   728         break;
   729     case SDLK_RGUI:
   730         modifier = KMOD_RGUI;
   731         break;
   732     case SDLK_MODE:
   733         modifier = KMOD_MODE;
   734         break;
   735     default:
   736         modifier = KMOD_NONE;
   737         break;
   738     }
   739     if (SDL_KEYDOWN == type) {
   740         modstate = keyboard->modstate;
   741         switch (keycode) {
   742         case SDLK_NUMLOCKCLEAR:
   743             keyboard->modstate ^= KMOD_NUM;
   744             break;
   745         case SDLK_CAPSLOCK:
   746             keyboard->modstate ^= KMOD_CAPS;
   747             break;
   748         default:
   749             keyboard->modstate |= modifier;
   750             break;
   751         }
   752     } else {
   753         keyboard->modstate &= ~modifier;
   754         modstate = keyboard->modstate;
   755     }
   756 
   757     /* Post the event, if desired */
   758     posted = 0;
   759     if (SDL_GetEventState(type) == SDL_ENABLE) {
   760         SDL_Event event;
   761         event.key.type = type;
   762         event.key.state = state;
   763         event.key.repeat = repeat;
   764         event.key.keysym.scancode = scancode;
   765         event.key.keysym.sym = keycode;
   766         event.key.keysym.mod = modstate;
   767         event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
   768         posted = (SDL_PushEvent(&event) > 0);
   769     }
   770     return (posted);
   771 }
   772 
   773 int
   774 SDL_SendKeyboardText(const char *text)
   775 {
   776     SDL_Keyboard *keyboard = &SDL_keyboard;
   777     int posted;
   778 
   779     /* Don't post text events for unprintable characters */
   780     if ((unsigned char)*text < ' ' || *text == 127) {
   781         return 0;
   782     }
   783 
   784     /* Post the event, if desired */
   785     posted = 0;
   786     if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
   787         SDL_Event event;
   788         event.text.type = SDL_TEXTINPUT;
   789         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
   790         SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
   791         posted = (SDL_PushEvent(&event) > 0);
   792     }
   793     return (posted);
   794 }
   795 
   796 int
   797 SDL_SendEditingText(const char *text, int start, int length)
   798 {
   799     SDL_Keyboard *keyboard = &SDL_keyboard;
   800     int posted;
   801 
   802     /* Post the event, if desired */
   803     posted = 0;
   804     if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
   805         SDL_Event event;
   806         event.edit.type = SDL_TEXTEDITING;
   807         event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
   808         event.edit.start = start;
   809         event.edit.length = length;
   810         SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
   811         posted = (SDL_PushEvent(&event) > 0);
   812     }
   813     return (posted);
   814 }
   815 
   816 void
   817 SDL_KeyboardQuit(void)
   818 {
   819 }
   820 
   821 const Uint8 *
   822 SDL_GetKeyboardState(int *numkeys)
   823 {
   824     SDL_Keyboard *keyboard = &SDL_keyboard;
   825 
   826     if (numkeys != (int *) 0) {
   827         *numkeys = SDL_NUM_SCANCODES;
   828     }
   829     return keyboard->keystate;
   830 }
   831 
   832 SDL_Keymod
   833 SDL_GetModState(void)
   834 {
   835     SDL_Keyboard *keyboard = &SDL_keyboard;
   836 
   837     return keyboard->modstate;
   838 }
   839 
   840 void
   841 SDL_SetModState(SDL_Keymod modstate)
   842 {
   843     SDL_Keyboard *keyboard = &SDL_keyboard;
   844 
   845     keyboard->modstate = modstate;
   846 }
   847 
   848 SDL_Keycode
   849 SDL_GetKeyFromScancode(SDL_Scancode scancode)
   850 {
   851     SDL_Keyboard *keyboard = &SDL_keyboard;
   852 
   853     if (scancode < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
   854           SDL_InvalidParamError("scancode");
   855           return 0;
   856     }
   857 
   858     return keyboard->keymap[scancode];
   859 }
   860 
   861 SDL_Scancode
   862 SDL_GetScancodeFromKey(SDL_Keycode key)
   863 {
   864     SDL_Keyboard *keyboard = &SDL_keyboard;
   865     SDL_Scancode scancode;
   866 
   867     for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
   868          ++scancode) {
   869         if (keyboard->keymap[scancode] == key) {
   870             return scancode;
   871         }
   872     }
   873     return SDL_SCANCODE_UNKNOWN;
   874 }
   875 
   876 const char *
   877 SDL_GetScancodeName(SDL_Scancode scancode)
   878 {
   879     const char *name;
   880     if (scancode < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
   881           SDL_InvalidParamError("scancode");
   882           return "";
   883     }
   884 
   885     name = SDL_scancode_names[scancode];
   886     if (name)
   887         return name;
   888     else
   889         return "";
   890 }
   891 
   892 SDL_Scancode SDL_GetScancodeFromName(const char *name)
   893 {
   894     int i;
   895 
   896     if (!name || !*name) {
   897             SDL_InvalidParamError("name");
   898         return SDL_SCANCODE_UNKNOWN;
   899     }
   900 
   901     for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
   902         if (!SDL_scancode_names[i]) {
   903             continue;
   904         }
   905         if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
   906             return (SDL_Scancode)i;
   907         }
   908     }
   909 
   910     SDL_InvalidParamError("name");
   911     return SDL_SCANCODE_UNKNOWN;
   912 }
   913 
   914 const char *
   915 SDL_GetKeyName(SDL_Keycode key)
   916 {
   917     static char name[8];
   918     char *end;
   919 
   920     if (key & SDLK_SCANCODE_MASK) {
   921         return
   922             SDL_GetScancodeName((SDL_Scancode) (key & ~SDLK_SCANCODE_MASK));
   923     }
   924 
   925     switch (key) {
   926     case SDLK_RETURN:
   927         return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
   928     case SDLK_ESCAPE:
   929         return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
   930     case SDLK_BACKSPACE:
   931         return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
   932     case SDLK_TAB:
   933         return SDL_GetScancodeName(SDL_SCANCODE_TAB);
   934     case SDLK_SPACE:
   935         return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
   936     case SDLK_DELETE:
   937         return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
   938     default:
   939         /* Unaccented letter keys on latin keyboards are normally
   940            labeled in upper case (and probably on others like Greek or
   941            Cyrillic too, so if you happen to know for sure, please
   942            adapt this). */
   943         if (key >= 'a' && key <= 'z') {
   944             key -= 32;
   945         }
   946 
   947         end = SDL_UCS4ToUTF8((Uint32) key, name);
   948         *end = '\0';
   949         return name;
   950     }
   951 }
   952 
   953 SDL_Keycode
   954 SDL_GetKeyFromName(const char *name)
   955 {
   956     SDL_Keycode key;
   957 
   958         /* Check input */
   959         if (name == NULL) return SDLK_UNKNOWN;
   960 
   961     /* If it's a single UTF-8 character, then that's the keycode itself */
   962     key = *(const unsigned char *)name;
   963     if (key >= 0xF0) {
   964         if (SDL_strlen(name) == 4) {
   965             int i = 0;
   966             key  = (Uint16)(name[i]&0x07) << 18;
   967             key |= (Uint16)(name[++i]&0x3F) << 12;
   968             key |= (Uint16)(name[++i]&0x3F) << 6;
   969             key |= (Uint16)(name[++i]&0x3F);
   970             return key;
   971         }
   972         return SDLK_UNKNOWN;
   973     } else if (key >= 0xE0) {
   974         if (SDL_strlen(name) == 3) {
   975             int i = 0;
   976             key  = (Uint16)(name[i]&0x0F) << 12;
   977             key |= (Uint16)(name[++i]&0x3F) << 6;
   978             key |= (Uint16)(name[++i]&0x3F);
   979             return key;
   980         }
   981         return SDLK_UNKNOWN;
   982     } else if (key >= 0xC0) {
   983         if (SDL_strlen(name) == 2) {
   984             int i = 0;
   985             key  = (Uint16)(name[i]&0x1F) << 6;
   986             key |= (Uint16)(name[++i]&0x3F);
   987             return key;
   988         }
   989         return SDLK_UNKNOWN;
   990     } else {
   991         if (SDL_strlen(name) == 1) {
   992             if (key >= 'A' && key <= 'Z') {
   993                 key += 32;
   994             }
   995             return key;
   996         }
   997 
   998         /* Get the scancode for this name, and the associated keycode */
   999         return SDL_default_keymap[SDL_GetScancodeFromName(name)];
  1000     }
  1001 }
  1002 
  1003 /* vi: set ts=4 sw=4 expandtab: */