2 Simple DirectMedia Layer
3 Copyright (C) 1997-2018 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_internal.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 "SDL_assert.h"
29 #include "../video/SDL_sysvideo.h"
32 /* #define DEBUG_KEYBOARD */
34 /* Global keyboard information */
36 typedef struct SDL_Keyboard SDL_Keyboard;
40 /* Data common to all keyboards */
43 Uint8 keystate[SDL_NUM_SCANCODES];
44 SDL_Keycode keymap[SDL_NUM_SCANCODES];
47 static SDL_Keyboard SDL_keyboard;
49 static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
180 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196 SDLK_THOUSANDSSEPARATOR,
197 SDLK_DECIMALSEPARATOR,
199 SDLK_CURRENCYSUBUNIT,
218 SDLK_KP_DBLAMPERSAND,
220 SDLK_KP_DBLVERTICALBAR,
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,
279 SDLK_AUDIOFASTFORWARD,
282 static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
283 NULL, NULL, NULL, NULL,
413 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
414 NULL, NULL, NULL, NULL, NULL, NULL,
427 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
430 "ThousandsSeparator",
464 "Keypad MemSubtract",
465 "Keypad MemMultiply",
473 "Keypad Hexadecimal",
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,
518 /* Taken from SDL_iconv() */
520 SDL_UCS4ToUTF8(Uint32 ch, char *dst)
522 Uint8 *p = (Uint8 *) dst;
526 } else if (ch <= 0x7FF) {
527 p[0] = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
528 p[1] = 0x80 | (Uint8) (ch & 0x3F);
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);
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);
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);
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);
560 /* Public functions */
562 SDL_KeyboardInit(void)
564 SDL_Keyboard *keyboard = &SDL_keyboard;
566 /* Set the default keymap */
567 SDL_memcpy(keyboard->keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
572 SDL_ResetKeyboard(void)
574 SDL_Keyboard *keyboard = &SDL_keyboard;
575 SDL_Scancode scancode;
577 #ifdef DEBUG_KEYBOARD
578 printf("Resetting keyboard\n");
580 for (scancode = (SDL_Scancode) 0; scancode < SDL_NUM_SCANCODES; ++scancode) {
581 if (keyboard->keystate[scancode] == SDL_PRESSED) {
582 SDL_SendKeyboardKey(SDL_RELEASED, scancode);
588 SDL_GetDefaultKeymap(SDL_Keycode * keymap)
590 SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
594 SDL_SetKeymap(int start, SDL_Keycode * keys, int length)
596 SDL_Keyboard *keyboard = &SDL_keyboard;
597 SDL_Scancode scancode;
599 if (start < 0 || start + length > SDL_NUM_SCANCODES) {
603 SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
605 /* The number key scancodes always map to the number key keycodes.
606 * On AZERTY layouts these technically are symbols, but users (and games)
607 * always think of them and view them in UI as number keys.
609 keyboard->keymap[SDL_SCANCODE_0] = SDLK_0;
610 for (scancode = SDL_SCANCODE_1; scancode <= SDL_SCANCODE_9; ++scancode) {
611 keyboard->keymap[scancode] = SDLK_1 + (scancode - SDL_SCANCODE_1);
616 SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
618 SDL_scancode_names[scancode] = name;
622 SDL_GetKeyboardFocus(void)
624 SDL_Keyboard *keyboard = &SDL_keyboard;
626 return keyboard->focus;
630 SDL_SetKeyboardFocus(SDL_Window * window)
632 SDL_Keyboard *keyboard = &SDL_keyboard;
634 if (keyboard->focus && !window) {
635 /* We won't get anymore keyboard messages, so reset keyboard state */
639 /* See if the current window has lost focus */
640 if (keyboard->focus && keyboard->focus != window) {
642 /* new window shouldn't think it has mouse captured. */
643 SDL_assert(!window || !(window->flags & SDL_WINDOW_MOUSE_CAPTURE));
645 /* old window must lose an existing mouse capture. */
646 if (keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE) {
647 SDL_CaptureMouse(SDL_FALSE); /* drop the capture. */
648 SDL_assert(!(keyboard->focus->flags & SDL_WINDOW_MOUSE_CAPTURE));
651 SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_LOST,
654 /* Ensures IME compositions are committed */
655 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
656 SDL_VideoDevice *video = SDL_GetVideoDevice();
657 if (video && video->StopTextInput) {
658 video->StopTextInput(video);
663 keyboard->focus = window;
665 if (keyboard->focus) {
666 SDL_SendWindowEvent(keyboard->focus, SDL_WINDOWEVENT_FOCUS_GAINED,
669 if (SDL_EventState(SDL_TEXTINPUT, SDL_QUERY)) {
670 SDL_VideoDevice *video = SDL_GetVideoDevice();
671 if (video && video->StartTextInput) {
672 video->StartTextInput(video);
679 SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
681 SDL_Keyboard *keyboard = &SDL_keyboard;
691 #ifdef DEBUG_KEYBOARD
692 printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
693 state == SDL_PRESSED ? "pressed" : "released");
696 /* Figure out what type of event this is */
705 /* Invalid state -- bail */
709 /* Drop events that don't change state */
710 repeat = (state && keyboard->keystate[scancode]);
711 if (keyboard->keystate[scancode] == state && !repeat) {
713 printf("Keyboard event didn't change state - dropped!\n");
718 /* Update internal keyboard state */
719 keyboard->keystate[scancode] = state;
721 keycode = keyboard->keymap[scancode];
723 /* Update modifiers state if applicable */
726 modifier = KMOD_LCTRL;
729 modifier = KMOD_RCTRL;
732 modifier = KMOD_LSHIFT;
735 modifier = KMOD_RSHIFT;
738 modifier = KMOD_LALT;
741 modifier = KMOD_RALT;
744 modifier = KMOD_LGUI;
747 modifier = KMOD_RGUI;
750 modifier = KMOD_MODE;
753 modifier = KMOD_NONE;
756 if (SDL_KEYDOWN == type) {
758 case SDLK_NUMLOCKCLEAR:
759 keyboard->modstate ^= KMOD_NUM;
762 keyboard->modstate ^= KMOD_CAPS;
765 keyboard->modstate |= modifier;
769 keyboard->modstate &= ~modifier;
772 /* Post the event, if desired */
774 if (SDL_GetEventState(type) == SDL_ENABLE) {
776 event.key.type = type;
777 event.key.state = state;
778 event.key.repeat = repeat;
779 event.key.keysym.scancode = scancode;
780 event.key.keysym.sym = keycode;
781 event.key.keysym.mod = keyboard->modstate;
782 event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
783 posted = (SDL_PushEvent(&event) > 0);
789 SDL_SendKeyboardText(const char *text)
791 SDL_Keyboard *keyboard = &SDL_keyboard;
794 /* Don't post text events for unprintable characters */
795 if ((unsigned char)*text < ' ' || *text == 127) {
799 /* Post the event, if desired */
801 if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
803 event.text.type = SDL_TEXTINPUT;
804 event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
805 SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
806 posted = (SDL_PushEvent(&event) > 0);
812 SDL_SendEditingText(const char *text, int start, int length)
814 SDL_Keyboard *keyboard = &SDL_keyboard;
817 /* Post the event, if desired */
819 if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
821 event.edit.type = SDL_TEXTEDITING;
822 event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
823 event.edit.start = start;
824 event.edit.length = length;
825 SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
826 posted = (SDL_PushEvent(&event) > 0);
832 SDL_KeyboardQuit(void)
837 SDL_GetKeyboardState(int *numkeys)
839 SDL_Keyboard *keyboard = &SDL_keyboard;
841 if (numkeys != (int *) 0) {
842 *numkeys = SDL_NUM_SCANCODES;
844 return keyboard->keystate;
848 SDL_GetModState(void)
850 SDL_Keyboard *keyboard = &SDL_keyboard;
852 return (SDL_Keymod) keyboard->modstate;
856 SDL_SetModState(SDL_Keymod modstate)
858 SDL_Keyboard *keyboard = &SDL_keyboard;
860 keyboard->modstate = modstate;
863 /* Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is. */
865 SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
867 SDL_Keyboard *keyboard = &SDL_keyboard;
869 keyboard->modstate |= modstate;
871 keyboard->modstate &= ~modstate;
877 SDL_GetKeyFromScancode(SDL_Scancode scancode)
879 SDL_Keyboard *keyboard = &SDL_keyboard;
881 if (((int)scancode) < ((int)SDL_SCANCODE_UNKNOWN) || scancode >= SDL_NUM_SCANCODES) {
882 SDL_InvalidParamError("scancode");
886 return keyboard->keymap[scancode];
890 SDL_GetScancodeFromKey(SDL_Keycode key)
892 SDL_Keyboard *keyboard = &SDL_keyboard;
893 SDL_Scancode scancode;
895 for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
897 if (keyboard->keymap[scancode] == key) {
901 return SDL_SCANCODE_UNKNOWN;
905 SDL_GetScancodeName(SDL_Scancode scancode)
908 if (((int)scancode) < ((int)SDL_SCANCODE_UNKNOWN) || scancode >= SDL_NUM_SCANCODES) {
909 SDL_InvalidParamError("scancode");
913 name = SDL_scancode_names[scancode];
920 SDL_Scancode SDL_GetScancodeFromName(const char *name)
924 if (!name || !*name) {
925 SDL_InvalidParamError("name");
926 return SDL_SCANCODE_UNKNOWN;
929 for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
930 if (!SDL_scancode_names[i]) {
933 if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
934 return (SDL_Scancode)i;
938 SDL_InvalidParamError("name");
939 return SDL_SCANCODE_UNKNOWN;
943 SDL_GetKeyName(SDL_Keycode key)
948 if (key & SDLK_SCANCODE_MASK) {
950 SDL_GetScancodeName((SDL_Scancode) (key & ~SDLK_SCANCODE_MASK));
955 return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
957 return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
959 return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
961 return SDL_GetScancodeName(SDL_SCANCODE_TAB);
963 return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
965 return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
967 /* Unaccented letter keys on latin keyboards are normally
968 labeled in upper case (and probably on others like Greek or
969 Cyrillic too, so if you happen to know for sure, please
971 if (key >= 'a' && key <= 'z') {
975 end = SDL_UCS4ToUTF8((Uint32) key, name);
982 SDL_GetKeyFromName(const char *name)
991 /* If it's a single UTF-8 character, then that's the keycode itself */
992 key = *(const unsigned char *)name;
994 if (SDL_strlen(name) == 4) {
996 key = (Uint16)(name[i]&0x07) << 18;
997 key |= (Uint16)(name[++i]&0x3F) << 12;
998 key |= (Uint16)(name[++i]&0x3F) << 6;
999 key |= (Uint16)(name[++i]&0x3F);
1002 return SDLK_UNKNOWN;
1003 } else if (key >= 0xE0) {
1004 if (SDL_strlen(name) == 3) {
1006 key = (Uint16)(name[i]&0x0F) << 12;
1007 key |= (Uint16)(name[++i]&0x3F) << 6;
1008 key |= (Uint16)(name[++i]&0x3F);
1011 return SDLK_UNKNOWN;
1012 } else if (key >= 0xC0) {
1013 if (SDL_strlen(name) == 2) {
1015 key = (Uint16)(name[i]&0x1F) << 6;
1016 key |= (Uint16)(name[++i]&0x3F);
1019 return SDLK_UNKNOWN;
1021 if (SDL_strlen(name) == 1) {
1022 if (key >= 'A' && key <= 'Z') {
1028 /* Get the scancode for this name, and the associated keycode */
1029 return SDL_default_keymap[SDL_GetScancodeFromName(name)];
1033 /* vi: set ts=4 sw=4 expandtab: */