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