src/events/SDL_keyboard.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 12 Aug 2017 12:34:09 -0700
changeset 11240 1f6105d09344
parent 11149 504c67e71589
child 11247 27eb9a10002c
permissions -rw-r--r--
Fixed bug 3249 - keysym.mod is incorrect when mod keys are pressed for SDL_KEYDOWN events

Adam M.

The keysym.mod field does not reflect the state of the modified keys when processing key down events for the modifier keys themselves. The documentation says that it returns the current key modifiers, but they are not current for key down events involving modifier keys. I interpret "current" to mean "equal to SDL_GetModState() at the instant the event is processed/enqueued".

For example, if you depress the Shift key you get a key down event with .mod == 0. However, .mod should not be 0 because a shift key is down. If you then release the Shift key, you get a key up event with .mod == 0. Neither event reports the modifier key.

If you press Shift and then A, .mod is incorrect (== 0) when Shift is pressed, but is correct later when A is pressed (== KMOD_LSHIFT).

You might say this behavior is deliberate, i.e. keysym.mod is the value /before/ the event, not the current value as documented, but that explanation is incorrect because only key down events behave that way. Key up events correctly give the current value, not the value before the event.

Not only is it inconsistent with itself, I think it makes keyboard processing harder.

The problem is near line 740 in SDL_keyboard.c:

if (SDL_KEYDOWN == type) {
modstate = keyboard->modstate; // SHOULD THIS BE MOVED DOWN?
switch (keycode) {
case SDLK_NUMLOCKCLEAR:
keyboard->modstate ^= KMOD_NUM;
break;
case SDLK_CAPSLOCK:
keyboard->modstate ^= KMOD_CAPS;
break;
default:
keyboard->modstate |= modifier;
break;
}
} else {
keyboard->modstate &= ~modifier;
modstate = keyboard->modstate;
}

