1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 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_hints.h"
26#include "SDL_timer.h"
27#include "SDL_events.h"
28#include "SDL_events_c.h"
29#include "../video/SDL_sysvideo.h"
30
31
32/* #define DEBUG_KEYBOARD */
33
34/* Global keyboard information */
35
36#define KEYBOARD_HARDWARE 0x01
37#define KEYBOARD_AUTORELEASE 0x02
38
39typedef struct SDL_Keyboard SDL_Keyboard;
40
41struct SDL_Keyboard
42{
43 /* Data common to all keyboards */
44 SDL_Window *focus;
45 Uint16 modstate;
46 Uint8 keysource[SDL_NUM_SCANCODES];
47 Uint8 keystate[SDL_NUM_SCANCODES];
48 SDL_Keycode keymap[SDL_NUM_SCANCODES];
49 SDL_bool autorelease_pending;
50};
51
52static SDL_Keyboard SDL_keyboard;
53
54static const SDL_Keycode SDL_default_keymap[SDL_NUM_SCANCODES] = {
55 0, 0, 0, 0,
56 'a',
57 'b',
58 'c',
59 'd',
60 'e',
61 'f',
62 'g',
63 'h',
64 'i',
65 'j',
66 'k',
67 'l',
68 'm',
69 'n',
70 'o',
71 'p',
72 'q',
73 'r',
74 's',
75 't',
76 'u',
77 'v',
78 'w',
79 'x',
80 'y',
81 'z',
82 '1',
83 '2',
84 '3',
85 '4',
86 '5',
87 '6',
88 '7',
89 '8',
90 '9',
91 '0',
92 SDLK_RETURN,
93 SDLK_ESCAPE,
94 SDLK_BACKSPACE,
95 SDLK_TAB,
96 SDLK_SPACE,
97 '-',
98 '=',
99 '[',
100 ']',
101 '\\',
102 '#',
103 ';',
104 '\'',
105 '`',
106 ',',
107 '.',
108 '/',
109 SDLK_CAPSLOCK,
110 SDLK_F1,
111 SDLK_F2,
112 SDLK_F3,
113 SDLK_F4,
114 SDLK_F5,
115 SDLK_F6,
116 SDLK_F7,
117 SDLK_F8,
118 SDLK_F9,
119 SDLK_F10,
120 SDLK_F11,
121 SDLK_F12,
122 SDLK_PRINTSCREEN,
123 SDLK_SCROLLLOCK,
124 SDLK_PAUSE,
125 SDLK_INSERT,
126 SDLK_HOME,
127 SDLK_PAGEUP,
128 SDLK_DELETE,
129 SDLK_END,
130 SDLK_PAGEDOWN,
131 SDLK_RIGHT,
132 SDLK_LEFT,
133 SDLK_DOWN,
134 SDLK_UP,
135 SDLK_NUMLOCKCLEAR,
136 SDLK_KP_DIVIDE,
137 SDLK_KP_MULTIPLY,
138 SDLK_KP_MINUS,
139 SDLK_KP_PLUS,
140 SDLK_KP_ENTER,
141 SDLK_KP_1,
142 SDLK_KP_2,
143 SDLK_KP_3,
144 SDLK_KP_4,
145 SDLK_KP_5,
146 SDLK_KP_6,
147 SDLK_KP_7,
148 SDLK_KP_8,
149 SDLK_KP_9,
150 SDLK_KP_0,
151 SDLK_KP_PERIOD,
152 0,
153 SDLK_APPLICATION,
154 SDLK_POWER,
155 SDLK_KP_EQUALS,
156 SDLK_F13,
157 SDLK_F14,
158 SDLK_F15,
159 SDLK_F16,
160 SDLK_F17,
161 SDLK_F18,
162 SDLK_F19,
163 SDLK_F20,
164 SDLK_F21,
165 SDLK_F22,
166 SDLK_F23,
167 SDLK_F24,
168 SDLK_EXECUTE,
169 SDLK_HELP,
170 SDLK_MENU,
171 SDLK_SELECT,
172 SDLK_STOP,
173 SDLK_AGAIN,
174 SDLK_UNDO,
175 SDLK_CUT,
176 SDLK_COPY,
177 SDLK_PASTE,
178 SDLK_FIND,
179 SDLK_MUTE,
180 SDLK_VOLUMEUP,
181 SDLK_VOLUMEDOWN,
182 0, 0, 0,
183 SDLK_KP_COMMA,
184 SDLK_KP_EQUALSAS400,
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
186 SDLK_ALTERASE,
187 SDLK_SYSREQ,
188 SDLK_CANCEL,
189 SDLK_CLEAR,
190 SDLK_PRIOR,
191 SDLK_RETURN2,
192 SDLK_SEPARATOR,
193 SDLK_OUT,
194 SDLK_OPER,
195 SDLK_CLEARAGAIN,
196 SDLK_CRSEL,
197 SDLK_EXSEL,
198 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
199 SDLK_KP_00,
200 SDLK_KP_000,
201 SDLK_THOUSANDSSEPARATOR,
202 SDLK_DECIMALSEPARATOR,
203 SDLK_CURRENCYUNIT,
204 SDLK_CURRENCYSUBUNIT,
205 SDLK_KP_LEFTPAREN,
206 SDLK_KP_RIGHTPAREN,
207 SDLK_KP_LEFTBRACE,
208 SDLK_KP_RIGHTBRACE,
209 SDLK_KP_TAB,
210 SDLK_KP_BACKSPACE,
211 SDLK_KP_A,
212 SDLK_KP_B,
213 SDLK_KP_C,
214 SDLK_KP_D,
215 SDLK_KP_E,
216 SDLK_KP_F,
217 SDLK_KP_XOR,
218 SDLK_KP_POWER,
219 SDLK_KP_PERCENT,
220 SDLK_KP_LESS,
221 SDLK_KP_GREATER,
222 SDLK_KP_AMPERSAND,
223 SDLK_KP_DBLAMPERSAND,
224 SDLK_KP_VERTICALBAR,
225 SDLK_KP_DBLVERTICALBAR,
226 SDLK_KP_COLON,
227 SDLK_KP_HASH,
228 SDLK_KP_SPACE,
229 SDLK_KP_AT,
230 SDLK_KP_EXCLAM,
231 SDLK_KP_MEMSTORE,
232 SDLK_KP_MEMRECALL,
233 SDLK_KP_MEMCLEAR,
234 SDLK_KP_MEMADD,
235 SDLK_KP_MEMSUBTRACT,
236 SDLK_KP_MEMMULTIPLY,
237 SDLK_KP_MEMDIVIDE,
238 SDLK_KP_PLUSMINUS,
239 SDLK_KP_CLEAR,
240 SDLK_KP_CLEARENTRY,
241 SDLK_KP_BINARY,
242 SDLK_KP_OCTAL,
243 SDLK_KP_DECIMAL,
244 SDLK_KP_HEXADECIMAL,
245 0, 0,
246 SDLK_LCTRL,
247 SDLK_LSHIFT,
248 SDLK_LALT,
249 SDLK_LGUI,
250 SDLK_RCTRL,
251 SDLK_RSHIFT,
252 SDLK_RALT,
253 SDLK_RGUI,
254 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,
255 SDLK_MODE,
256 SDLK_AUDIONEXT,
257 SDLK_AUDIOPREV,
258 SDLK_AUDIOSTOP,
259 SDLK_AUDIOPLAY,
260 SDLK_AUDIOMUTE,
261 SDLK_MEDIASELECT,
262 SDLK_WWW,
263 SDLK_MAIL,
264 SDLK_CALCULATOR,
265 SDLK_COMPUTER,
266 SDLK_AC_SEARCH,
267 SDLK_AC_HOME,
268 SDLK_AC_BACK,
269 SDLK_AC_FORWARD,
270 SDLK_AC_STOP,
271 SDLK_AC_REFRESH,
272 SDLK_AC_BOOKMARKS,
273 SDLK_BRIGHTNESSDOWN,
274 SDLK_BRIGHTNESSUP,
275 SDLK_DISPLAYSWITCH,
276 SDLK_KBDILLUMTOGGLE,
277 SDLK_KBDILLUMDOWN,
278 SDLK_KBDILLUMUP,
279 SDLK_EJECT,
280 SDLK_SLEEP,
281 SDLK_APP1,
282 SDLK_APP2,
283 SDLK_AUDIOREWIND,
284 SDLK_AUDIOFASTFORWARD,
285};
286
287static const char *SDL_scancode_names[SDL_NUM_SCANCODES] = {
288 NULL, NULL, NULL, NULL,
289 "A",
290 "B",
291 "C",
292 "D",
293 "E",
294 "F",
295 "G",
296 "H",
297 "I",
298 "J",
299 "K",
300 "L",
301 "M",
302 "N",
303 "O",
304 "P",
305 "Q",
306 "R",
307 "S",
308 "T",
309 "U",
310 "V",
311 "W",
312 "X",
313 "Y",
314 "Z",
315 "1",
316 "2",
317 "3",
318 "4",
319 "5",
320 "6",
321 "7",
322 "8",
323 "9",
324 "0",
325 "Return",
326 "Escape",
327 "Backspace",
328 "Tab",
329 "Space",
330 "-",
331 "=",
332 "[",
333 "]",
334 "\\",
335 "#",
336 ";",
337 "'",
338 "`",
339 ",",
340 ".",
341 "/",
342 "CapsLock",
343 "F1",
344 "F2",
345 "F3",
346 "F4",
347 "F5",
348 "F6",
349 "F7",
350 "F8",
351 "F9",
352 "F10",
353 "F11",
354 "F12",
355 "PrintScreen",
356 "ScrollLock",
357 "Pause",
358 "Insert",
359 "Home",
360 "PageUp",
361 "Delete",
362 "End",
363 "PageDown",
364 "Right",
365 "Left",
366 "Down",
367 "Up",
368 "Numlock",
369 "Keypad /",
370 "Keypad *",
371 "Keypad -",
372 "Keypad +",
373 "Keypad Enter",
374 "Keypad 1",
375 "Keypad 2",
376 "Keypad 3",
377 "Keypad 4",
378 "Keypad 5",
379 "Keypad 6",
380 "Keypad 7",
381 "Keypad 8",
382 "Keypad 9",
383 "Keypad 0",
384 "Keypad .",
385 NULL,
386 "Application",
387 "Power",
388 "Keypad =",
389 "F13",
390 "F14",
391 "F15",
392 "F16",
393 "F17",
394 "F18",
395 "F19",
396 "F20",
397 "F21",
398 "F22",
399 "F23",
400 "F24",
401 "Execute",
402 "Help",
403 "Menu",
404 "Select",
405 "Stop",
406 "Again",
407 "Undo",
408 "Cut",
409 "Copy",
410 "Paste",
411 "Find",
412 "Mute",
413 "VolumeUp",
414 "VolumeDown",
415 NULL, NULL, NULL,
416 "Keypad ,",
417 "Keypad = (AS400)",
418 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
419 NULL, NULL, NULL, NULL, NULL, NULL,
420 "AltErase",
421 "SysReq",
422 "Cancel",
423 "Clear",
424 "Prior",
425 "Return",
426 "Separator",
427 "Out",
428 "Oper",
429 "Clear / Again",
430 "CrSel",
431 "ExSel",
432 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
433 "Keypad 00",
434 "Keypad 000",
435 "ThousandsSeparator",
436 "DecimalSeparator",
437 "CurrencyUnit",
438 "CurrencySubUnit",
439 "Keypad (",
440 "Keypad )",
441 "Keypad {",
442 "Keypad }",
443 "Keypad Tab",
444 "Keypad Backspace",
445 "Keypad A",
446 "Keypad B",
447 "Keypad C",
448 "Keypad D",
449 "Keypad E",
450 "Keypad F",
451 "Keypad XOR",
452 "Keypad ^",
453 "Keypad %",
454 "Keypad <",
455 "Keypad >",
456 "Keypad &",
457 "Keypad &&",
458 "Keypad |",
459 "Keypad ||",
460 "Keypad :",
461 "Keypad #",
462 "Keypad Space",
463 "Keypad @",
464 "Keypad !",
465 "Keypad MemStore",
466 "Keypad MemRecall",
467 "Keypad MemClear",
468 "Keypad MemAdd",
469 "Keypad MemSubtract",
470 "Keypad MemMultiply",
471 "Keypad MemDivide",
472 "Keypad +/-",
473 "Keypad Clear",
474 "Keypad ClearEntry",
475 "Keypad Binary",
476 "Keypad Octal",
477 "Keypad Decimal",
478 "Keypad Hexadecimal",
479 NULL, NULL,
480 "Left Ctrl",
481 "Left Shift",
482 "Left Alt",
483 "Left GUI",
484 "Right Ctrl",
485 "Right Shift",
486 "Right Alt",
487 "Right GUI",
488 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
489 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
490 NULL,
491 "ModeSwitch",
492 "AudioNext",
493 "AudioPrev",
494 "AudioStop",
495 "AudioPlay",
496 "AudioMute",
497 "MediaSelect",
498 "WWW",
499 "Mail",
500 "Calculator",
501 "Computer",
502 "AC Search",
503 "AC Home",
504 "AC Back",
505 "AC Forward",
506 "AC Stop",
507 "AC Refresh",
508 "AC Bookmarks",
509 "BrightnessDown",
510 "BrightnessUp",
511 "DisplaySwitch",
512 "KBDIllumToggle",
513 "KBDIllumDown",
514 "KBDIllumUp",
515 "Eject",
516 "Sleep",
517 "App1",
518 "App2",
519 "AudioRewind",
520 "AudioFastForward",
521};
522
523/* Taken from SDL_iconv() */
524char *
525SDL_UCS4ToUTF8(Uint32 ch, char *dst)
526{
527 Uint8 *p = (Uint8 *) dst;
528 if (ch <= 0x7F) {
529 *p = (Uint8) ch;
530 ++dst;
531 } else if (ch <= 0x7FF) {
532 p[0] = 0xC0 | (Uint8) ((ch >> 6) & 0x1F);
533 p[1] = 0x80 | (Uint8) (ch & 0x3F);
534 dst += 2;
535 } else if (ch <= 0xFFFF) {
536 p[0] = 0xE0 | (Uint8) ((ch >> 12) & 0x0F);
537 p[1] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
538 p[2] = 0x80 | (Uint8) (ch & 0x3F);
539 dst += 3;
540 } else {
541 p[0] = 0xF0 | (Uint8) ((ch >> 18) & 0x07);
542 p[1] = 0x80 | (Uint8) ((ch >> 12) & 0x3F);
543 p[2] = 0x80 | (Uint8) ((ch >> 6) & 0x3F);
544 p[3] = 0x80 | (Uint8) (ch & 0x3F);
545 dst += 4;
546 }
547 return dst;
548}
549
550/* Public functions */
551int
552SDL_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
561void
562SDL_ResetKeyboard(void)
563{
564 SDL_Keyboard *keyboard = &SDL_keyboard;
565 SDL_Scancode scancode;
566
567#ifdef DEBUG_KEYBOARD
568 printf("Resetting keyboard\n");
569#endif
570 for (scancode = (SDL_Scancode) 0; scancode < SDL_NUM_SCANCODES; ++scancode) {
571 if (keyboard->keystate[scancode] == SDL_PRESSED) {
572 SDL_SendKeyboardKey(SDL_RELEASED, scancode);
573 }
574 }
575}
576
577void
578SDL_GetDefaultKeymap(SDL_Keycode * keymap)
579{
580 SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap));
581}
582
583void
584SDL_SetKeymap(int start, SDL_Keycode * keys, int length)
585{
586 SDL_Keyboard *keyboard = &SDL_keyboard;
587 SDL_Scancode scancode;
588
589 if (start < 0 || start + length > SDL_NUM_SCANCODES) {
590 return;
591 }
592
593 SDL_memcpy(&keyboard->keymap[start], keys, sizeof(*keys) * length);
594
595 /* The number key scancodes always map to the number key keycodes.
596 * On AZERTY layouts these technically are symbols, but users (and games)
597 * always think of them and view them in UI as number keys.
598 */
599 keyboard->keymap[SDL_SCANCODE_0] = SDLK_0;
600 for (scancode = SDL_SCANCODE_1; scancode <= SDL_SCANCODE_9; ++scancode) {
601 keyboard->keymap[scancode] = SDLK_1 + (scancode - SDL_SCANCODE_1);
602 }
603}
604
605void
606SDL_SetScancodeName(SDL_Scancode scancode, const char *name)
607{
608 SDL_scancode_names[scancode] = name;
609}
610
611SDL_Window *
612SDL_GetKeyboardFocus(void)
613{
614 SDL_Keyboard *keyboard = &SDL_keyboard;
615
616 return keyboard->focus;
617}
618
619void
620SDL_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
668static int
669SDL_SendKeyboardKeyInternal(Uint8 source, 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 = SDL_FALSE;
677
678 if (scancode == SDL_SCANCODE_UNKNOWN) {
679 return 0;
680 }
681
682#ifdef DEBUG_KEYBOARD
683 printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode),
684 state == SDL_PRESSED ? "pressed" : "released");
685#endif
686
687 /* Figure out what type of event this is */
688 switch (state) {
689 case SDL_PRESSED:
690 type = SDL_KEYDOWN;
691 break;
692 case SDL_RELEASED:
693 type = SDL_KEYUP;
694 break;
695 default:
696 /* Invalid state -- bail */
697 return 0;
698 }
699
700 /* Drop events that don't change state */
701 if (state) {
702 if (keyboard->keystate[scancode]) {
703 if (!(keyboard->keysource[scancode] & source)) {
704 keyboard->keysource[scancode] |= source;
705 return 0;
706 }
707 repeat = SDL_TRUE;
708 }
709 keyboard->keysource[scancode] |= source;
710 } else {
711 if (!keyboard->keystate[scancode]) {
712 return 0;
713 }
714 keyboard->keysource[scancode] = 0;
715 }
716
717 /* Update internal keyboard state */
718 keyboard->keystate[scancode] = state;
719
720 keycode = keyboard->keymap[scancode];
721
722 if (source == KEYBOARD_AUTORELEASE) {
723 keyboard->autorelease_pending = SDL_TRUE;
724 }
725
726 /* Update modifiers state if applicable */
727 switch (keycode) {
728 case SDLK_LCTRL:
729 modifier = KMOD_LCTRL;
730 break;
731 case SDLK_RCTRL:
732 modifier = KMOD_RCTRL;
733 break;
734 case SDLK_LSHIFT:
735 modifier = KMOD_LSHIFT;
736 break;
737 case SDLK_RSHIFT:
738 modifier = KMOD_RSHIFT;
739 break;
740 case SDLK_LALT:
741 modifier = KMOD_LALT;
742 break;
743 case SDLK_RALT:
744 modifier = KMOD_RALT;
745 break;
746 case SDLK_LGUI:
747 modifier = KMOD_LGUI;
748 break;
749 case SDLK_RGUI:
750 modifier = KMOD_RGUI;
751 break;
752 case SDLK_MODE:
753 modifier = KMOD_MODE;
754 break;
755 default:
756 modifier = KMOD_NONE;
757 break;
758 }
759 if (SDL_KEYDOWN == type) {
760 switch (keycode) {
761 case SDLK_NUMLOCKCLEAR:
762 keyboard->modstate ^= KMOD_NUM;
763 break;
764 case SDLK_CAPSLOCK:
765 keyboard->modstate ^= KMOD_CAPS;
766 break;
767 default:
768 keyboard->modstate |= modifier;
769 break;
770 }
771 } else {
772 keyboard->modstate &= ~modifier;
773 }
774
775 /* Post the event, if desired */
776 posted = 0;
777 if (SDL_GetEventState(type) == SDL_ENABLE) {
778 SDL_Event event;
779 event.key.type = type;
780 event.key.state = state;
781 event.key.repeat = repeat;
782 event.key.keysym.scancode = scancode;
783 event.key.keysym.sym = keycode;
784 event.key.keysym.mod = keyboard->modstate;
785 event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
786 posted = (SDL_PushEvent(&event) > 0);
787 }
788
789 /* If the keyboard is grabbed and the grabbed window is in full-screen,
790 minimize the window when we receive Alt+Tab, unless the application
791 has explicitly opted out of this behavior. */
792 if (keycode == SDLK_TAB &&
793 state == SDL_PRESSED &&
794 (keyboard->modstate & KMOD_ALT) &&
795 keyboard->focus &&
796 (keyboard->focus->flags & SDL_WINDOW_KEYBOARD_GRABBED) &&
797 (keyboard->focus->flags & SDL_WINDOW_FULLSCREEN) &&
798 SDL_GetHintBoolean(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, SDL_TRUE)) {
799 /* We will temporarily forfeit our grab by minimizing our window,
800 allowing the user to escape the application */
801 SDL_MinimizeWindow(keyboard->focus);
802 }
803
804 return (posted);
805}
806
807int
808SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
809{
810 return SDL_SendKeyboardKeyInternal(KEYBOARD_HARDWARE, state, scancode);
811}
812
813int
814SDL_SendKeyboardKeyAutoRelease(SDL_Scancode scancode)
815{
816 return SDL_SendKeyboardKeyInternal(KEYBOARD_AUTORELEASE, SDL_PRESSED, scancode);
817}
818
819void
820SDL_ReleaseAutoReleaseKeys(void)
821{
822 SDL_Keyboard *keyboard = &SDL_keyboard;
823 SDL_Scancode scancode;
824
825 if (keyboard->autorelease_pending) {
826 for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
827 if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) {
828 SDL_SendKeyboardKeyInternal(KEYBOARD_AUTORELEASE, SDL_RELEASED, scancode);
829 }
830 }
831 keyboard->autorelease_pending = SDL_FALSE;
832 }
833}
834
835SDL_bool
836SDL_HardwareKeyboardKeyPressed(void)
837{
838 SDL_Keyboard *keyboard = &SDL_keyboard;
839 SDL_Scancode scancode;
840
841 for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES; ++scancode) {
842 if ((keyboard->keysource[scancode] & KEYBOARD_HARDWARE) != 0) {
843 return SDL_TRUE;
844 }
845 }
846 return SDL_FALSE;
847}
848
849int
850SDL_SendKeyboardText(const char *text)
851{
852 SDL_Keyboard *keyboard = &SDL_keyboard;
853 int posted;
854
855 /* Don't post text events for unprintable characters */
856 if ((unsigned char)*text < ' ' || *text == 127) {
857 return 0;
858 }
859
860 /* Post the event, if desired */
861 posted = 0;
862 if (SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE) {
863 SDL_Event event;
864 event.text.type = SDL_TEXTINPUT;
865 event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
866 SDL_utf8strlcpy(event.text.text, text, SDL_arraysize(event.text.text));
867 posted = (SDL_PushEvent(&event) > 0);
868 }
869 return (posted);
870}
871
872int
873SDL_SendEditingText(const char *text, int start, int length)
874{
875 SDL_Keyboard *keyboard = &SDL_keyboard;
876 int posted;
877
878 /* Post the event, if desired */
879 posted = 0;
880 if (SDL_GetEventState(SDL_TEXTEDITING) == SDL_ENABLE) {
881 SDL_Event event;
882 event.edit.type = SDL_TEXTEDITING;
883 event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
884 event.edit.start = start;
885 event.edit.length = length;
886 SDL_utf8strlcpy(event.edit.text, text, SDL_arraysize(event.edit.text));
887 posted = (SDL_PushEvent(&event) > 0);
888 }
889 return (posted);
890}
891
892void
893SDL_KeyboardQuit(void)
894{
895}
896
897const Uint8 *
898SDL_GetKeyboardState(int *numkeys)
899{
900 SDL_Keyboard *keyboard = &SDL_keyboard;
901
902 if (numkeys != (int *) 0) {
903 *numkeys = SDL_NUM_SCANCODES;
904 }
905 return keyboard->keystate;
906}
907
908SDL_Keymod
909SDL_GetModState(void)
910{
911 SDL_Keyboard *keyboard = &SDL_keyboard;
912
913 return (SDL_Keymod) keyboard->modstate;
914}
915
916void
917SDL_SetModState(SDL_Keymod modstate)
918{
919 SDL_Keyboard *keyboard = &SDL_keyboard;
920
921 keyboard->modstate = modstate;
922}
923
924/* Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is. */
925void
926SDL_ToggleModState(const SDL_Keymod modstate, const SDL_bool toggle)
927{
928 SDL_Keyboard *keyboard = &SDL_keyboard;
929 if (toggle) {
930 keyboard->modstate |= modstate;
931 } else {
932 keyboard->modstate &= ~modstate;
933 }
934}
935
936
937SDL_Keycode
938SDL_GetKeyFromScancode(SDL_Scancode scancode)
939{
940 SDL_Keyboard *keyboard = &SDL_keyboard;
941
942 if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
943 SDL_InvalidParamError("scancode");
944 return 0;
945 }
946
947 return keyboard->keymap[scancode];
948}
949
950SDL_Scancode
951SDL_GetScancodeFromKey(SDL_Keycode key)
952{
953 SDL_Keyboard *keyboard = &SDL_keyboard;
954 SDL_Scancode scancode;
955
956 for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_NUM_SCANCODES;
957 ++scancode) {
958 if (keyboard->keymap[scancode] == key) {
959 return scancode;
960 }
961 }
962 return SDL_SCANCODE_UNKNOWN;
963}
964
965const char *
966SDL_GetScancodeName(SDL_Scancode scancode)
967{
968 const char *name;
969 if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
970 SDL_InvalidParamError("scancode");
971 return "";
972 }
973
974 name = SDL_scancode_names[scancode];
975 if (name)
976 return name;
977 else
978 return "";
979}
980
981SDL_Scancode SDL_GetScancodeFromName(const char *name)
982{
983 int i;
984
985 if (!name || !*name) {
986 SDL_InvalidParamError("name");
987 return SDL_SCANCODE_UNKNOWN;
988 }
989
990 for (i = 0; i < SDL_arraysize(SDL_scancode_names); ++i) {
991 if (!SDL_scancode_names[i]) {
992 continue;
993 }
994 if (SDL_strcasecmp(name, SDL_scancode_names[i]) == 0) {
995 return (SDL_Scancode)i;
996 }
997 }
998
999 SDL_InvalidParamError("name");
1000 return SDL_SCANCODE_UNKNOWN;
1001}
1002
1003const char *
1004SDL_GetKeyName(SDL_Keycode key)
1005{
1006 static char name[8];
1007 char *end;
1008
1009 if (key & SDLK_SCANCODE_MASK) {
1010 return
1011 SDL_GetScancodeName((SDL_Scancode) (key & ~SDLK_SCANCODE_MASK));
1012 }
1013
1014 switch (key) {
1015 case SDLK_RETURN:
1016 return SDL_GetScancodeName(SDL_SCANCODE_RETURN);
1017 case SDLK_ESCAPE:
1018 return SDL_GetScancodeName(SDL_SCANCODE_ESCAPE);
1019 case SDLK_BACKSPACE:
1020 return SDL_GetScancodeName(SDL_SCANCODE_BACKSPACE);
1021 case SDLK_TAB:
1022 return SDL_GetScancodeName(SDL_SCANCODE_TAB);
1023 case SDLK_SPACE:
1024 return SDL_GetScancodeName(SDL_SCANCODE_SPACE);
1025 case SDLK_DELETE:
1026 return SDL_GetScancodeName(SDL_SCANCODE_DELETE);
1027 default:
1028 /* Unaccented letter keys on latin keyboards are normally
1029 labeled in upper case (and probably on others like Greek or
1030 Cyrillic too, so if you happen to know for sure, please
1031 adapt this). */
1032 if (key >= 'a' && key <= 'z') {
1033 key -= 32;
1034 }
1035
1036 end = SDL_UCS4ToUTF8((Uint32) key, name);
1037 *end = '\0';
1038 return name;
1039 }
1040}
1041
1042SDL_Keycode
1043SDL_GetKeyFromName(const char *name)
1044{
1045 SDL_Keycode key;
1046
1047 /* Check input */
1048 if (name == NULL) {
1049 return SDLK_UNKNOWN;
1050 }
1051
1052 /* If it's a single UTF-8 character, then that's the keycode itself */
1053 key = *(const unsigned char *)name;
1054 if (key >= 0xF0) {
1055 if (SDL_strlen(name) == 4) {
1056 int i = 0;
1057 key = (Uint16)(name[i]&0x07) << 18;
1058 key |= (Uint16)(name[++i]&0x3F) << 12;
1059 key |= (Uint16)(name[++i]&0x3F) << 6;
1060 key |= (Uint16)(name[++i]&0x3F);
1061 return key;
1062 }
1063 return SDLK_UNKNOWN;
1064 } else if (key >= 0xE0) {
1065 if (SDL_strlen(name) == 3) {
1066 int i = 0;
1067 key = (Uint16)(name[i]&0x0F) << 12;
1068 key |= (Uint16)(name[++i]&0x3F) << 6;
1069 key |= (Uint16)(name[++i]&0x3F);
1070 return key;
1071 }
1072 return SDLK_UNKNOWN;
1073 } else if (key >= 0xC0) {
1074 if (SDL_strlen(name) == 2) {
1075 int i = 0;
1076 key = (Uint16)(name[i]&0x1F) << 6;
1077 key |= (Uint16)(name[++i]&0x3F);
1078 return key;
1079 }
1080 return SDLK_UNKNOWN;
1081 } else {
1082 if (SDL_strlen(name) == 1) {
1083 if (key >= 'A' && key <= 'Z') {
1084 key += 32;
1085 }
1086 return key;
1087 }
1088
1089 /* Get the scancode for this name, and the associated keycode */
1090 return SDL_default_keymap[SDL_GetScancodeFromName(name)];
1091 }
1092}
1093
1094/* vi: set ts=4 sw=4 expandtab: */
1095