SDL_keyboard.c 26 KB

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