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