SDL_keyboard.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. // General keyboard handling code for SDL
  20. #include "SDL_events_c.h"
  21. #include "SDL_keymap_c.h"
  22. #include "../video/SDL_sysvideo.h"
  23. // #define DEBUG_KEYBOARD
  24. // Global keyboard information
  25. #define KEYBOARD_HARDWARE 0x01
  26. #define KEYBOARD_VIRTUAL 0x02
  27. #define KEYBOARD_AUTORELEASE 0x04
  28. #define KEYBOARD_IGNOREMODIFIERS 0x08
  29. #define KEYBOARD_SOURCE_MASK (KEYBOARD_HARDWARE | KEYBOARD_AUTORELEASE)
  30. #define KEYCODE_OPTION_HIDE_NUMPAD 0x01
  31. #define KEYCODE_OPTION_FRENCH_NUMBERS 0x02
  32. #define KEYCODE_OPTION_LATIN_LETTERS 0x04
  33. #define DEFAULT_KEYCODE_OPTIONS (KEYCODE_OPTION_FRENCH_NUMBERS | KEYCODE_OPTION_LATIN_LETTERS)
  34. typedef struct SDL_KeyboardInstance
  35. {
  36. SDL_KeyboardID instance_id;
  37. char *name;
  38. } SDL_KeyboardInstance;
  39. typedef struct SDL_Keyboard
  40. {
  41. // Data common to all keyboards
  42. SDL_Window *focus;
  43. SDL_Keymod modstate;
  44. Uint8 keysource[SDL_SCANCODE_COUNT];
  45. bool keystate[SDL_SCANCODE_COUNT];
  46. SDL_Keymap *keymap;
  47. bool french_numbers;
  48. bool latin_letters;
  49. bool thai_keyboard;
  50. Uint32 keycode_options;
  51. bool autorelease_pending;
  52. Uint64 hardware_timestamp;
  53. int next_reserved_scancode;
  54. } SDL_Keyboard;
  55. static SDL_Keyboard SDL_keyboard;
  56. static int SDL_keyboard_count;
  57. static SDL_KeyboardInstance *SDL_keyboards;
  58. static void SDLCALL SDL_KeycodeOptionsChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
  59. {
  60. SDL_Keyboard *keyboard = (SDL_Keyboard *)userdata;
  61. if (hint && *hint) {
  62. keyboard->keycode_options = 0;
  63. if (!SDL_strstr(hint, "none")) {
  64. if (SDL_strstr(hint, "hide_numpad")) {
  65. keyboard->keycode_options |= KEYCODE_OPTION_HIDE_NUMPAD;
  66. }
  67. if (SDL_strstr(hint, "french_numbers")) {
  68. keyboard->keycode_options |= KEYCODE_OPTION_FRENCH_NUMBERS;
  69. }
  70. if (SDL_strstr(hint, "latin_letters")) {
  71. keyboard->keycode_options |= KEYCODE_OPTION_LATIN_LETTERS;
  72. }
  73. }
  74. } else {
  75. keyboard->keycode_options = DEFAULT_KEYCODE_OPTIONS;
  76. }
  77. }
  78. // Public functions
  79. bool SDL_InitKeyboard(void)
  80. {
  81. SDL_AddHintCallback(SDL_HINT_KEYCODE_OPTIONS,
  82. SDL_KeycodeOptionsChanged, &SDL_keyboard);
  83. return true;
  84. }
  85. bool SDL_IsKeyboard(Uint16 vendor, Uint16 product, int num_keys)
  86. {
  87. const int REAL_KEYBOARD_KEY_COUNT = 50;
  88. if (num_keys > 0 && num_keys < REAL_KEYBOARD_KEY_COUNT) {
  89. return false;
  90. }
  91. // Eventually we'll have a blacklist of devices that enumerate as keyboards but aren't really
  92. return true;
  93. }
  94. static int SDL_GetKeyboardIndex(SDL_KeyboardID keyboardID)
  95. {
  96. for (int i = 0; i < SDL_keyboard_count; ++i) {
  97. if (keyboardID == SDL_keyboards[i].instance_id) {
  98. return i;
  99. }
  100. }
  101. return -1;
  102. }
  103. void SDL_AddKeyboard(SDL_KeyboardID keyboardID, const char *name, bool send_event)
  104. {
  105. int keyboard_index = SDL_GetKeyboardIndex(keyboardID);
  106. if (keyboard_index >= 0) {
  107. // We already know about this keyboard
  108. return;
  109. }
  110. SDL_assert(keyboardID != 0);
  111. SDL_KeyboardInstance *keyboards = (SDL_KeyboardInstance *)SDL_realloc(SDL_keyboards, (SDL_keyboard_count + 1) * sizeof(*keyboards));
  112. if (!keyboards) {
  113. return;
  114. }
  115. SDL_KeyboardInstance *instance = &keyboards[SDL_keyboard_count];
  116. instance->instance_id = keyboardID;
  117. instance->name = SDL_strdup(name ? name : "");
  118. SDL_keyboards = keyboards;
  119. ++SDL_keyboard_count;
  120. if (send_event) {
  121. SDL_Event event;
  122. SDL_zero(event);
  123. event.type = SDL_EVENT_KEYBOARD_ADDED;
  124. event.kdevice.which = keyboardID;
  125. SDL_PushEvent(&event);
  126. }
  127. }
  128. void SDL_RemoveKeyboard(SDL_KeyboardID keyboardID, bool send_event)
  129. {
  130. int keyboard_index = SDL_GetKeyboardIndex(keyboardID);
  131. if (keyboard_index < 0) {
  132. // We don't know about this keyboard
  133. return;
  134. }
  135. SDL_free(SDL_keyboards[keyboard_index].name);
  136. if (keyboard_index != SDL_keyboard_count - 1) {
  137. SDL_memcpy(&SDL_keyboards[keyboard_index], &SDL_keyboards[keyboard_index + 1], (SDL_keyboard_count - keyboard_index - 1) * sizeof(SDL_keyboards[keyboard_index]));
  138. }
  139. --SDL_keyboard_count;
  140. if (send_event) {
  141. SDL_Event event;
  142. SDL_zero(event);
  143. event.type = SDL_EVENT_KEYBOARD_REMOVED;
  144. event.kdevice.which = keyboardID;
  145. SDL_PushEvent(&event);
  146. }
  147. }
  148. bool SDL_HasKeyboard(void)
  149. {
  150. return (SDL_keyboard_count > 0);
  151. }
  152. SDL_KeyboardID *SDL_GetKeyboards(int *count)
  153. {
  154. int i;
  155. SDL_KeyboardID *keyboards;
  156. keyboards = (SDL_JoystickID *)SDL_malloc((SDL_keyboard_count + 1) * sizeof(*keyboards));
  157. if (keyboards) {
  158. if (count) {
  159. *count = SDL_keyboard_count;
  160. }
  161. for (i = 0; i < SDL_keyboard_count; ++i) {
  162. keyboards[i] = SDL_keyboards[i].instance_id;
  163. }
  164. keyboards[i] = 0;
  165. } else {
  166. if (count) {
  167. *count = 0;
  168. }
  169. }
  170. return keyboards;
  171. }
  172. const char *SDL_GetKeyboardNameForID(SDL_KeyboardID instance_id)
  173. {
  174. int keyboard_index = SDL_GetKeyboardIndex(instance_id);
  175. if (keyboard_index < 0) {
  176. return NULL;
  177. }
  178. return SDL_GetPersistentString(SDL_keyboards[keyboard_index].name);
  179. }
  180. void SDL_ResetKeyboard(void)
  181. {
  182. SDL_Keyboard *keyboard = &SDL_keyboard;
  183. int scancode;
  184. #ifdef DEBUG_KEYBOARD
  185. printf("Resetting keyboard\n");
  186. #endif
  187. for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) {
  188. if (keyboard->keystate[scancode]) {
  189. SDL_SendKeyboardKey(0, SDL_GLOBAL_KEYBOARD_ID, 0, (SDL_Scancode)scancode, false);
  190. }
  191. }
  192. }
  193. SDL_Keymap *SDL_GetCurrentKeymap(void)
  194. {
  195. SDL_Keyboard *keyboard = &SDL_keyboard;
  196. if (keyboard->thai_keyboard) {
  197. // Thai keyboards are QWERTY plus Thai characters, use the default QWERTY keymap
  198. return NULL;
  199. }
  200. if ((keyboard->keycode_options & KEYCODE_OPTION_LATIN_LETTERS) &&
  201. !keyboard->latin_letters) {
  202. // We'll use the default QWERTY keymap
  203. return NULL;
  204. }
  205. return keyboard->keymap;
  206. }
  207. void SDL_SetKeymap(SDL_Keymap *keymap, bool send_event)
  208. {
  209. SDL_Keyboard *keyboard = &SDL_keyboard;
  210. if (keyboard->keymap) {
  211. SDL_DestroyKeymap(keyboard->keymap);
  212. }
  213. keyboard->keymap = keymap;
  214. // Detect French number row (all symbols)
  215. keyboard->french_numbers = true;
  216. for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_0; ++i) {
  217. if (SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE)) ||
  218. !SDL_isdigit(SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_SHIFT))) {
  219. keyboard->french_numbers = false;
  220. break;
  221. }
  222. }
  223. // Detect non-Latin keymap
  224. keyboard->thai_keyboard = false;
  225. keyboard->latin_letters = false;
  226. for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_D; ++i) {
  227. SDL_Keycode key = SDL_GetKeymapKeycode(keymap, (SDL_Scancode)i, SDL_KMOD_NONE);
  228. if (key <= 0xFF) {
  229. keyboard->latin_letters = true;
  230. break;
  231. }
  232. if (key >= 0x0E00 && key <= 0x0E7F) {
  233. keyboard->thai_keyboard = true;
  234. break;
  235. }
  236. }
  237. if (send_event) {
  238. SDL_SendKeymapChangedEvent();
  239. }
  240. }
  241. static SDL_Scancode GetNextReservedScancode(void)
  242. {
  243. SDL_Keyboard *keyboard = &SDL_keyboard;
  244. SDL_Scancode scancode;
  245. if (keyboard->next_reserved_scancode && keyboard->next_reserved_scancode < SDL_SCANCODE_RESERVED + 100) {
  246. scancode = (SDL_Scancode)keyboard->next_reserved_scancode;
  247. } else {
  248. scancode = SDL_SCANCODE_RESERVED;
  249. }
  250. keyboard->next_reserved_scancode = (int)scancode + 1;
  251. return scancode;
  252. }
  253. static void SetKeymapEntry(SDL_Scancode scancode, SDL_Keymod modstate, SDL_Keycode keycode)
  254. {
  255. SDL_Keyboard *keyboard = &SDL_keyboard;
  256. if (!keyboard->keymap) {
  257. keyboard->keymap = SDL_CreateKeymap();
  258. }
  259. SDL_SetKeymapEntry(keyboard->keymap, scancode, modstate, keycode);
  260. }
  261. SDL_Window *SDL_GetKeyboardFocus(void)
  262. {
  263. SDL_Keyboard *keyboard = &SDL_keyboard;
  264. return keyboard->focus;
  265. }
  266. bool SDL_SetKeyboardFocus(SDL_Window *window)
  267. {
  268. SDL_VideoDevice *video = SDL_GetVideoDevice();
  269. SDL_Keyboard *keyboard = &SDL_keyboard;
  270. if (window) {
  271. if (!SDL_ObjectValid(window, SDL_OBJECT_TYPE_WINDOW) || window->is_destroying) {
  272. return SDL_SetError("Invalid window");
  273. }
  274. }
  275. if (keyboard->focus && !window) {
  276. // We won't get anymore keyboard messages, so reset keyboard state
  277. SDL_ResetKeyboard();
  278. }
  279. // See if the current window has lost focus
  280. if (keyboard->focus && keyboard->focus != window) {
  281. SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_LOST, 0, 0);
  282. // Ensures IME compositions are committed
  283. if (SDL_TextInputActive(keyboard->focus)) {
  284. if (video && video->StopTextInput) {
  285. video->StopTextInput(video, keyboard->focus);
  286. }
  287. }
  288. }
  289. keyboard->focus = window;
  290. if (keyboard->focus) {
  291. SDL_SendWindowEvent(keyboard->focus, SDL_EVENT_WINDOW_FOCUS_GAINED, 0, 0);
  292. if (SDL_TextInputActive(keyboard->focus)) {
  293. if (video && video->StartTextInput) {
  294. video->StartTextInput(video, keyboard->focus, keyboard->focus->text_input_props);
  295. }
  296. }
  297. }
  298. SDL_UpdateRelativeMouseMode();
  299. return true;
  300. }
  301. static SDL_Keycode SDL_ConvertNumpadKeycode(SDL_Keycode keycode, bool numlock)
  302. {
  303. switch (keycode) {
  304. case SDLK_KP_DIVIDE:
  305. return SDLK_SLASH;
  306. case SDLK_KP_MULTIPLY:
  307. return SDLK_ASTERISK;
  308. case SDLK_KP_MINUS:
  309. return SDLK_MINUS;
  310. case SDLK_KP_PLUS:
  311. return SDLK_PLUS;
  312. case SDLK_KP_ENTER:
  313. return SDLK_RETURN;
  314. case SDLK_KP_1:
  315. return numlock ? SDLK_1 : SDLK_END;
  316. case SDLK_KP_2:
  317. return numlock ? SDLK_2 : SDLK_DOWN;
  318. case SDLK_KP_3:
  319. return numlock ? SDLK_3 : SDLK_PAGEDOWN;
  320. case SDLK_KP_4:
  321. return numlock ? SDLK_4 : SDLK_LEFT;
  322. case SDLK_KP_5:
  323. return numlock ? SDLK_5 : SDLK_CLEAR;
  324. case SDLK_KP_6:
  325. return numlock ? SDLK_6 : SDLK_RIGHT;
  326. case SDLK_KP_7:
  327. return numlock ? SDLK_7 : SDLK_HOME;
  328. case SDLK_KP_8:
  329. return numlock ? SDLK_8 : SDLK_UP;
  330. case SDLK_KP_9:
  331. return numlock ? SDLK_9 : SDLK_PAGEUP;
  332. case SDLK_KP_0:
  333. return numlock ? SDLK_0 : SDLK_INSERT;
  334. case SDLK_KP_PERIOD:
  335. return numlock ? SDLK_PERIOD : SDLK_DELETE;
  336. case SDLK_KP_EQUALS:
  337. return SDLK_EQUALS;
  338. case SDLK_KP_COMMA:
  339. return SDLK_COMMA;
  340. case SDLK_KP_EQUALSAS400:
  341. return SDLK_EQUALS;
  342. case SDLK_KP_LEFTPAREN:
  343. return SDLK_LEFTPAREN;
  344. case SDLK_KP_RIGHTPAREN:
  345. return SDLK_RIGHTPAREN;
  346. case SDLK_KP_LEFTBRACE:
  347. return SDLK_LEFTBRACE;
  348. case SDLK_KP_RIGHTBRACE:
  349. return SDLK_RIGHTBRACE;
  350. case SDLK_KP_TAB:
  351. return SDLK_TAB;
  352. case SDLK_KP_BACKSPACE:
  353. return SDLK_BACKSPACE;
  354. case SDLK_KP_A:
  355. return SDLK_A;
  356. case SDLK_KP_B:
  357. return SDLK_B;
  358. case SDLK_KP_C:
  359. return SDLK_C;
  360. case SDLK_KP_D:
  361. return SDLK_D;
  362. case SDLK_KP_E:
  363. return SDLK_E;
  364. case SDLK_KP_F:
  365. return SDLK_F;
  366. case SDLK_KP_PERCENT:
  367. return SDLK_PERCENT;
  368. case SDLK_KP_LESS:
  369. return SDLK_LESS;
  370. case SDLK_KP_GREATER:
  371. return SDLK_GREATER;
  372. case SDLK_KP_AMPERSAND:
  373. return SDLK_AMPERSAND;
  374. case SDLK_KP_COLON:
  375. return SDLK_COLON;
  376. case SDLK_KP_HASH:
  377. return SDLK_HASH;
  378. case SDLK_KP_SPACE:
  379. return SDLK_SPACE;
  380. case SDLK_KP_AT:
  381. return SDLK_AT;
  382. case SDLK_KP_EXCLAM:
  383. return SDLK_EXCLAIM;
  384. case SDLK_KP_PLUSMINUS:
  385. return SDLK_PLUSMINUS;
  386. default:
  387. return keycode;
  388. }
  389. }
  390. SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate, bool key_event)
  391. {
  392. SDL_Keyboard *keyboard = &SDL_keyboard;
  393. if (key_event) {
  394. SDL_Keymap *keymap = SDL_GetCurrentKeymap();
  395. bool numlock = (modstate & SDL_KMOD_NUM) != 0;
  396. SDL_Keycode keycode;
  397. // We won't be applying any modifiers by default
  398. modstate = SDL_KMOD_NONE;
  399. if ((keyboard->keycode_options & KEYCODE_OPTION_FRENCH_NUMBERS) &&
  400. keyboard->french_numbers &&
  401. (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0)) {
  402. // Add the shift state to generate a numeric keycode
  403. modstate |= SDL_KMOD_SHIFT;
  404. }
  405. keycode = SDL_GetKeymapKeycode(keymap, scancode, modstate);
  406. if (keyboard->keycode_options & KEYCODE_OPTION_HIDE_NUMPAD) {
  407. keycode = SDL_ConvertNumpadKeycode(keycode, numlock);
  408. }
  409. return keycode;
  410. }
  411. return SDL_GetKeymapKeycode(keyboard->keymap, scancode, modstate);
  412. }
  413. SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate)
  414. {
  415. SDL_Keyboard *keyboard = &SDL_keyboard;
  416. return SDL_GetKeymapScancode(keyboard->keymap, key, modstate);
  417. }
  418. static bool SDL_SendKeyboardKeyInternal(Uint64 timestamp, Uint32 flags, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down)
  419. {
  420. SDL_Keyboard *keyboard = &SDL_keyboard;
  421. bool posted = false;
  422. SDL_Keycode keycode = SDLK_UNKNOWN;
  423. Uint32 type;
  424. bool repeat = false;
  425. const Uint8 source = flags & KEYBOARD_SOURCE_MASK;
  426. #ifdef DEBUG_KEYBOARD
  427. printf("The '%s' key has been %s\n", SDL_GetScancodeName(scancode), down ? "pressed" : "released");
  428. #endif
  429. // Figure out what type of event this is
  430. if (down) {
  431. type = SDL_EVENT_KEY_DOWN;
  432. } else {
  433. type = SDL_EVENT_KEY_UP;
  434. }
  435. if (scancode > SDL_SCANCODE_UNKNOWN && scancode < SDL_SCANCODE_COUNT) {
  436. // Drop events that don't change state
  437. if (down) {
  438. if (keyboard->keystate[scancode]) {
  439. if (!(keyboard->keysource[scancode] & source)) {
  440. keyboard->keysource[scancode] |= source;
  441. return false;
  442. }
  443. repeat = true;
  444. }
  445. keyboard->keysource[scancode] |= source;
  446. } else {
  447. if (!keyboard->keystate[scancode]) {
  448. return false;
  449. }
  450. keyboard->keysource[scancode] = 0;
  451. }
  452. // Update internal keyboard state
  453. keyboard->keystate[scancode] = down;
  454. keycode = SDL_GetKeyFromScancode(scancode, keyboard->modstate, true);
  455. } else if (rawcode == 0) {
  456. // Nothing to do!
  457. return false;
  458. }
  459. if (source == KEYBOARD_HARDWARE) {
  460. keyboard->hardware_timestamp = SDL_GetTicks();
  461. } else if (source == KEYBOARD_AUTORELEASE) {
  462. keyboard->autorelease_pending = true;
  463. }
  464. // Update modifiers state if applicable
  465. if (!(flags & KEYBOARD_IGNOREMODIFIERS) && !repeat) {
  466. SDL_Keymod modifier;
  467. switch (keycode) {
  468. case SDLK_LCTRL:
  469. modifier = SDL_KMOD_LCTRL;
  470. break;
  471. case SDLK_RCTRL:
  472. modifier = SDL_KMOD_RCTRL;
  473. break;
  474. case SDLK_LSHIFT:
  475. modifier = SDL_KMOD_LSHIFT;
  476. break;
  477. case SDLK_RSHIFT:
  478. modifier = SDL_KMOD_RSHIFT;
  479. break;
  480. case SDLK_LALT:
  481. modifier = SDL_KMOD_LALT;
  482. break;
  483. case SDLK_RALT:
  484. modifier = SDL_KMOD_RALT;
  485. break;
  486. case SDLK_LGUI:
  487. modifier = SDL_KMOD_LGUI;
  488. break;
  489. case SDLK_RGUI:
  490. modifier = SDL_KMOD_RGUI;
  491. break;
  492. case SDLK_MODE:
  493. modifier = SDL_KMOD_MODE;
  494. break;
  495. default:
  496. modifier = SDL_KMOD_NONE;
  497. break;
  498. }
  499. if (SDL_EVENT_KEY_DOWN == type) {
  500. switch (keycode) {
  501. case SDLK_NUMLOCKCLEAR:
  502. keyboard->modstate ^= SDL_KMOD_NUM;
  503. break;
  504. case SDLK_CAPSLOCK:
  505. keyboard->modstate ^= SDL_KMOD_CAPS;
  506. break;
  507. case SDLK_SCROLLLOCK:
  508. keyboard->modstate ^= SDL_KMOD_SCROLL;
  509. break;
  510. default:
  511. keyboard->modstate |= modifier;
  512. break;
  513. }
  514. } else {
  515. keyboard->modstate &= ~modifier;
  516. }
  517. }
  518. // Post the event, if desired
  519. if (SDL_EventEnabled(type)) {
  520. SDL_Event event;
  521. event.type = type;
  522. event.common.timestamp = timestamp;
  523. event.key.scancode = scancode;
  524. event.key.key = keycode;
  525. event.key.mod = keyboard->modstate;
  526. event.key.raw = (Uint16)rawcode;
  527. event.key.down = down;
  528. event.key.repeat = repeat;
  529. event.key.windowID = keyboard->focus ? keyboard->focus->id : 0;
  530. event.key.which = keyboardID;
  531. posted = SDL_PushEvent(&event);
  532. }
  533. /* If the keyboard is grabbed and the grabbed window is in full-screen,
  534. minimize the window when we receive Alt+Tab, unless the application
  535. has explicitly opted out of this behavior. */
  536. if (keycode == SDLK_TAB && down &&
  537. (keyboard->modstate & SDL_KMOD_ALT) &&
  538. keyboard->focus &&
  539. (keyboard->focus->flags & SDL_WINDOW_KEYBOARD_GRABBED) &&
  540. (keyboard->focus->flags & SDL_WINDOW_FULLSCREEN) &&
  541. SDL_GetHintBoolean(SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED, true)) {
  542. /* We will temporarily forfeit our grab by minimizing our window,
  543. allowing the user to escape the application */
  544. SDL_MinimizeWindow(keyboard->focus);
  545. }
  546. return posted;
  547. }
  548. void SDL_SendKeyboardUnicodeKey(Uint64 timestamp, Uint32 ch)
  549. {
  550. SDL_Keyboard *keyboard = &SDL_keyboard;
  551. SDL_Keymod modstate = SDL_KMOD_NONE;
  552. SDL_Scancode scancode;
  553. if (ch == '\n') {
  554. ch = SDLK_RETURN;
  555. }
  556. scancode = SDL_GetKeymapScancode(keyboard->keymap, ch, &modstate);
  557. // Make sure we have this keycode in our keymap
  558. if (scancode == SDL_SCANCODE_UNKNOWN && ch < SDLK_SCANCODE_MASK) {
  559. scancode = GetNextReservedScancode();
  560. SetKeymapEntry(scancode, modstate, ch);
  561. }
  562. if (modstate & SDL_KMOD_SHIFT) {
  563. // If the character uses shift, press shift down
  564. SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, true);
  565. }
  566. // Send a keydown and keyup for the character
  567. SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, true);
  568. SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, false);
  569. if (modstate & SDL_KMOD_SHIFT) {
  570. // If the character uses shift, release shift
  571. SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_VIRTUAL, SDL_GLOBAL_KEYBOARD_ID, 0, SDL_SCANCODE_LSHIFT, false);
  572. }
  573. }
  574. bool SDL_SendKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down)
  575. {
  576. return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, rawcode, scancode, down);
  577. }
  578. bool SDL_SendKeyboardKeyAndKeycode(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, SDL_Keycode keycode, bool down)
  579. {
  580. if (down) {
  581. // Make sure we have this keycode in our keymap
  582. SetKeymapEntry(scancode, SDL_GetModState(), keycode);
  583. }
  584. return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE, keyboardID, rawcode, scancode, down);
  585. }
  586. bool SDL_SendKeyboardKeyIgnoreModifiers(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down)
  587. {
  588. return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_HARDWARE | KEYBOARD_IGNOREMODIFIERS, keyboardID, rawcode, scancode, down);
  589. }
  590. bool SDL_SendKeyboardKeyAutoRelease(Uint64 timestamp, SDL_Scancode scancode)
  591. {
  592. return SDL_SendKeyboardKeyInternal(timestamp, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, 0, scancode, true);
  593. }
  594. void SDL_SendRawKeyboardKey(Uint64 timestamp, SDL_KeyboardID keyboardID, int rawcode, SDL_Scancode scancode, bool down)
  595. {
  596. const SDL_EventType type = down ? SDL_EVENT_RAW_KEY_DOWN : SDL_EVENT_RAW_KEY_UP;
  597. if (SDL_EventEnabled(type)) {
  598. SDL_Event event;
  599. event.type = type;
  600. event.common.timestamp = timestamp;
  601. event.raw_key.which = keyboardID;
  602. event.raw_key.scancode = scancode;
  603. event.raw_key.raw = rawcode;
  604. event.raw_key.down = down;
  605. SDL_PushEvent(&event);
  606. }
  607. }
  608. void SDL_ReleaseAutoReleaseKeys(void)
  609. {
  610. SDL_Keyboard *keyboard = &SDL_keyboard;
  611. int scancode;
  612. if (keyboard->autorelease_pending) {
  613. for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) {
  614. if (keyboard->keysource[scancode] == KEYBOARD_AUTORELEASE) {
  615. SDL_SendKeyboardKeyInternal(0, KEYBOARD_AUTORELEASE, SDL_GLOBAL_KEYBOARD_ID, 0, (SDL_Scancode)scancode, false);
  616. }
  617. }
  618. keyboard->autorelease_pending = false;
  619. }
  620. if (keyboard->hardware_timestamp) {
  621. // Keep hardware keyboard "active" for 250 ms
  622. if (SDL_GetTicks() >= keyboard->hardware_timestamp + 250) {
  623. keyboard->hardware_timestamp = 0;
  624. }
  625. }
  626. }
  627. bool SDL_HardwareKeyboardKeyPressed(void)
  628. {
  629. SDL_Keyboard *keyboard = &SDL_keyboard;
  630. int scancode;
  631. for (scancode = SDL_SCANCODE_UNKNOWN; scancode < SDL_SCANCODE_COUNT; ++scancode) {
  632. if (keyboard->keysource[scancode] & KEYBOARD_HARDWARE) {
  633. return true;
  634. }
  635. }
  636. return keyboard->hardware_timestamp ? true : false;
  637. }
  638. void SDL_SendKeyboardText(const char *text)
  639. {
  640. SDL_Keyboard *keyboard = &SDL_keyboard;
  641. if (!SDL_TextInputActive(keyboard->focus)) {
  642. return;
  643. }
  644. if (!text || !*text) {
  645. return;
  646. }
  647. // Don't post text events for unprintable characters
  648. if (SDL_iscntrl((unsigned char)*text)) {
  649. return;
  650. }
  651. // Post the event, if desired
  652. if (SDL_EventEnabled(SDL_EVENT_TEXT_INPUT)) {
  653. SDL_Event event;
  654. event.type = SDL_EVENT_TEXT_INPUT;
  655. event.common.timestamp = 0;
  656. event.text.windowID = keyboard->focus ? keyboard->focus->id : 0;
  657. event.text.text = SDL_CreateTemporaryString(text);
  658. if (!event.text.text) {
  659. return;
  660. }
  661. SDL_PushEvent(&event);
  662. }
  663. }
  664. void SDL_SendEditingText(const char *text, int start, int length)
  665. {
  666. SDL_Keyboard *keyboard = &SDL_keyboard;
  667. if (!SDL_TextInputActive(keyboard->focus)) {
  668. return;
  669. }
  670. if (!text) {
  671. return;
  672. }
  673. // Post the event, if desired
  674. if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING)) {
  675. SDL_Event event;
  676. event.type = SDL_EVENT_TEXT_EDITING;
  677. event.common.timestamp = 0;
  678. event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
  679. event.edit.start = start;
  680. event.edit.length = length;
  681. event.edit.text = SDL_CreateTemporaryString(text);
  682. if (!event.edit.text) {
  683. return;
  684. }
  685. SDL_PushEvent(&event);
  686. }
  687. }
  688. static const char * const *CreateCandidatesForEvent(char **candidates, int num_candidates)
  689. {
  690. const char **event_candidates;
  691. int i;
  692. char *ptr;
  693. size_t total_length = (num_candidates + 1) * sizeof(*event_candidates);
  694. for (i = 0; i < num_candidates; ++i) {
  695. size_t length = SDL_strlen(candidates[i]) + 1;
  696. total_length += length;
  697. }
  698. event_candidates = (const char **)SDL_AllocateTemporaryMemory(total_length);
  699. if (!event_candidates) {
  700. return NULL;
  701. }
  702. ptr = (char *)(event_candidates + (num_candidates + 1));
  703. for (i = 0; i < num_candidates; ++i) {
  704. size_t length = SDL_strlen(candidates[i]) + 1;
  705. event_candidates[i] = ptr;
  706. SDL_memcpy(ptr, candidates[i], length);
  707. ptr += length;
  708. }
  709. event_candidates[i] = NULL;
  710. return event_candidates;
  711. }
  712. void SDL_SendEditingTextCandidates(char **candidates, int num_candidates, int selected_candidate, bool horizontal)
  713. {
  714. SDL_Keyboard *keyboard = &SDL_keyboard;
  715. if (!SDL_TextInputActive(keyboard->focus)) {
  716. return;
  717. }
  718. // Post the event, if desired
  719. if (SDL_EventEnabled(SDL_EVENT_TEXT_EDITING_CANDIDATES)) {
  720. SDL_Event event;
  721. event.type = SDL_EVENT_TEXT_EDITING_CANDIDATES;
  722. event.common.timestamp = 0;
  723. event.edit.windowID = keyboard->focus ? keyboard->focus->id : 0;
  724. if (num_candidates > 0) {
  725. const char * const *event_candidates = CreateCandidatesForEvent(candidates, num_candidates);
  726. if (!event_candidates) {
  727. return;
  728. }
  729. event.edit_candidates.candidates = event_candidates;
  730. event.edit_candidates.num_candidates = num_candidates;
  731. event.edit_candidates.selected_candidate = selected_candidate;
  732. event.edit_candidates.horizontal = horizontal;
  733. } else {
  734. event.edit_candidates.candidates = NULL;
  735. event.edit_candidates.num_candidates = 0;
  736. event.edit_candidates.selected_candidate = -1;
  737. event.edit_candidates.horizontal = false;
  738. }
  739. SDL_PushEvent(&event);
  740. }
  741. }
  742. void SDL_QuitKeyboard(void)
  743. {
  744. for (int i = SDL_keyboard_count; i--;) {
  745. SDL_RemoveKeyboard(SDL_keyboards[i].instance_id, false);
  746. }
  747. SDL_free(SDL_keyboards);
  748. SDL_keyboards = NULL;
  749. if (SDL_keyboard.keymap) {
  750. SDL_DestroyKeymap(SDL_keyboard.keymap);
  751. SDL_keyboard.keymap = NULL;
  752. }
  753. SDL_RemoveHintCallback(SDL_HINT_KEYCODE_OPTIONS,
  754. SDL_KeycodeOptionsChanged, &SDL_keyboard);
  755. }
  756. const bool *SDL_GetKeyboardState(int *numkeys)
  757. {
  758. SDL_Keyboard *keyboard = &SDL_keyboard;
  759. if (numkeys != (int *)0) {
  760. *numkeys = SDL_SCANCODE_COUNT;
  761. }
  762. return keyboard->keystate;
  763. }
  764. SDL_Keymod SDL_GetModState(void)
  765. {
  766. SDL_Keyboard *keyboard = &SDL_keyboard;
  767. return keyboard->modstate;
  768. }
  769. void SDL_SetModState(SDL_Keymod modstate)
  770. {
  771. SDL_Keyboard *keyboard = &SDL_keyboard;
  772. keyboard->modstate = modstate;
  773. }
  774. // Note that SDL_ToggleModState() is not a public API. SDL_SetModState() is.
  775. void SDL_ToggleModState(SDL_Keymod modstate, bool toggle)
  776. {
  777. SDL_Keyboard *keyboard = &SDL_keyboard;
  778. if (toggle) {
  779. keyboard->modstate |= modstate;
  780. } else {
  781. keyboard->modstate &= ~modstate;
  782. }
  783. }