src/events/SDL_keyboard.c
author Sylvain Becker <sylvain.becker@gmail.com>
Wed, 30 Oct 2019 15:13:55 +0100
changeset 13200 057a3fe53d5a
parent 12503 806492103856
permissions -rw-r--r--
Readability: remove redundant cast to the same type
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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     SDLK_APP1,
   277     SDLK_APP2,
   278     SDLK_AUDIOREWIND,
   279     SDLK_AUDIOFASTFORWARD,
   280 };
   281 
   282 static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
   283     NULL, NULL, NULL, NULL,
   284     "A",
   285     "B",
   286     "C",
   287     "D",
   288     "E",
   289     "F",
   290     "G",
   291     "H",
   292     "I",
   293     "J",
   294     "K",
   295     "L",
   296     "M",
   297     "N",
   298     "O",
   299     "P",
   300     "Q",
   301     "R",
   302     "S",
   303     "T",
   304     "U",
   305     "V",
   306     "W",
   307     "X",
   308     "Y",
   309     "Z",
   310     "1",
   311     "2",
   312     "3",
   313     "4",
   314     "5",
   315     "6",
   316     "7",
   317     "8",
   318     "9",
   319     "0",
   320     "Return",
   321     "Escape",
   322     "Backspace",
   323     "Tab",
   324     "Space",
   325     "-",
   326     "=",
   327     "[",
   328     "]",
   329     "\\",
   330     "#",
   331     ";",
   332     "'",
   333     "`",
   334     ",",
   335     ".",
   336     "/",
   337     "CapsLock",
   338     "F1",
   339     "F2",
   340     "F3",
   341     "F4",
   342     "F5",
   343     "F6",
   344     "F7",
   345     "F8",
   346     "F9",
   347     "F10",
   348     "F11",
   349     "F12",
   350     "PrintScreen",
   351     "ScrollLock",
   352     "Pause",
   353     "Insert",
   354     "Home",
   355     "PageUp",
   356     "Delete",
   357     "End",
   358     "PageDown",
   359     "Right",
   360     "Left",
   361     "Down",
   362     "Up",
   363     "Numlock",
   364     "Keypad /",
   365     "Keypad *",
   366     "Keypad -",
   367     "Keypad +",
   368     "Keypad Enter",
   369     "Keypad 1",
   370     "Keypad 2",
   371     "Keypad 3",
   372     "Keypad 4",
   373     "Keypad 5",
   374     "Keypad 6",
   375     "Keypad 7",
   376     "Keypad 8",
   377     "Keypad 9",
   378     "Keypad 0",
   379     "Keypad .",
   380     NULL,
   381     "Application",
   382     "Power",
   383     "Keypad =",
   384     "F13",
   385     "F14",
   386     "F15",
   387     "F16",
   388     "F17",
   389     "F18",
   390     "F19",
   391     "F20",
   392     "F21",
   393     "F22",
   394     "F23",
   395     "F24",
   396     "Execute",
   397     "Help",
   398     "Menu",
   399     "Select",
   400     "Stop",
   401     "Again",
   402     "Undo",
   403     "Cut",
   404     "Copy",
   405     "Paste",
   406     "Find",
   407     "Mute",
   408     "VolumeUp",
   409     "VolumeDown",
   410     NULL, NULL, NULL,
   411     "Keypad ,",
   412     "Keypad = (AS400)",
   413     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   414     NULL, NULL, NULL, NULL, NULL, NULL,
   415     "AltErase",
   416     "SysReq",
   417     "Cancel",
   418     "Clear",
   419     "Prior",
   420     "Return",
   421     "Separator",
   422     "Out",
   423     "Oper",
   424     "Clear / Again",
   425     "CrSel",
   426     "ExSel",
   427     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   428     "Keypad 00",
   429     "Keypad 000",
   430     "ThousandsSeparator",
   431     "DecimalSeparator",
   432     "CurrencyUnit",
   433     "CurrencySubUnit",
   434     "Keypad (",
   435     "Keypad )",
   436     "Keypad {",
   437     "Keypad }",
   438     "Keypad Tab",
   439     "Keypad Backspace",
   440     "Keypad A",
   441     "Keypad B",
   442     "Keypad C",
   443     "Keypad D",
   444     "Keypad E",
   445     "Keypad F",
   446     "Keypad XOR",
   447     "Keypad ^",
   448     "Keypad %",
   449     "Keypad <",
   450     "Keypad >",
   451     "Keypad &",
   452     "Keypad &&",
   453     "Keypad |",
   454     "Keypad ||",
   455     "Keypad :",
   456     "Keypad #",
   457     "Keypad Space",
   458     "Keypad @",
   459     "Keypad !",
   460     "Keypad MemStore",
   461     "Keypad MemRecall",
   462     "Keypad MemClear",
   463     "Keypad MemAdd",
   464     "Keypad MemSubtract",
   465     "Keypad MemMultiply",
   466     "Keypad MemDivide",
   467     "Keypad +/-",
   468     "Keypad Clear",
   469     "Keypad ClearEntry",
   470     "Keypad Binary",
   471     "Keypad Octal",
   472     "Keypad Decimal",
   473     "Keypad Hexadecimal",
   474     NULL, NULL,
   475     "Left Ctrl",
   476     "Left Shift",
   477     "Left Alt",
   478     "Left GUI",
   479     "Right Ctrl",
   480     "Right Shift",
   481     "Right Alt",
   482     "Right GUI",
   483     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   484     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
   485     NULL,
   486     "ModeSwitch",
   487     "AudioNext",
   488     "AudioPrev",
   489     "AudioStop",
   490     "AudioPlay",
   491     "AudioMute",
   492     "MediaSelect",
   493     "WWW",
   494     "Mail",
   495     "Calculator",
   496     "Computer",
   497     "AC Search",
   498     "AC Home",
   499     "AC Back",
   500     "AC Forward",
   501     "AC Stop",
   502     "AC Refresh",
   503     "AC Bookmarks",
   504     "BrightnessDown",
   505     "BrightnessUp",
   506     "DisplaySwitch",
   507     "KBDIllumToggle",
   508     "KBDIllumDown",
   509     "KBDIllumUp",
   510     "Eject",
   511     "Sleep",
   512     "App1",
   513     "App2",
   514     "AudioRewind",
   515     "AudioFastForward",
   516 };
   517 
   518 /* Taken from SDL_iconv() */
   519 char *
   520 SDL_UCS4ToUTF8(Uint32 ch, char *dst)
   521 {
   522     Uint8 *p = (Uint8 *) dst;
   523     if (ch <= 0x7F) {
   524         *p = (Uint8) ch;
   525         ++dst;
   526     } else if (ch <= 0x7FF) {
   527         p[0] = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
   528         p[1] = 0x80 | (Uint8) (ch & 0x3F);
   529         dst += 2;
   530     } else if (ch <= 0xFFFF) {
   531         p[0] = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
   532         p[1] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   533         p[2] = 0x80 | (Uint8) (ch & 0x3F);
   534         dst += 3;
   535     } else if (ch <= 0x1FFFFF) {
   536         p[0] = 0xF0 | (Uint8) ((ch >> 18) & 0x07);
   537         p[1] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
   538         p[2] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   539         p[3] = 0x80 | (Uint8) (ch & 0x3F);
   540         dst += 4;
   541     } else if (ch <= 0x3FFFFFF) {
   542         p[0] = 0xF8 | (Uint8) ((ch >> 24) & 0x03);
   543         p[1] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
   544         p[2] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
   545         p[3] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   546         p[4] = 0x80 | (Uint8) (ch & 0x3F);
   547         dst += 5;
   548     } else {
   549         p[0] = 0xFC | (Uint8) ((ch >> 30) & 0x01);
   550         p[1] = 0x80 | (Uint8) ((ch >> 24) & 0x3F);
   551         p[2] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
   552         p[3] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
   553         p[4] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
   554         p[5] = 0x80 | (Uint8) (ch & 0x3F);
   555         dst += 6;
   556     }
   557     return dst;
   558 }
   559 
   560 /* Public functions */
   561 int
   562 SDL_KeyboardInit(void)
   563 {
   564     SDL_Keyboard *keyboard = &SDL_keyboard;
   565 
   566     /* Set the default keymap */
   567     SDL_memcpy(keyboard->keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
   568     return (0);
   569 }
   570 
   571 void
   572 SDL_ResetKeyboard(void)
   573 {
   574     SDL_Keyboard *keyboard = &SDL_keyboard;
   575     SDL_Scancode scancode;
   576 
   577 #ifdef DEBUG_KEYBOARD
   578     printf("Resetting keyboard\n");
   579 #endif
   580     for (scancode = (SDL_Scancode) 0; scancode < SDL_NUM_SCANCODES; ++scancode) {
   581         if (keyboard->keystate[scancode] == SDL_PRESSED) {
   582             SDL_SendKeyboardKey(SDL_RELEASED, scancode);
   583         }
   584     }
   585 }
   586 
   587 void
   588 SDL_GetDefaultKeymap(SDL_Keycode * keymap)
   589 {
   590     SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
   591 }
   592 
   593 void
   594 SDL_SetKeymap(int start, SDL_Keycode * keys, int length)
   595 {
   596     SDL_Keyboard *keyboard = &SDL_keyboard;
   597     SDL_Scancode scancode;
   598 
   599     if (start < 0 || start + length > SDL_NUM_SCANCODES) {
   600         return;
   601     }
   602 
   603     SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
   604 
   605     /* The number key scancodes always map to the number key keycodes.
   606      * On AZERTY layouts these technically are symbols, but users (and games)
   607      * always think of them and view them in UI as number keys.
   608      */
   609     keyboard->keymap[SDL_SCANCODE_0] = SDLK_0;
   610     for (scancode = SDL_SCANCODE_1; scancode <= SDL_SCANCODE_9; ++scancode) {
   611         keyboard->keymap[scancode] = SDLK_1 + (scancode - SDL_SCANCODE_1);
   612     }
   613 }
   614 
   615 void
   616 SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
   617 {
   618     SDL_scancode_names[scancode] = name;
   619 }
   620 
   621 SDL_Window *
   622 SDL_GetKeyboardFocus(void)
   623 {
   624     SDL_Keyboard *keyboard = &SDL_keyboard;
   625 
   626     return keyboard->focus;
   627 }
   628 
   629 void
   630 SDL_SetKeyboardFocus(SDL_Window * window)
   631 {
   632     SDL_Keyboard *keyboard = &SDL_keyboard;
   633 
   634     if (keyboard->focus && !window) {
   635         /* We won't get anymore keyboard messages, so reset keyboard state */
   636         SDL_ResetKeyboard();
   637     }
   638 
   639     /* See if the current window has lost focus */
   640     if (keyboard->focus && keyboard->focus != window) {
   641 
   642         /* new window shouldn't think it has mouse captured. */
   643         SDL_assert(!window || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE));
   644 
   645         /* old window must lose an existing mouse capture. */
   646         if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
   647             SDL_CaptureMouse(SDL_FALSE);  /* drop the capture. */
   648             SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
   649         }
   650 
   651         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST,
   652                             0, 0);
   653 
   654         /* Ensures IME compositions are committed */
   655         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   656             SDL_VideoDevice *video = SDL_GetVideoDevice();
   657             if (video && video->StopTextInput) {
   658                 video->StopTextInput(video);
   659             }
   660         }
   661     }
   662 
   663     keyboard->focus = window;
   664 
   665     if (keyboard->focus) {
   666         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED,
   667                             0, 0);
   668 
   669         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   670             SDL_VideoDevice *video = SDL_GetVideoDevice();
   671             if (video && video->StartTextInput) {
   672                 video->StartTextInput(video);
   673             }
   674         }
   675     }
   676 }
   677 
   678 int
   679 SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
   680 {
   681     SDL_Keyboard *keyboard = &SDL_keyboard;
   682     int posted;
   683     SDL_Keymod modifier;
   684     SDL_Keycode keycode;
   685     Uint32 type;
   686     Uint8 repeat;
   687 
   688     if (!scancode) {
   689         return 0;
   690     }
   691 #ifdef DEBUG_KEYBOARD
   692     printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
   693            state == SDL_PRESSED ? "pressed" : "released");
   694 #endif
   695 
   696     /* Figure out what type of event this is */
   697     switch (state) {
   698     case SDL_PRESSED:
   699         type = SDL_KEYDOWN;
   700         break;
   701     case SDL_RELEASED:
   702         type = SDL_KEYUP;
   703         break;
   704     default:
   705         /* Invalid state -- bail */
   706         return 0;
   707     }
   708 
   709     /* Drop events that don't change state */
   710     repeat = (state && keyboard->keystate[scancode]);
   711     if (keyboard->keystate[scancode] == state && !repeat) {
   712 #if 0
   713         printf("Keyboard event didn't change state - dropped!\n");
   714 #endif
   715         return 0;
   716     }
   717 
   718     /* Update internal keyboard state */
   719     keyboard->keystate[scancode] = state;
   720 
   721     keycode = keyboard->keymap[scancode];
   722 
   723     /* Update modifiers state if applicable */
   724     switch (keycode) {
   725     case SDLK_LCTRL:
   726         modifier = KMOD_LCTRL;
   727         break;
   728     case SDLK_RCTRL:
   729         modifier = KMOD_RCTRL;
   730         break;
   731     case SDLK_LSHIFT:
   732         modifier = KMOD_LSHIFT;
   733         break;
   734     case SDLK_RSHIFT:
   735         modifier = KMOD_RSHIFT;
   736         break;
   737     case SDLK_LALT:
   738         modifier = KMOD_LALT;
   739         break;
   740     case SDLK_RALT:
   741         modifier = KMOD_RALT;
   742         break;
   743     case SDLK_LGUI:
   744         modifier = KMOD_LGUI;
   745         break;
   746     case SDLK_RGUI:
   747         modifier = KMOD_RGUI;
   748         break;
   749     case SDLK_MODE:
   750         modifier = KMOD_MODE;
   751         break;
   752     default:
   753         modifier = KMOD_NONE;
   754         break;
   755     }
   756     if (SDL_KEYDOWN == type) {
   757         switch (keycode) {
   758         case SDLK_NUMLOCKCLEAR:
   759             keyboard->modstate ^= KMOD_NUM;
   760             break;
   761         case SDLK_CAPSLOCK:
   762             keyboard->modstate ^= KMOD_CAPS;
   763             break;
   764         default:
   765             keyboard->modstate |= modifier;
   766             break;
   767         }
   768     } else {
   769         keyboard->modstate &= ~modifier;
   770     }
   771 
   772     /* Post the event, if desired */
   773     posted = 0;
   774     if (SDL_GetEventState(type) == SDL_ENABLE) {
   775         SDL_Event event;
   776         event.key.type = type;
   777         event.key.state = state;
   778         event.key.repeat = repeat;
   779         event.key.keysym.scancode = scancode;
   780         event.key.keysym.sym = keycode;
   781         event.key.keysym.mod = keyboard->modstate;
   782         event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
   783         posted = (SDL_PushEvent(&event) > 0);
   784     }
   785     return (posted);
   786 }
   787 
   788 int
   789 SDL_SendKeyboardText(const char *text)
   790 {
   791     SDL_Keyboard *keyboard = &SDL_keyboard;
   792     int posted;
   793 
   794     /* Don't post text events for unprintable characters */
   795     if ((unsigned char)*text < ' ' || *text == 127) {
   796         return 0;
   797     }
   798 
   799     /* Post the event, if desired */
   800     posted = 0;
   801     if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
   802         SDL_Event event;
   803         event.text.type = SDL_TEXTINPUT;
   804         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
   805         SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
   806         posted = (SDL_PushEvent(&event) > 0);
   807     }
   808     return (posted);
   809 }
   810 
   811 int
   812 SDL_SendEditingText(const char *text, int start, int length)
   813 {
   814     SDL_Keyboard *keyboard = &SDL_keyboard;
   815     int posted;
   816 
   817     /* Post the event, if desired */
   818     posted = 0;
   819     if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
   820         SDL_Event event;
   821         event.edit.type = SDL_TEXTEDITING;
   822         event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
   823         event.edit.start = start;
   824         event.edit.length = length;
   825         SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
   826         posted = (SDL_PushEvent(&event) > 0);
   827     }
   828     return (posted);
   829 }
   830 
   831 void
   832 SDL_KeyboardQuit(void)
   833 {
   834 }
   835 
   836 const Uint8 *
   837 SDL_GetKeyboardState(int *numkeys)
   838 {
   839     SDL_Keyboard *keyboard = &SDL_keyboard;
   840 
   841     if (numkeys != (int *) 0) {
   842         *numkeys = SDL_NUM_SCANCODES;
   843     }
   844     return keyboard->keystate;
   845 }
   846 
   847 SDL_Keymod
   848 SDL_GetModState(void)
   849 {
   850     SDL_Keyboard *keyboard = &SDL_keyboard;
   851 
   852     return (SDL_Keymod) keyboard->modstate;
   853 }
   854 
   855 void
   856 SDL_SetModState(SDL_Keymod modstate)
   857 {
   858     SDL_Keyboard *keyboard = &SDL_keyboard;
   859 
   860     keyboard->modstate = modstate;
   861 }
   862 
   863 /* Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is. */
   864 void
   865 SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
   866 {
   867     SDL_Keyboard *keyboard = &SDL_keyboard;
   868     if (toggle) {
   869         keyboard->modstate |= modstate;
   870     } else {
   871         keyboard->modstate &= ~modstate;
   872     }
   873 }
   874 
   875 
   876 SDL_Keycode
   877 SDL_GetKeyFromScancode(SDL_Scancode scancode)
   878 {
   879     SDL_Keyboard *keyboard = &SDL_keyboard;
   880 
   881     if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
   882           SDL_InvalidParamError("scancode");
   883           return 0;
   884     }
   885 
   886     return keyboard->keymap[scancode];
   887 }
   888 
   889 SDL_Scancode
   890 SDL_GetScancodeFromKey(SDL_Keycode key)
   891 {
   892     SDL_Keyboard *keyboard = &SDL_keyboard;
   893     SDL_Scancode scancode;
   894 
   895     for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
   896          ++scancode) {
   897         if (keyboard->keymap[scancode] == key) {
   898             return scancode;
   899         }
   900     }
   901     return SDL_SCANCODE_UNKNOWN;
   902 }
   903 
   904 const char *
   905 SDL_GetScancodeName(SDL_Scancode scancode)
   906 {
   907     const char *name;
   908     if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
   909           SDL_InvalidParamError("scancode");
   910           return "";
   911     }
   912 
   913     name = SDL_scancode_names[scancode];
   914     if (name)
   915         return name;
   916     else
   917         return "";
   918 }
   919 
   920 SDL_Scancode SDL_GetScancodeFromName(const char *name)
   921 {
   922     int i;
   923 
   924     if (!name || !*name) {
   925             SDL_InvalidParamError("name");
   926         return SDL_SCANCODE_UNKNOWN;
   927     }
   928 
   929     for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
   930         if (!SDL_scancode_names[i]) {
   931             continue;
   932         }
   933         if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
   934             return (SDL_Scancode)i;
   935         }
   936     }
   937 
   938     SDL_InvalidParamError("name");
   939     return SDL_SCANCODE_UNKNOWN;
   940 }
   941 
   942 const char *
   943 SDL_GetKeyName(SDL_Keycode key)
   944 {
   945     static char name[8];
   946     char *end;
   947 
   948     if (key & SDLK_SCANCODE_MASK) {
   949         return
   950             SDL_GetScancodeName((SDL_Scancode) (key & ~SDLK_SCANCODE_MASK));
   951     }
   952 
   953     switch (key) {
   954     case SDLK_RETURN:
   955         return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
   956     case SDLK_ESCAPE:
   957         return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
   958     case SDLK_BACKSPACE:
   959         return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
   960     case SDLK_TAB:
   961         return SDL_GetScancodeName(SDL_SCANCODE_TAB);
   962     case SDLK_SPACE:
   963         return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
   964     case SDLK_DELETE:
   965         return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
   966     default:
   967         /* Unaccented letter keys on latin keyboards are normally
   968            labeled in upper case (and probably on others like Greek or
   969            Cyrillic too, so if you happen to know for sure, please
   970            adapt this). */
   971         if (key >= 'a' && key <= 'z') {
   972             key -= 32;
   973         }
   974 
   975         end = SDL_UCS4ToUTF8((Uint32) key, name);
   976         *end = '\0';
   977         return name;
   978     }
   979 }
   980 
   981 SDL_Keycode
   982 SDL_GetKeyFromName(const char *name)
   983 {
   984     SDL_Keycode key;
   985 
   986     /* Check input */
   987     if (name == NULL) {
   988         return SDLK_UNKNOWN;
   989     }
   990 
   991     /* If it's a single UTF-8 character, then that's the keycode itself */
   992     key = *(const unsigned char *)name;
   993     if (key >= 0xF0) {
   994         if (SDL_strlen(name) == 4) {
   995             int i = 0;
   996             key  = (Uint16)(name[i]&0x07) << 18;
   997             key |= (Uint16)(name[++i]&0x3F) << 12;
   998             key |= (Uint16)(name[++i]&0x3F) << 6;
   999             key |= (Uint16)(name[++i]&0x3F);
  1000             return key;
  1001         }
  1002         return SDLK_UNKNOWN;
  1003     } else if (key >= 0xE0) {
  1004         if (SDL_strlen(name) == 3) {
  1005             int i = 0;
  1006             key  = (Uint16)(name[i]&0x0F) << 12;
  1007             key |= (Uint16)(name[++i]&0x3F) << 6;
  1008             key |= (Uint16)(name[++i]&0x3F);
  1009             return key;
  1010         }
  1011         return SDLK_UNKNOWN;
  1012     } else if (key >= 0xC0) {
  1013         if (SDL_strlen(name) == 2) {
  1014             int i = 0;
  1015             key  = (Uint16)(name[i]&0x1F) << 6;
  1016             key |= (Uint16)(name[++i]&0x3F);
  1017             return key;
  1018         }
  1019         return SDLK_UNKNOWN;
  1020     } else {
  1021         if (SDL_strlen(name) == 1) {
  1022             if (key >= 'A' && key <= 'Z') {
  1023                 key += 32;
  1024             }
  1025             return key;
  1026         }
  1027 
  1028         /* Get the scancode for this name, and the associated keycode */
  1029         return SDL_default_keymap[SDL_GetScancodeFromName(name)];
  1030     }
  1031 }
  1032 
  1033 /* vi: set ts=4 sw=4 expandtab: */