In the key down path, modstate (and thus keysym.mod) ends up being the modifier state /before/ the event, but in the key up path modstate ends up being the modifier state /after/ the event. Personally I think the "modstate = keyboard->modstate" line should just be moved after the entire if/else statement, so that keysym.mod always reflects the current state.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 
   598     if (start < 0 || start + length > SDL_NUM_SCANCODES) {
   599         return;
   600     }
   601 
   602     SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
   603 }
   604 
   605 void
   606 SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
   607 {
   608     SDL_scancode_names[scancode] = name;
   609 }
   610 
   611 SDL_Window *
   612 SDL_GetKeyboardFocus(void)
   613 {
   614     SDL_Keyboard *keyboard = &SDL_keyboard;
   615 
   616     return keyboard->focus;
   617 }
   618 
   619 void
   620 SDL_SetKeyboardFocus(SDL_Window * window)
   621 {
   622     SDL_Keyboard *keyboard = &SDL_keyboard;
   623 
   624     if (keyboard->focus && !window) {
   625         /* We won't get anymore keyboard messages, so reset keyboard state */
   626         SDL_ResetKeyboard();
   627     }
   628 
   629     /* See if the current window has lost focus */
   630     if (keyboard->focus && keyboard->focus != window) {
   631 
   632         /* new window shouldn't think it has mouse captured. */
   633         SDL_assert(!window || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE));
   634 
   635         /* old window must lose an existing mouse capture. */
   636         if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
   637             SDL_CaptureMouse(SDL_FALSE);  /* drop the capture. */
   638             SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
   639         }
   640 
   641         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST,
   642                             0, 0);
   643 
   644         /* Ensures IME compositions are committed */
   645         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   646             SDL_VideoDevice *video = SDL_GetVideoDevice();
   647             if (video && video->StopTextInput) {
   648                 video->StopTextInput(video);
   649             }
   650         }
   651     }
   652 
   653     keyboard->focus = window;
   654 
   655     if (keyboard->focus) {
   656         SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED,
   657                             0, 0);
   658 
   659         if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
   660             SDL_VideoDevice *video = SDL_GetVideoDevice();
   661             if (video && video->StartTextInput) {
   662                 video->StartTextInput(video);
   663             }
   664         }
   665     }
   666 }
   667 
   668 int
   669 SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
   670 {
   671     SDL_Keyboard *keyboard = &SDL_keyboard;
   672     int posted;
   673     SDL_Keymod modifier;
   674     SDL_Keycode keycode;
   675     Uint32 type;
   676     Uint8 repeat;
   677 
   678     if (!scancode) {
   679         return 0;
   680     }
   681 #ifdef DEBUG_KEYBOARD
   682     printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
   683            state == SDL_PRESSED ? "pressed" : "released");
   684 #endif
   685 
   686     /* Figure out what type of event this is */
   687     switch (state) {
   688     case SDL_PRESSED:
   689         type = SDL_KEYDOWN;
   690         break;
   691     case SDL_RELEASED:
   692         type = SDL_KEYUP;
   693         break;
   694     default:
   695         /* Invalid state -- bail */
   696         return 0;
   697     }
   698 
   699     /* Drop events that don't change state */
   700     repeat = (state && keyboard->keystate[scancode]);
   701     if (keyboard->keystate[scancode] == state && !repeat) {
   702 #if 0
   703         printf("Keyboard event didn't change state - dropped!\n");
   704 #endif
   705         return 0;
   706     }
   707 
   708     /* Update internal keyboard state */
   709     keyboard->keystate[scancode] = state;
   710 
   711     keycode = keyboard->keymap[scancode];
   712 
   713     /* Update modifiers state if applicable */
   714     switch (keycode) {
   715     case SDLK_LCTRL:
   716         modifier = KMOD_LCTRL;
   717         break;
   718     case SDLK_RCTRL:
   719         modifier = KMOD_RCTRL;
   720         break;
   721     case SDLK_LSHIFT:
   722         modifier = KMOD_LSHIFT;
   723         break;
   724     case SDLK_RSHIFT:
   725         modifier = KMOD_RSHIFT;
   726         break;
   727     case SDLK_LALT:
   728         modifier = KMOD_LALT;
   729         break;
   730     case SDLK_RALT:
   731         modifier = KMOD_RALT;
   732         break;
   733     case SDLK_LGUI:
   734         modifier = KMOD_LGUI;
   735         break;
   736     case SDLK_RGUI:
   737         modifier = KMOD_RGUI;
   738         break;
   739     case SDLK_MODE:
   740         modifier = KMOD_MODE;
   741         break;
   742     default:
   743         modifier = KMOD_NONE;
   744         break;
   745     }
   746     if (SDL_KEYDOWN == type) {
   747         switch (keycode) {
   748         case SDLK_NUMLOCKCLEAR:
   749             keyboard->modstate ^= KMOD_NUM;
   750             break;
   751         case SDLK_CAPSLOCK:
   752             keyboard->modstate ^= KMOD_CAPS;
   753             break;
   754         default:
   755             keyboard->modstate |= modifier;
   756             break;
   757         }
   758     } else {
   759         keyboard->modstate &= ~modifier;
   760     }
   761 
   762     /* Post the event, if desired */
   763     posted = 0;
   764     if (SDL_GetEventState(type) == SDL_ENABLE) {
   765         SDL_Event event;
   766         event.key.type = type;
   767         event.key.state = state;
   768         event.key.repeat = repeat;
   769         event.key.keysym.scancode = scancode;
   770         event.key.keysym.sym = keycode;
   771         event.key.keysym.mod = keyboard->modstate;
   772         event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
   773         posted = (SDL_PushEvent(&event) > 0);
   774     }
   775     return (posted);
   776 }
   777 
   778 int
   779 SDL_SendKeyboardText(const char *text)
   780 {
   781     SDL_Keyboard *keyboard = &SDL_keyboard;
   782     int posted;
   783 
   784     /* Don't post text events for unprintable characters */
   785     if ((unsigned char)*text < ' ' || *text == 127) {
   786         return 0;
   787     }
   788 
   789     /* Post the event, if desired */
   790     posted = 0;
   791     if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
   792         SDL_Event event;
   793         event.text.type = SDL_TEXTINPUT;
   794         event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
   795         SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
   796         posted = (SDL_PushEvent(&event) > 0);
   797     }
   798     return (posted);
   799 }
   800 
   801 int
   802 SDL_SendEditingText(const char *text, int start, int length)
   803 {
   804     SDL_Keyboard *keyboard = &SDL_keyboard;
   805     int posted;
   806 
   807     /* Post the event, if desired */
   808     posted = 0;
   809     if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
   810         SDL_Event event;
   811         event.edit.type = SDL_TEXTEDITING;
   812         event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
   813         event.edit.start = start;
   814         event.edit.length = length;
   815         SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
   816         posted = (SDL_PushEvent(&event) > 0);
   817     }
   818     return (posted);
   819 }
   820 
   821 void
   822 SDL_KeyboardQuit(void)
   823 {
   824 }
   825 
   826 const Uint8 *
   827 SDL_GetKeyboardState(int *numkeys)
   828 {
   829     SDL_Keyboard *keyboard = &SDL_keyboard;
   830 
   831     if (numkeys != (int *) 0) {
   832         *numkeys = SDL_NUM_SCANCODES;
   833     }
   834     return keyboard->keystate;
   835 }
   836 
   837 SDL_Keymod
   838 SDL_GetModState(void)
   839 {
   840     SDL_Keyboard *keyboard = &SDL_keyboard;
   841 
   842     return (SDL_Keymod) keyboard->modstate;
   843 }
   844 
   845 void
   846 SDL_SetModState(SDL_Keymod modstate)
   847 {
   848     SDL_Keyboard *keyboard = &SDL_keyboard;
   849 
   850     keyboard->modstate = modstate;
   851 }
   852 
   853 /* Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is. */
   854 void
   855 SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
   856 {
   857     SDL_Keyboard *keyboard = &SDL_keyboard;
   858     if (toggle) {
   859         keyboard->modstate |= modstate;
   860     } else {
   861         keyboard->modstate &= ~modstate;
   862     }
   863 }
   864 
   865 
   866 SDL_Keycode
   867 SDL_GetKeyFromScancode(SDL_Scancode scancode)
   868 {
   869     SDL_Keyboard *keyboard = &SDL_keyboard;
   870 
   871     if (((int)scancode) < ((int)SDL_SCANCODE_UNKNOWN) || scancode >= SDL_NUM_SCANCODES) {
   872           SDL_InvalidParamError("scancode");
   873           return 0;
   874     }
   875 
   876     return keyboard->keymap[scancode];
   877 }
   878 
   879 SDL_Scancode
   880 SDL_GetScancodeFromKey(SDL_Keycode key)
   881 {
   882     SDL_Keyboard *keyboard = &SDL_keyboard;
   883     SDL_Scancode scancode;
   884 
   885     for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
   886          ++scancode) {
   887         if (keyboard->keymap[scancode] == key) {
   888             return scancode;
   889         }
   890     }
   891     return SDL_SCANCODE_UNKNOWN;
   892 }
   893 
   894 const char *
   895 SDL_GetScancodeName(SDL_Scancode scancode)
   896 {
   897     const char *name;
   898     if (((int)scancode) < ((int)SDL_SCANCODE_UNKNOWN) || scancode >= SDL_NUM_SCANCODES) {
   899           SDL_InvalidParamError("scancode");
   900           return "";
   901     }
   902 
   903     name = SDL_scancode_names[scancode];
   904     if (name)
   905         return name;
   906     else
   907         return "";
   908 }
   909 
   910 SDL_Scancode SDL_GetScancodeFromName(const char *name)
   911 {
   912     int i;
   913 
   914     if (!name || !*name) {
   915             SDL_InvalidParamError("name");
   916         return SDL_SCANCODE_UNKNOWN;
   917     }
   918 
   919     for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
   920         if (!SDL_scancode_names[i]) {
   921             continue;
   922         }
   923         if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
   924             return (SDL_Scancode)i;
   925         }
   926     }
   927 
   928     SDL_InvalidParamError("name");
   929     return SDL_SCANCODE_UNKNOWN;
   930 }
   931 
   932 const char *
   933 SDL_GetKeyName(SDL_Keycode key)
   934 {
   935     static char name[8];
   936     char *end;
   937 
   938     if (key & SDLK_SCANCODE_MASK) {
   939         return
   940             SDL_GetScancodeName((SDL_Scancode) (key & ~SDLK_SCANCODE_MASK));
   941     }
   942 
   943     switch (key) {
   944     case SDLK_RETURN:
   945         return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
   946     case SDLK_ESCAPE:
   947         return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
   948     case SDLK_BACKSPACE:
   949         return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
   950     case SDLK_TAB:
   951         return SDL_GetScancodeName(SDL_SCANCODE_TAB);
   952     case SDLK_SPACE:
   953         return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
   954     case SDLK_DELETE:
   955         return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
   956     default:
   957         /* Unaccented letter keys on latin keyboards are normally
   958            labeled in upper case (and probably on others like Greek or
   959            Cyrillic too, so if you happen to know for sure, please
   960            adapt this). */
   961         if (key >= 'a' && key <= 'z') {
   962             key -= 32;
   963         }
   964 
   965         end = SDL_UCS4ToUTF8((Uint32) key, name);
   966         *end = '\0';
   967         return name;
   968     }
   969 }
   970 
   971 SDL_Keycode
   972 SDL_GetKeyFromName(const char *name)
   973 {
   974     SDL_Keycode key;
   975 
   976     /* Check input */
   977     if (name == NULL) {
   978         return SDLK_UNKNOWN;
   979     }
   980 
   981     /* If it's a single UTF-8 character, then that's the keycode itself */
   982     key = *(const unsigned char *)name;
   983     if (key >= 0xF0) {
   984         if (SDL_strlen(name) == 4) {
   985             int i = 0;
   986             key  = (Uint16)(name[i]&0x07) << 18;
   987             key |= (Uint16)(name[++i]&0x3F) << 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 >= 0xE0) {
   994         if (SDL_strlen(name) == 3) {
   995             int i = 0;
   996             key  = (Uint16)(name[i]&0x0F) << 12;
   997             key |= (Uint16)(name[++i]&0x3F) << 6;
   998             key |= (Uint16)(name[++i]&0x3F);
   999             return key;
  1000         }
  1001         return SDLK_UNKNOWN;
  1002     } else if (key >= 0xC0) {
  1003         if (SDL_strlen(name) == 2) {
  1004             int i = 0;
  1005             key  = (Uint16)(name[i]&0x1F) << 6;
  1006             key |= (Uint16)(name[++i]&0x3F);
  1007             return key;
  1008         }
  1009         return SDLK_UNKNOWN;
  1010     } else {
  1011         if (SDL_strlen(name) == 1) {
  1012             if (key >= 'A' && key <= 'Z') {
  1013                 key += 32;
  1014             }
  1015             return key;
  1016         }
  1017 
  1018         /* Get the scancode for this name, and the associated keycode */
  1019         return SDL_default_keymap[SDL_GetScancodeFromName(name)];
  1020     }
  1021 }
  1022 
  1023 /* vi: set ts=4 sw=4 expandtab: */