src/events/SDL_keyboard.c
author dewyatt
Wed, 15 Sep 2010 00:28:19 -0400
changeset 4882 e725a6a60c32
parent 4763 518d1679d2d0
child 4890 443771460df9
permissions -rw-r--r--
Ensure compositions are committed when keyboard focus changes.
There may be a better way to do this.
     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);
   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         //Ensures IME compositions are committed
   617         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   618             SDL_GetVideoDevice()->StopTextInput(SDL_GetVideoDevice());
   619         }
   620     }
   621 
   622     keyboard->focus = window;
   623 
   624     if (keyboard->focus) {
   625         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED,
   626                             0, 0);
   627 
   628         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   629             SDL_StartTextInput();
   630         }
   631     }
   632 }
   633 
   634 int
   635 SDL_SendKeyboardKey(Uint8 state, SDL_scancode scancode)
   636 {
   637     SDL_Keyboard *keyboard = &SDL_keyboard;
   638     int posted;
   639     Uint16 modstate;
   640     Uint32 type;
   641     Uint8 repeat;
   642 
   643     if (!scancode) {
   644         return 0;
   645     }
   646 #if 0
   647     printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
   648            state == SDL_PRESSED ? "pressed" : "released");
   649 #endif
   650     if (state == SDL_PRESSED) {
   651         modstate = keyboard->modstate;
   652         switch (scancode) {
   653         case SDL_SCANCODE_NUMLOCKCLEAR:
   654             keyboard->modstate ^= KMOD_NUM;
   655             break;
   656         case SDL_SCANCODE_CAPSLOCK:
   657             keyboard->modstate ^= KMOD_CAPS;
   658             break;
   659         case SDL_SCANCODE_LCTRL:
   660             keyboard->modstate |= KMOD_LCTRL;
   661             break;
   662         case SDL_SCANCODE_RCTRL:
   663             keyboard->modstate |= KMOD_RCTRL;
   664             break;
   665         case SDL_SCANCODE_LSHIFT:
   666             keyboard->modstate |= KMOD_LSHIFT;
   667             break;
   668         case SDL_SCANCODE_RSHIFT:
   669             keyboard->modstate |= KMOD_RSHIFT;
   670             break;
   671         case SDL_SCANCODE_LALT:
   672             keyboard->modstate |= KMOD_LALT;
   673             break;
   674         case SDL_SCANCODE_RALT:
   675             keyboard->modstate |= KMOD_RALT;
   676             break;
   677         case SDL_SCANCODE_LGUI:
   678             keyboard->modstate |= KMOD_LGUI;
   679             break;
   680         case SDL_SCANCODE_RGUI:
   681             keyboard->modstate |= KMOD_RGUI;
   682             break;
   683         case SDL_SCANCODE_MODE:
   684             keyboard->modstate |= KMOD_MODE;
   685             break;
   686         default:
   687             break;
   688         }
   689     } else {
   690         switch (scancode) {
   691         case SDL_SCANCODE_NUMLOCKCLEAR:
   692         case SDL_SCANCODE_CAPSLOCK:
   693             break;
   694         case SDL_SCANCODE_LCTRL:
   695             keyboard->modstate &= ~KMOD_LCTRL;
   696             break;
   697         case SDL_SCANCODE_RCTRL:
   698             keyboard->modstate &= ~KMOD_RCTRL;
   699             break;
   700         case SDL_SCANCODE_LSHIFT:
   701             keyboard->modstate &= ~KMOD_LSHIFT;
   702             break;
   703         case SDL_SCANCODE_RSHIFT:
   704             keyboard->modstate &= ~KMOD_RSHIFT;
   705             break;
   706         case SDL_SCANCODE_LALT:
   707             keyboard->modstate &= ~KMOD_LALT;
   708             break;
   709         case SDL_SCANCODE_RALT:
   710             keyboard->modstate &= ~KMOD_RALT;
   711             break;
   712         case SDL_SCANCODE_LGUI:
   713             keyboard->modstate &= ~KMOD_LGUI;
   714             break;
   715         case SDL_SCANCODE_RGUI:
   716             keyboard->modstate &= ~KMOD_RGUI;
   717             break;
   718         case SDL_SCANCODE_MODE:
   719             keyboard->modstate &= ~KMOD_MODE;
   720             break;
   721         default:
   722             break;
   723         }
   724         modstate = keyboard->modstate;
   725     }
   726 
   727     /* Figure out what type of event this is */
   728     switch (state) {
   729     case SDL_PRESSED:
   730         type = SDL_KEYDOWN;
   731         break;
   732     case SDL_RELEASED:
   733         type = SDL_KEYUP;
   734         break;
   735     default:
   736         /* Invalid state -- bail */
   737         return 0;
   738     }
   739 
   740     /* Drop events that don't change state */
   741     repeat = (state && keyboard->keystate[scancode]);
   742     if (keyboard->keystate[scancode] == state && !repeat) {
   743 #if 0
   744         printf("Keyboard event didn't change state - dropped!\n");
   745 #endif
   746         return 0;
   747     }
   748 
   749     /* Update internal keyboard state */
   750     keyboard->keystate[scancode] = state;
   751 
   752     /* Post the event, if desired */
   753     posted = 0;
   754     if (SDL_GetEventState(type) == SDL_ENABLE) {
   755         SDL_Event event;
   756         event.key.type = type;
   757         event.key.state = state;
   758         event.key.repeat = repeat;
   759         event.key.keysym.scancode = scancode;
   760         event.key.keysym.sym = keyboard->keymap[scancode];
   761         event.key.keysym.mod = modstate;
   762         event.key.keysym.unicode = 0;
   763         event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
   764         posted = (SDL_PushEvent(&event) > 0);
   765     }
   766     return (posted);
   767 }
   768 
   769 int
   770 SDL_SendKeyboardText(const char *text)
   771 {
   772     SDL_Keyboard *keyboard = &SDL_keyboard;
   773     int posted;
   774 
   775     /* Don't post text events for unprintable characters */
   776     if ((unsigned char)*text < ' ' || *text == 127) {
   777         return 0;
   778     }
   779 
   780     /* Post the event, if desired */
   781     posted = 0;
   782     if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
   783         SDL_Event event;
   784         event.text.type = SDL_TEXTINPUT;
   785         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
   786         SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
   787         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
   788         posted = (SDL_PushEvent(&event) > 0);
   789     }
   790     return (posted);
   791 }
   792 
   793 int
   794 SDL_SendEditingText(const char *text, int start, int length)
   795 {
   796     SDL_Keyboard *keyboard = &SDL_keyboard;
   797     int posted;
   798 
   799     /* Post the event, if desired */
   800     posted = 0;
   801     if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
   802         SDL_Event event;
   803         event.edit.type = SDL_TEXTEDITING;
   804         event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
   805         event.edit.start = start;
   806         event.edit.length = length;
   807         SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
   808         posted = (SDL_PushEvent(&event) > 0);
   809     }
   810     return (posted);
   811 }
   812 
   813 void
   814 SDL_KeyboardQuit(void)
   815 {
   816 }
   817 
   818 Uint8 *
   819 SDL_GetKeyboardState(int *numkeys)
   820 {
   821     SDL_Keyboard *keyboard = &SDL_keyboard;
   822 
   823     if (numkeys != (int *) 0) {
   824         *numkeys = SDL_NUM_SCANCODES;
   825     }
   826     return keyboard->keystate;
   827 }
   828 
   829 SDLMod
   830 SDL_GetModState(void)
   831 {
   832     SDL_Keyboard *keyboard = &SDL_keyboard;
   833 
   834     return keyboard->modstate;
   835 }
   836 
   837 void
   838 SDL_SetModState(SDLMod modstate)
   839 {
   840     SDL_Keyboard *keyboard = &SDL_keyboard;
   841 
   842     keyboard->modstate = modstate;
   843 }
   844 
   845 SDLKey
   846 SDL_GetKeyFromScancode(SDL_scancode scancode)
   847 {
   848     SDL_Keyboard *keyboard = &SDL_keyboard;
   849 
   850     return keyboard->keymap[scancode];
   851 }
   852 
   853 SDL_scancode
   854 SDL_GetScancodeFromKey(SDLKey key)
   855 {
   856     SDL_Keyboard *keyboard = &SDL_keyboard;
   857     SDL_scancode scancode;
   858 
   859     for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
   860          ++scancode) {
   861         if (keyboard->keymap[scancode] == key) {
   862             return scancode;
   863         }
   864     }
   865     return SDL_SCANCODE_UNKNOWN;
   866 }
   867 
   868 const char *
   869 SDL_GetScancodeName(SDL_scancode scancode)
   870 {
   871     const char *name = SDL_scancode_names[scancode];
   872 
   873     if (name)
   874         return name;
   875     else
   876         return "";
   877 }
   878 
   879 const char *
   880 SDL_GetKeyName(SDLKey key)
   881 {
   882     static char name[8];
   883     char *end;
   884 
   885     if (key & SDLK_SCANCODE_MASK) {
   886         return
   887             SDL_GetScancodeName((SDL_scancode) (key & ~SDLK_SCANCODE_MASK));
   888     }
   889 
   890     switch (key) {
   891     case SDLK_RETURN:
   892         return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
   893     case SDLK_ESCAPE:
   894         return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
   895     case SDLK_BACKSPACE:
   896         return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
   897     case SDLK_TAB:
   898         return SDL_GetScancodeName(SDL_SCANCODE_TAB);
   899     case SDLK_SPACE:
   900         return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
   901     case SDLK_DELETE:
   902         return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
   903     default:
   904         /* Unaccented letter keys on latin keyboards are normally
   905            labeled in upper case (and probably on others like Greek or
   906            Cyrillic too, so if you happen to know for sure, please
   907            adapt this). */
   908         if (key >= 'a' && key <= 'z') {
   909             key -= 32;
   910         }
   911 
   912         end = SDL_UCS4ToUTF8((Uint32) key, name);
   913         *end = '\0';
   914         return name;
   915     }
   916 }
   917 
   918 /* vi: set ts=4 sw=4 expandtab: */