Add input validation to SDL_GetKeyFromScancode; fix compiler warning in testautomation driver on Linux; update keyboard test suite
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "SDL_config.h"
23 /* General keyboard handling code for SDL */
25 #include "SDL_timer.h"
26 #include "SDL_events.h"
27 #include "SDL_events_c.h"
28 #include "../video/SDL_sysvideo.h"
31 /*#define DEBUG_KEYBOARD*/
33 /* Global keyboard information */
35 typedef struct SDL_Keyboard SDL_Keyboard;
39 /* Data common to all keyboards */
42 Uint8 keystate[SDL_NUM_SCANCODES];
43 SDL_Keycode keymap[SDL_NUM_SCANCODES];
46 static SDL_Keyboard SDL_keyboard;
48 static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
179 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195 SDLK_THOUSANDSSEPARATOR,
196 SDLK_DECIMALSEPARATOR,
198 SDLK_CURRENCYSUBUNIT,
217 SDLK_KP_DBLAMPERSAND,
219 SDLK_KP_DBLVERTICALBAR,
248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277 static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
278 NULL, NULL, NULL, NULL,
408 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
409 NULL, NULL, NULL, NULL, NULL, NULL,
422 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
425 "ThousandsSeparator",
459 "Keypad MemSubtract",
460 "Keypad MemMultiply",
468 "Keypad Hexadecimal",
478 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
479 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
509 /* Taken from SDL_iconv() */
511 SDL_UCS4ToUTF8(Uint32 ch, char *dst)
513 Uint8 *p = (Uint8 *) dst;
517 } else if (ch <= 0x7FF) {
518 p[0] = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
519 p[1] = 0x80 | (Uint8) (ch & 0x3F);
521 } else if (ch <= 0xFFFF) {
522 p[0] = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
523 p[1] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
524 p[2] = 0x80 | (Uint8) (ch & 0x3F);
526 } else if (ch <= 0x1FFFFF) {
527 p[0] = 0xF0 | (Uint8) ((ch >> 18) & 0x07);
528 p[1] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
529 p[2] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
530 p[3] = 0x80 | (Uint8) (ch & 0x3F);
532 } else if (ch <= 0x3FFFFFF) {
533 p[0] = 0xF8 | (Uint8) ((ch >> 24) & 0x03);
534 p[1] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
535 p[2] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
536 p[3] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
537 p[4] = 0x80 | (Uint8) (ch & 0x3F);
540 p[0] = 0xFC | (Uint8) ((ch >> 30) & 0x01);
541 p[1] = 0x80 | (Uint8) ((ch >> 24) & 0x3F);
542 p[2] = 0x80 | (Uint8) ((ch >> 18) & 0x3F);
543 p[3] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
544 p[4] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
545 p[5] = 0x80 | (Uint8) (ch & 0x3F);
551 /* Public functions */
553 SDL_KeyboardInit(void)
555 SDL_Keyboard *keyboard = &SDL_keyboard;
557 /* Set the default keymap */
558 SDL_memcpy(keyboard->keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
563 SDL_ResetKeyboard(void)
565 SDL_Keyboard *keyboard = &SDL_keyboard;
566 SDL_Scancode scancode;
568 #ifdef DEBUG_KEYBOARD
569 printf("Resetting keyboard\n");
571 for (scancode = 0; scancode < SDL_NUM_SCANCODES; ++scancode) {
572 if (keyboard->keystate[scancode] == SDL_PRESSED) {
573 SDL_SendKeyboardKey(SDL_RELEASED, scancode);
579 SDL_GetDefaultKeymap(SDL_Keycode * keymap)
581 SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
585 SDL_SetKeymap(int start, SDL_Keycode * keys, int length)
587 SDL_Keyboard *keyboard = &SDL_keyboard;
589 if (start < 0 || start + length > SDL_NUM_SCANCODES) {
593 SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
597 SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
599 SDL_scancode_names[scancode] = name;
603 SDL_GetKeyboardFocus(void)
605 SDL_Keyboard *keyboard = &SDL_keyboard;
607 return keyboard->focus;
611 SDL_SetKeyboardFocus(SDL_Window * window)
613 SDL_Keyboard *keyboard = &SDL_keyboard;
615 if (keyboard->focus && !window) {
616 /* We won't get anymore keyboard messages, so reset keyboard state */
620 /* See if the current window has lost focus */
621 if (keyboard->focus && keyboard->focus != window) {
622 SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST,
625 /* Ensures IME compositions are committed */
626 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
627 SDL_VideoDevice *video = SDL_GetVideoDevice();
628 if (video && video->StopTextInput) {
629 video->StopTextInput(video);
634 keyboard->focus = window;
636 if (keyboard->focus) {
637 SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED,
640 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
641 SDL_VideoDevice *video = SDL_GetVideoDevice();
642 if (video && video->StartTextInput) {
643 video->StartTextInput(video);
650 SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
652 SDL_Keyboard *keyboard = &SDL_keyboard;
661 #ifdef DEBUG_KEYBOARD
662 printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
663 state == SDL_PRESSED ? "pressed" : "released");
665 if (state == SDL_PRESSED) {
666 modstate = keyboard->modstate;
668 case SDL_SCANCODE_NUMLOCKCLEAR:
669 keyboard->modstate ^= KMOD_NUM;
671 case SDL_SCANCODE_CAPSLOCK:
672 keyboard->modstate ^= KMOD_CAPS;
674 case SDL_SCANCODE_LCTRL:
675 keyboard->modstate |= KMOD_LCTRL;
677 case SDL_SCANCODE_RCTRL:
678 keyboard->modstate |= KMOD_RCTRL;
680 case SDL_SCANCODE_LSHIFT:
681 keyboard->modstate |= KMOD_LSHIFT;
683 case SDL_SCANCODE_RSHIFT:
684 keyboard->modstate |= KMOD_RSHIFT;
686 case SDL_SCANCODE_LALT:
687 keyboard->modstate |= KMOD_LALT;
689 case SDL_SCANCODE_RALT:
690 keyboard->modstate |= KMOD_RALT;
692 case SDL_SCANCODE_LGUI:
693 keyboard->modstate |= KMOD_LGUI;
695 case SDL_SCANCODE_RGUI:
696 keyboard->modstate |= KMOD_RGUI;
698 case SDL_SCANCODE_MODE:
699 keyboard->modstate |= KMOD_MODE;
706 case SDL_SCANCODE_NUMLOCKCLEAR:
707 case SDL_SCANCODE_CAPSLOCK:
709 case SDL_SCANCODE_LCTRL:
710 keyboard->modstate &= ~KMOD_LCTRL;
712 case SDL_SCANCODE_RCTRL:
713 keyboard->modstate &= ~KMOD_RCTRL;
715 case SDL_SCANCODE_LSHIFT:
716 keyboard->modstate &= ~KMOD_LSHIFT;
718 case SDL_SCANCODE_RSHIFT:
719 keyboard->modstate &= ~KMOD_RSHIFT;
721 case SDL_SCANCODE_LALT:
722 keyboard->modstate &= ~KMOD_LALT;
724 case SDL_SCANCODE_RALT:
725 keyboard->modstate &= ~KMOD_RALT;
727 case SDL_SCANCODE_LGUI:
728 keyboard->modstate &= ~KMOD_LGUI;
730 case SDL_SCANCODE_RGUI:
731 keyboard->modstate &= ~KMOD_RGUI;
733 case SDL_SCANCODE_MODE:
734 keyboard->modstate &= ~KMOD_MODE;
739 modstate = keyboard->modstate;
742 /* Figure out what type of event this is */
751 /* Invalid state -- bail */
755 /* Drop events that don't change state */
756 repeat = (state && keyboard->keystate[scancode]);
757 if (keyboard->keystate[scancode] == state && !repeat) {
759 printf("Keyboard event didn't change state - dropped!\n");
764 /* Update internal keyboard state */
765 keyboard->keystate[scancode] = state;
767 /* Post the event, if desired */
769 if (SDL_GetEventState(type) == SDL_ENABLE) {
771 event.key.type = type;
772 event.key.state = state;
773 event.key.repeat = repeat;
774 event.key.keysym.scancode = scancode;
775 event.key.keysym.sym = keyboard->keymap[scancode];
776 event.key.keysym.mod = modstate;
777 event.key.keysym.unicode = 0;
778 event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
779 posted = (SDL_PushEvent(&event) > 0);
785 SDL_SendKeyboardText(const char *text)
787 SDL_Keyboard *keyboard = &SDL_keyboard;
790 /* Don't post text events for unprintable characters */
791 if ((unsigned char)*text < ' ' || *text == 127) {
795 /* Post the event, if desired */
797 if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
799 event.text.type = SDL_TEXTINPUT;
800 event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
801 SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
802 posted = (SDL_PushEvent(&event) > 0);
808 SDL_SendEditingText(const char *text, int start, int length)
810 SDL_Keyboard *keyboard = &SDL_keyboard;
813 /* Post the event, if desired */
815 if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
817 event.edit.type = SDL_TEXTEDITING;
818 event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
819 event.edit.start = start;
820 event.edit.length = length;
821 SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
822 posted = (SDL_PushEvent(&event) > 0);
828 SDL_KeyboardQuit(void)
833 SDL_GetKeyboardState(int *numkeys)
835 SDL_Keyboard *keyboard = &SDL_keyboard;
837 if (numkeys != (int *) 0) {
838 *numkeys = SDL_NUM_SCANCODES;
840 return keyboard->keystate;
844 SDL_GetModState(void)
846 SDL_Keyboard *keyboard = &SDL_keyboard;
848 return keyboard->modstate;
852 SDL_SetModState(SDL_Keymod modstate)
854 SDL_Keyboard *keyboard = &SDL_keyboard;
856 keyboard->modstate = modstate;
860 SDL_GetKeyFromScancode(SDL_Scancode scancode)
862 SDL_Keyboard *keyboard = &SDL_keyboard;
864 if (scancode<SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
865 SDL_InvalidParamError("scancode");
869 return keyboard->keymap[scancode];
873 SDL_GetScancodeFromKey(SDL_Keycode key)
875 SDL_Keyboard *keyboard = &SDL_keyboard;
876 SDL_Scancode scancode;
878 for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
880 if (keyboard->keymap[scancode] == key) {
884 return SDL_SCANCODE_UNKNOWN;
888 SDL_GetScancodeName(SDL_Scancode scancode)
890 const char *name = SDL_scancode_names[scancode];
898 SDL_Scancode SDL_GetScancodeFromName(const char *name)
902 if (!name || !*name) {
903 SDL_InvalidParamError("name");
904 return SDL_SCANCODE_UNKNOWN;
907 for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
908 if (!SDL_scancode_names[i]) {
911 if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
912 return (SDL_Scancode)i;
916 SDL_InvalidParamError("name");
917 return SDL_SCANCODE_UNKNOWN;
921 SDL_GetKeyName(SDL_Keycode key)
926 if (key & SDLK_SCANCODE_MASK) {
928 SDL_GetScancodeName((SDL_Scancode) (key & ~SDLK_SCANCODE_MASK));
933 return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
935 return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
937 return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
939 return SDL_GetScancodeName(SDL_SCANCODE_TAB);
941 return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
943 return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
945 /* Unaccented letter keys on latin keyboards are normally
946 labeled in upper case (and probably on others like Greek or
947 Cyrillic too, so if you happen to know for sure, please
949 if (key >= 'a' && key <= 'z') {
953 end = SDL_UCS4ToUTF8((Uint32) key, name);
960 SDL_GetKeyFromName(const char *name)
965 if (name == NULL) return SDLK_UNKNOWN;
967 /* If it's a single UTF-8 character, then that's the keycode itself */
968 key = *(const unsigned char *)name;
970 if (SDL_strlen(name) == 4) {
972 key = (Uint16)(name[i]&0x07) << 18;
973 key |= (Uint16)(name[++i]&0x3F) << 12;
974 key |= (Uint16)(name[++i]&0x3F) << 6;
975 key |= (Uint16)(name[++i]&0x3F);
979 } else if (key >= 0xE0) {
980 if (SDL_strlen(name) == 3) {
982 key = (Uint16)(name[i]&0x0F) << 12;
983 key |= (Uint16)(name[++i]&0x3F) << 6;
984 key |= (Uint16)(name[++i]&0x3F);
988 } else if (key >= 0xC0) {
989 if (SDL_strlen(name) == 2) {
991 key = (Uint16)(name[i]&0x1F) << 6;
992 key |= (Uint16)(name[++i]&0x3F);
997 if (SDL_strlen(name) == 1) {
998 if (key >= 'A' && key <= 'Z') {
1004 /* Get the scancode for this name, and the associated keycode */
1005 return SDL_default_keymap[SDL_GetScancodeFromName(name)];
1009 /* vi: set ts=4 sw=4 expandtab: */