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 | |
39 | typedef struct SDL_Keyboard SDL_Keyboard; |
40 | |
41 | struct 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 | |
52 | static SDL_Keyboard SDL_keyboard; |
53 | |
54 | static 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 | |
287 | static 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() */ |
524 | char * |
525 | SDL_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 */ |
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 | #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 | |
577 | void |
578 | SDL_GetDefaultKeymap(SDL_Keycode * keymap) |
579 | { |
580 | SDL_memcpy(keymap, SDL_default_keymap, sizeof(SDL_default_keymap)); |
581 | } |
582 | |
583 | void |
584 | SDL_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 | |
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 | static int |
669 | SDL_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 | |
807 | int |
808 | SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode) |
809 | { |
810 | return SDL_SendKeyboardKeyInternal(KEYBOARD_HARDWARE, state, scancode); |
811 | } |
812 | |
813 | int |
814 | SDL_SendKeyboardKeyAutoRelease(SDL_Scancode scancode) |
815 | { |
816 | return SDL_SendKeyboardKeyInternal(KEYBOARD_AUTORELEASE, SDL_PRESSED, scancode); |
817 | } |
818 | |
819 | void |
820 | SDL_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 | |
835 | SDL_bool |
836 | SDL_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 | |
849 | int |
850 | SDL_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 | |
872 | int |
873 | SDL_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 | |
892 | void |
893 | SDL_KeyboardQuit(void) |
894 | { |
895 | } |
896 | |
897 | const Uint8 * |
898 | SDL_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 | |
908 | SDL_Keymod |
909 | SDL_GetModState(void) |
910 | { |
911 | SDL_Keyboard *keyboard = &SDL_keyboard; |
912 | |
913 | return (SDL_Keymod) keyboard->modstate; |
914 | } |
915 | |
916 | void |
917 | SDL_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. */ |
925 | void |
926 | SDL_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 | |
937 | SDL_Keycode |
938 | SDL_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 | |
950 | SDL_Scancode |
951 | SDL_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 | |
965 | const char * |
966 | SDL_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 | |
981 | SDL_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 | |
1003 | const char * |
1004 | SDL_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 | |
1042 | SDL_Keycode |
1043 | SDL_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 | |