SDL_x11keyboard.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2022 Sam Lantinga <[email protected]>
  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. #if SDL_VIDEO_DRIVER_X11
  20. #include "SDL_hints.h"
  21. #include "SDL_misc.h"
  22. #include "SDL_x11video.h"
  23. #include "../../events/SDL_keyboard_c.h"
  24. #include "../../events/SDL_scancode_tables_c.h"
  25. #include <X11/keysym.h>
  26. #include <X11/XKBlib.h>
  27. #include "../../events/imKStoUCS.h"
  28. #ifdef X_HAVE_UTF8_STRING
  29. #include <locale.h>
  30. #endif
  31. /* *INDENT-OFF* */ /* clang-format off */
  32. static const struct {
  33. KeySym keysym;
  34. SDL_Scancode scancode;
  35. } KeySymToSDLScancode[] = {
  36. { XK_KP_End, SDL_SCANCODE_KP_1 },
  37. { XK_KP_Down, SDL_SCANCODE_KP_2 },
  38. { XK_KP_Next, SDL_SCANCODE_KP_3 },
  39. { XK_KP_Left, SDL_SCANCODE_KP_4 },
  40. { XK_KP_Begin, SDL_SCANCODE_KP_5 },
  41. { XK_KP_Right, SDL_SCANCODE_KP_6 },
  42. { XK_KP_Home, SDL_SCANCODE_KP_7 },
  43. { XK_KP_Up, SDL_SCANCODE_KP_8 },
  44. { XK_KP_Prior, SDL_SCANCODE_KP_9 },
  45. { XK_KP_Insert, SDL_SCANCODE_KP_0 },
  46. { XK_KP_Delete, SDL_SCANCODE_KP_PERIOD },
  47. { XK_Execute, SDL_SCANCODE_EXECUTE },
  48. { XK_Hyper_R, SDL_SCANCODE_APPLICATION },
  49. { XK_ISO_Level3_Shift, SDL_SCANCODE_RALT },
  50. { XK_Super_L, SDL_SCANCODE_LGUI },
  51. { XK_Super_R, SDL_SCANCODE_RGUI },
  52. { XK_Mode_switch, SDL_SCANCODE_MODE },
  53. { 0x1008FF65, SDL_SCANCODE_MENU }, /* XF86MenuKB */
  54. { 0x1008FF81, SDL_SCANCODE_F13 }, /* XF86Tools */
  55. { 0x1008FF45, SDL_SCANCODE_F14 }, /* XF86Launch5 */
  56. { 0x1008FF46, SDL_SCANCODE_F15 }, /* XF86Launch6 */
  57. { 0x1008FF47, SDL_SCANCODE_F16 }, /* XF86Launch7 */
  58. { 0x1008FF48, SDL_SCANCODE_F17 }, /* XF86Launch8 */
  59. { 0x1008FF49, SDL_SCANCODE_F18 }, /* XF86Launch9 */
  60. };
  61. /* This is a mapping from X keysym to Linux keycode */
  62. static const KeySym LinuxKeycodeKeysyms[] = {
  63. /* 0, 0x000 */ 0x0, /* NoSymbol */
  64. /* 1, 0x001 */ 0xFF1B, /* Escape */
  65. /* 2, 0x002 */ 0x31, /* 1 */
  66. /* 3, 0x003 */ 0x32, /* 2 */
  67. /* 4, 0x004 */ 0x33, /* 3 */
  68. /* 5, 0x005 */ 0x34, /* 4 */
  69. /* 6, 0x006 */ 0x35, /* 5 */
  70. /* 7, 0x007 */ 0x36, /* 6 */
  71. /* 8, 0x008 */ 0x37, /* 7 */
  72. /* 9, 0x009 */ 0x38, /* 8 */
  73. /* 10, 0x00a */ 0x39, /* 9 */
  74. /* 11, 0x00b */ 0x30, /* 0 */
  75. /* 12, 0x00c */ 0x2D, /* minus */
  76. /* 13, 0x00d */ 0x3D, /* equal */
  77. /* 14, 0x00e */ 0xFF08, /* BackSpace */
  78. /* 15, 0x00f */ 0xFF09, /* Tab */
  79. /* 16, 0x010 */ 0x71, /* q */
  80. /* 17, 0x011 */ 0x77, /* w */
  81. /* 18, 0x012 */ 0x65, /* e */
  82. /* 19, 0x013 */ 0x72, /* r */
  83. /* 20, 0x014 */ 0x74, /* t */
  84. /* 21, 0x015 */ 0x79, /* y */
  85. /* 22, 0x016 */ 0x75, /* u */
  86. /* 23, 0x017 */ 0x69, /* i */
  87. /* 24, 0x018 */ 0x6F, /* o */
  88. /* 25, 0x019 */ 0x70, /* p */
  89. /* 26, 0x01a */ 0x5B, /* bracketleft */
  90. /* 27, 0x01b */ 0x5D, /* bracketright */
  91. /* 28, 0x01c */ 0xFF0D, /* Return */
  92. /* 29, 0x01d */ 0xFFE3, /* Control_L */
  93. /* 30, 0x01e */ 0x61, /* a */
  94. /* 31, 0x01f */ 0x73, /* s */
  95. /* 32, 0x020 */ 0x64, /* d */
  96. /* 33, 0x021 */ 0x66, /* f */
  97. /* 34, 0x022 */ 0x67, /* g */
  98. /* 35, 0x023 */ 0x68, /* h */
  99. /* 36, 0x024 */ 0x6A, /* j */
  100. /* 37, 0x025 */ 0x6B, /* k */
  101. /* 38, 0x026 */ 0x6C, /* l */
  102. /* 39, 0x027 */ 0x3B, /* semicolon */
  103. /* 40, 0x028 */ 0x27, /* apostrophe */
  104. /* 41, 0x029 */ 0x60, /* grave */
  105. /* 42, 0x02a */ 0xFFE1, /* Shift_L */
  106. /* 43, 0x02b */ 0x5C, /* backslash */
  107. /* 44, 0x02c */ 0x7A, /* z */
  108. /* 45, 0x02d */ 0x78, /* x */
  109. /* 46, 0x02e */ 0x63, /* c */
  110. /* 47, 0x02f */ 0x76, /* v */
  111. /* 48, 0x030 */ 0x62, /* b */
  112. /* 49, 0x031 */ 0x6E, /* n */
  113. /* 50, 0x032 */ 0x6D, /* m */
  114. /* 51, 0x033 */ 0x2C, /* comma */
  115. /* 52, 0x034 */ 0x2E, /* period */
  116. /* 53, 0x035 */ 0x2F, /* slash */
  117. /* 54, 0x036 */ 0xFFE2, /* Shift_R */
  118. /* 55, 0x037 */ 0xFFAA, /* KP_Multiply */
  119. /* 56, 0x038 */ 0xFFE9, /* Alt_L */
  120. /* 57, 0x039 */ 0x20, /* space */
  121. /* 58, 0x03a */ 0xFFE5, /* Caps_Lock */
  122. /* 59, 0x03b */ 0xFFBE, /* F1 */
  123. /* 60, 0x03c */ 0xFFBF, /* F2 */
  124. /* 61, 0x03d */ 0xFFC0, /* F3 */
  125. /* 62, 0x03e */ 0xFFC1, /* F4 */
  126. /* 63, 0x03f */ 0xFFC2, /* F5 */
  127. /* 64, 0x040 */ 0xFFC3, /* F6 */
  128. /* 65, 0x041 */ 0xFFC4, /* F7 */
  129. /* 66, 0x042 */ 0xFFC5, /* F8 */
  130. /* 67, 0x043 */ 0xFFC6, /* F9 */
  131. /* 68, 0x044 */ 0xFFC7, /* F10 */
  132. /* 69, 0x045 */ 0xFF7F, /* Num_Lock */
  133. /* 70, 0x046 */ 0xFF14, /* Scroll_Lock */
  134. /* 71, 0x047 */ 0xFFB7, /* KP_7 */
  135. /* 72, 0x048 */ 0XFFB8, /* KP_8 */
  136. /* 73, 0x049 */ 0XFFB9, /* KP_9 */
  137. /* 74, 0x04a */ 0xFFAD, /* KP_Subtract */
  138. /* 75, 0x04b */ 0xFFB4, /* KP_4 */
  139. /* 76, 0x04c */ 0xFFB5, /* KP_5 */
  140. /* 77, 0x04d */ 0xFFB6, /* KP_6 */
  141. /* 78, 0x04e */ 0xFFAB, /* KP_Add */
  142. /* 79, 0x04f */ 0xFFB1, /* KP_1 */
  143. /* 80, 0x050 */ 0xFFB2, /* KP_2 */
  144. /* 81, 0x051 */ 0xFFB3, /* KP_3 */
  145. /* 82, 0x052 */ 0xFFB0, /* KP_0 */
  146. /* 83, 0x053 */ 0xFFAE, /* KP_Decimal */
  147. /* 84, 0x054 */ 0x0, /* NoSymbol */
  148. /* 85, 0x055 */ 0x0, /* NoSymbol */
  149. /* 86, 0x056 */ 0x3C, /* less */
  150. /* 87, 0x057 */ 0xFFC8, /* F11 */
  151. /* 88, 0x058 */ 0xFFC9, /* F12 */
  152. /* 89, 0x059 */ 0x0, /* NoSymbol */
  153. /* 90, 0x05a */ 0xFF26, /* Katakana */
  154. /* 91, 0x05b */ 0xFF25, /* Hiragana */
  155. /* 92, 0x05c */ 0xFF23, /* Henkan_Mode */
  156. /* 93, 0x05d */ 0xFF27, /* Hiragana_Katakana */
  157. /* 94, 0x05e */ 0xFF22, /* Muhenkan */
  158. /* 95, 0x05f */ 0x0, /* NoSymbol */
  159. /* 96, 0x060 */ 0xFF8D, /* KP_Enter */
  160. /* 97, 0x061 */ 0xFFE4, /* Control_R */
  161. /* 98, 0x062 */ 0xFFAF, /* KP_Divide */
  162. /* 99, 0x063 */ 0xFF15, /* Sys_Req */
  163. /* 100, 0x064 */ 0xFFEA, /* Alt_R */
  164. /* 101, 0x065 */ 0xFF0A, /* Linefeed */
  165. /* 102, 0x066 */ 0xFF50, /* Home */
  166. /* 103, 0x067 */ 0xFF52, /* Up */
  167. /* 104, 0x068 */ 0xFF55, /* Prior */
  168. /* 105, 0x069 */ 0xFF51, /* Left */
  169. /* 106, 0x06a */ 0xFF53, /* Right */
  170. /* 107, 0x06b */ 0xFF57, /* End */
  171. /* 108, 0x06c */ 0xFF54, /* Down */
  172. /* 109, 0x06d */ 0xFF56, /* Next */
  173. /* 110, 0x06e */ 0xFF63, /* Insert */
  174. /* 111, 0x06f */ 0xFFFF, /* Delete */
  175. /* 112, 0x070 */ 0x0, /* NoSymbol */
  176. /* 113, 0x071 */ 0x1008FF12, /* XF86AudioMute */
  177. /* 114, 0x072 */ 0x1008FF11, /* XF86AudioLowerVolume */
  178. /* 115, 0x073 */ 0x1008FF13, /* XF86AudioRaiseVolume */
  179. /* 116, 0x074 */ 0x1008FF2A, /* XF86PowerOff */
  180. /* 117, 0x075 */ 0xFFBD, /* KP_Equal */
  181. /* 118, 0x076 */ 0xB1, /* plusminus */
  182. /* 119, 0x077 */ 0xFF13, /* Pause */
  183. /* 120, 0x078 */ 0x1008FF4A, /* XF86LaunchA */
  184. /* 121, 0x079 */ 0xFFAC, /* KP_Separator */
  185. /* 122, 0x07a */ 0xFF31, /* Hangul */
  186. /* 123, 0x07b */ 0xFF34, /* Hangul_Hanja */
  187. /* 124, 0x07c */ 0x0, /* NoSymbol */
  188. /* 125, 0x07d */ 0xFFE7, /* Meta_L */
  189. /* 126, 0x07e */ 0xFFE8, /* Meta_R */
  190. /* 127, 0x07f */ 0xFF67, /* Menu */
  191. /* 128, 0x080 */ 0x00, /* NoSymbol */
  192. /* 129, 0x081 */ 0xFF66, /* Redo */
  193. /* 130, 0x082 */ 0x1005FF70, /* SunProps */
  194. /* 131, 0x083 */ 0xFF65, /* Undo */
  195. /* 132, 0x084 */ 0x1005FF71, /* SunFront */
  196. /* 133, 0x085 */ 0x1008FF57, /* XF86Copy */
  197. /* 134, 0x086 */ 0x1008FF6B, /* XF86Open */
  198. /* 135, 0x087 */ 0x1008FF6D, /* XF86Paste */
  199. /* 136, 0x088 */ 0xFF68, /* Find */
  200. /* 137, 0x089 */ 0x1008FF58, /* XF86Cut */
  201. /* 138, 0x08a */ 0xFF6A, /* Help */
  202. /* 139, 0x08b */ 0xFF67, /* Menu */
  203. /* 140, 0x08c */ 0x1008FF1D, /* XF86Calculator */
  204. /* 141, 0x08d */ 0x0, /* NoSymbol */
  205. /* 142, 0x08e */ 0x1008FF2F, /* XF86Sleep */
  206. /* 143, 0x08f */ 0x1008FF2B, /* XF86WakeUp */
  207. /* 144, 0x090 */ 0x1008FF5D, /* XF86Explorer */
  208. /* 145, 0x091 */ 0x1008FF7B, /* XF86Send */
  209. /* 146, 0x092 */ 0x0, /* NoSymbol */
  210. /* 147, 0x093 */ 0x1008FF8A, /* XF86Xfer */
  211. /* 148, 0x094 */ 0x1008FF41, /* XF86Launch1 */
  212. /* 149, 0x095 */ 0x1008FF42, /* XF86Launch2 */
  213. /* 150, 0x096 */ 0x1008FF2E, /* XF86WWW */
  214. /* 151, 0x097 */ 0x1008FF5A, /* XF86DOS */
  215. /* 152, 0x098 */ 0x1008FF2D, /* XF86ScreenSaver */
  216. /* 153, 0x099 */ 0x1008FF74, /* XF86RotateWindows */
  217. /* 154, 0x09a */ 0x1008FF7F, /* XF86TaskPane */
  218. /* 155, 0x09b */ 0x1008FF19, /* XF86Mail */
  219. /* 156, 0x09c */ 0x1008FF30, /* XF86Favorites */
  220. /* 157, 0x09d */ 0x1008FF33, /* XF86MyComputer */
  221. /* 158, 0x09e */ 0x1008FF26, /* XF86Back */
  222. /* 159, 0x09f */ 0x1008FF27, /* XF86Forward */
  223. /* 160, 0x0a0 */ 0x0, /* NoSymbol */
  224. /* 161, 0x0a1 */ 0x1008FF2C, /* XF86Eject */
  225. /* 162, 0x0a2 */ 0x1008FF2C, /* XF86Eject */
  226. /* 163, 0x0a3 */ 0x1008FF17, /* XF86AudioNext */
  227. /* 164, 0x0a4 */ 0x1008FF14, /* XF86AudioPlay */
  228. /* 165, 0x0a5 */ 0x1008FF16, /* XF86AudioPrev */
  229. /* 166, 0x0a6 */ 0x1008FF15, /* XF86AudioStop */
  230. /* 167, 0x0a7 */ 0x1008FF1C, /* XF86AudioRecord */
  231. /* 168, 0x0a8 */ 0x1008FF3E, /* XF86AudioRewind */
  232. /* 169, 0x0a9 */ 0x1008FF6E, /* XF86Phone */
  233. /* 170, 0x0aa */ 0x0, /* NoSymbol */
  234. /* 171, 0x0ab */ 0x1008FF81, /* XF86Tools */
  235. /* 172, 0x0ac */ 0x1008FF18, /* XF86HomePage */
  236. /* 173, 0x0ad */ 0x1008FF73, /* XF86Reload */
  237. /* 174, 0x0ae */ 0x1008FF56, /* XF86Close */
  238. /* 175, 0x0af */ 0x0, /* NoSymbol */
  239. /* 176, 0x0b0 */ 0x0, /* NoSymbol */
  240. /* 177, 0x0b1 */ 0x1008FF78, /* XF86ScrollUp */
  241. /* 178, 0x0b2 */ 0x1008FF79, /* XF86ScrollDown */
  242. /* 179, 0x0b3 */ 0x28, /* parenleft */
  243. /* 180, 0x0b4 */ 0x29, /* parenright */
  244. /* 181, 0x0b5 */ 0x1008FF68, /* XF86New */
  245. /* 182, 0x0b6 */ 0xFF66, /* Redo */
  246. /* 183, 0x0b7 */ 0xFFCA, /* F13 */
  247. /* 184, 0x0b8 */ 0xFFCB, /* F14 */
  248. /* 185, 0x0b9 */ 0xFFCC, /* F15 */
  249. /* 186, 0x0ba */ 0xFFCD, /* F16 */
  250. /* 187, 0x0bb */ 0xFFCE, /* F17 */
  251. /* 188, 0x0bc */ 0xFFCF, /* F18 */
  252. /* 189, 0x0bd */ 0xFFD0, /* F19 */
  253. /* 190, 0x0be */ 0xFFD1, /* F20 */
  254. /* 191, 0x0bf */ 0xFFD2, /* F21 */
  255. /* 192, 0x0c0 */ 0xFFD3, /* F22 */
  256. /* 193, 0x0c1 */ 0xFFD4, /* F23 */
  257. /* 194, 0x0c2 */ 0xFFD5, /* F24 */
  258. /* 195, 0x0c3 */ 0x0, /* NoSymbol */
  259. /* 196, 0x0c4 */ 0x0, /* NoSymbol */
  260. /* 197, 0x0c5 */ 0x0, /* NoSymbol */
  261. /* 198, 0x0c6 */ 0x0, /* NoSymbol */
  262. /* 199, 0x0c7 */ 0x0, /* NoSymbol */
  263. /* 200, 0x0c8 */ 0x1008FF14, /* XF86AudioPlay */
  264. /* 201, 0x0c9 */ 0x1008FF31, /* XF86AudioPause */
  265. /* 202, 0x0ca */ 0x1008FF43, /* XF86Launch3 */
  266. /* 203, 0x0cb */ 0x1008FF44, /* XF86Launch4 */
  267. /* 204, 0x0cc */ 0x1008FF4B, /* XF86LaunchB */
  268. /* 205, 0x0cd */ 0x1008FFA7, /* XF86Suspend */
  269. /* 206, 0x0ce */ 0x1008FF56, /* XF86Close */
  270. /* 207, 0x0cf */ 0x1008FF14, /* XF86AudioPlay */
  271. /* 208, 0x0d0 */ 0x1008FF97, /* XF86AudioForward */
  272. /* 209, 0x0d1 */ 0x0, /* NoSymbol */
  273. /* 210, 0x0d2 */ 0xFF61, /* Print */
  274. /* 211, 0x0d3 */ 0x0, /* NoSymbol */
  275. /* 212, 0x0d4 */ 0x1008FF8F, /* XF86WebCam */
  276. /* 213, 0x0d5 */ 0x1008FFB6, /* XF86AudioPreset */
  277. /* 214, 0x0d6 */ 0x0, /* NoSymbol */
  278. /* 215, 0x0d7 */ 0x1008FF19, /* XF86Mail */
  279. /* 216, 0x0d8 */ 0x1008FF8E, /* XF86Messenger */
  280. /* 217, 0x0d9 */ 0x1008FF1B, /* XF86Search */
  281. /* 218, 0x0da */ 0x1008FF5F, /* XF86Go */
  282. /* 219, 0x0db */ 0x1008FF3C, /* XF86Finance */
  283. /* 220, 0x0dc */ 0x1008FF5E, /* XF86Game */
  284. /* 221, 0x0dd */ 0x1008FF36, /* XF86Shop */
  285. /* 222, 0x0de */ 0x0, /* NoSymbol */
  286. /* 223, 0x0df */ 0xFF69, /* Cancel */
  287. /* 224, 0x0e0 */ 0x1008FF03, /* XF86MonBrightnessDown */
  288. /* 225, 0x0e1 */ 0x1008FF02, /* XF86MonBrightnessUp */
  289. /* 226, 0x0e2 */ 0x1008FF32, /* XF86AudioMedia */
  290. /* 227, 0x0e3 */ 0x1008FF59, /* XF86Display */
  291. /* 228, 0x0e4 */ 0x1008FF04, /* XF86KbdLightOnOff */
  292. /* 229, 0x0e5 */ 0x1008FF06, /* XF86KbdBrightnessDown */
  293. /* 230, 0x0e6 */ 0x1008FF05, /* XF86KbdBrightnessUp */
  294. /* 231, 0x0e7 */ 0x1008FF7B, /* XF86Send */
  295. /* 232, 0x0e8 */ 0x1008FF72, /* XF86Reply */
  296. /* 233, 0x0e9 */ 0x1008FF90, /* XF86MailForward */
  297. /* 234, 0x0ea */ 0x1008FF77, /* XF86Save */
  298. /* 235, 0x0eb */ 0x1008FF5B, /* XF86Documents */
  299. /* 236, 0x0ec */ 0x1008FF93, /* XF86Battery */
  300. /* 237, 0x0ed */ 0x1008FF94, /* XF86Bluetooth */
  301. /* 238, 0x0ee */ 0x1008FF95, /* XF86WLAN */
  302. /* 239, 0x0ef */ 0x1008FF96, /* XF86UWB */
  303. /* 240, 0x0f0 */ 0x0, /* NoSymbol */
  304. /* 241, 0x0f1 */ 0x1008FE22, /* XF86Next_VMode */
  305. /* 242, 0x0f2 */ 0x1008FE23, /* XF86Prev_VMode */
  306. /* 243, 0x0f3 */ 0x1008FF07, /* XF86MonBrightnessCycle */
  307. /* 244, 0x0f4 */ 0x100810F4, /* XF86BrightnessAuto */
  308. /* 245, 0x0f5 */ 0x100810F5, /* XF86DisplayOff */
  309. /* 246, 0x0f6 */ 0x1008FFB4, /* XF86WWAN */
  310. /* 247, 0x0f7 */ 0x1008FFB5, /* XF86RFKill */
  311. };
  312. #if 0 /* Here is a script to generate the ExtendedLinuxKeycodeKeysyms table */
  313. #!/bin/bash
  314. function process_line
  315. {
  316. sym=$(echo "$1" | awk '{print $3}')
  317. code=$(echo "$1" | sed 's,.*_EVDEVK(\(0x[0-9A-Fa-f]*\)).*,\1,')
  318. value=$(egrep "#define ${sym}\s" -R /usr/include/X11 | awk '{print $3}')
  319. printf " { 0x%.8X, 0x%.3x }, /* $sym */\n" $value $code
  320. }
  321. fgrep "/* Use: " /usr/include/xkbcommon/xkbcommon-keysyms.h | fgrep _EVDEVK | while read line; do
  322. process_line "$line"
  323. done
  324. #endif
  325. static const struct {
  326. KeySym keysym;
  327. int linux_keycode;
  328. } ExtendedLinuxKeycodeKeysyms[] = {
  329. { 0x1008FF2C, 0x0a2 }, /* XF86XK_Eject */
  330. { 0x1008FF68, 0x0b5 }, /* XF86XK_New */
  331. { 0x0000FF66, 0x0b6 }, /* XK_Redo */
  332. { 0x1008FF4B, 0x0cc }, /* XF86XK_LaunchB */
  333. { 0x1008FF59, 0x0e3 }, /* XF86XK_Display */
  334. { 0x1008FF04, 0x0e4 }, /* XF86XK_KbdLightOnOff */
  335. { 0x1008FF06, 0x0e5 }, /* XF86XK_KbdBrightnessDown */
  336. { 0x1008FF05, 0x0e6 }, /* XF86XK_KbdBrightnessUp */
  337. { 0x1008FF7B, 0x0e7 }, /* XF86XK_Send */
  338. { 0x1008FF72, 0x0e8 }, /* XF86XK_Reply */
  339. { 0x1008FF90, 0x0e9 }, /* XF86XK_MailForward */
  340. { 0x1008FF77, 0x0ea }, /* XF86XK_Save */
  341. { 0x1008FF5B, 0x0eb }, /* XF86XK_Documents */
  342. { 0x1008FF93, 0x0ec }, /* XF86XK_Battery */
  343. { 0x1008FF94, 0x0ed }, /* XF86XK_Bluetooth */
  344. { 0x1008FF95, 0x0ee }, /* XF86XK_WLAN */
  345. { 0x1008FF96, 0x0ef }, /* XF86XK_UWB */
  346. { 0x1008FE22, 0x0f1 }, /* XF86XK_Next_VMode */
  347. { 0x1008FE23, 0x0f2 }, /* XF86XK_Prev_VMode */
  348. { 0x1008FF07, 0x0f3 }, /* XF86XK_MonBrightnessCycle */
  349. { 0x1008FFB4, 0x0f6 }, /* XF86XK_WWAN */
  350. { 0x1008FFB5, 0x0f7 }, /* XF86XK_RFKill */
  351. { 0x1008FFB2, 0x0f8 }, /* XF86XK_AudioMicMute */
  352. { 0x1008FF9C, 0x173 }, /* XF86XK_CycleAngle */
  353. { 0x1008FFB8, 0x174 }, /* XF86XK_FullScreen */
  354. { 0x1008FF87, 0x189 }, /* XF86XK_Video */
  355. { 0x1008FF20, 0x18d }, /* XF86XK_Calendar */
  356. { 0x1008FF99, 0x19a }, /* XF86XK_AudioRandomPlay */
  357. { 0x1008FF5E, 0x1a1 }, /* XF86XK_Game */
  358. { 0x1008FF8B, 0x1a2 }, /* XF86XK_ZoomIn */
  359. { 0x1008FF8C, 0x1a3 }, /* XF86XK_ZoomOut */
  360. { 0x1008FF89, 0x1a5 }, /* XF86XK_Word */
  361. { 0x1008FF5C, 0x1a7 }, /* XF86XK_Excel */
  362. { 0x1008FF69, 0x1ab }, /* XF86XK_News */
  363. { 0x1008FF8E, 0x1ae }, /* XF86XK_Messenger */
  364. { 0x1008FF61, 0x1b1 }, /* XF86XK_LogOff */
  365. { 0x00000024, 0x1b2 }, /* XK_dollar */
  366. { 0x000020AC, 0x1b3 }, /* XK_EuroSign */
  367. { 0x1008FF9D, 0x1b4 }, /* XF86XK_FrameBack */
  368. { 0x1008FF9E, 0x1b5 }, /* XF86XK_FrameForward */
  369. { 0x0000FFF1, 0x1f1 }, /* XK_braille_dot_1 */
  370. { 0x0000FFF2, 0x1f2 }, /* XK_braille_dot_2 */
  371. { 0x0000FFF3, 0x1f3 }, /* XK_braille_dot_3 */
  372. { 0x0000FFF4, 0x1f4 }, /* XK_braille_dot_4 */
  373. { 0x0000FFF5, 0x1f5 }, /* XK_braille_dot_5 */
  374. { 0x0000FFF6, 0x1f6 }, /* XK_braille_dot_6 */
  375. { 0x0000FFF7, 0x1f7 }, /* XK_braille_dot_7 */
  376. { 0x0000FFF8, 0x1f8 }, /* XK_braille_dot_8 */
  377. { 0x0000FFF9, 0x1f9 }, /* XK_braille_dot_9 */
  378. { 0x0000FFF1, 0x1fa }, /* XK_braille_dot_1 */
  379. { 0x1008FFA9, 0x212 }, /* XF86XK_TouchpadToggle */
  380. { 0x1008FFB0, 0x213 }, /* XF86XK_TouchpadOn */
  381. { 0x1008FFB1, 0x214 }, /* XF86XK_TouchpadOff */
  382. { 0x1008FFB7, 0x231 }, /* XF86XK_RotationLockToggle */
  383. { 0x0000FE08, 0x248 }, /* XK_ISO_Next_Group */
  384. };
  385. static SDL_ScancodeTable scancode_set[] = {
  386. SDL_SCANCODE_TABLE_DARWIN,
  387. SDL_SCANCODE_TABLE_XFREE86_1,
  388. SDL_SCANCODE_TABLE_XFREE86_2,
  389. SDL_SCANCODE_TABLE_XVNC,
  390. };
  391. /* *INDENT-OFF* */ /* clang-format off */
  392. /* This function only correctly maps letters and numbers for keyboards in US QWERTY layout */
  393. static SDL_Scancode
  394. X11_KeyCodeToSDLScancode(_THIS, KeyCode keycode)
  395. {
  396. KeySym keysym;
  397. int i;
  398. int linux_keycode = 0;
  399. keysym = X11_KeyCodeToSym(_this, keycode, 0);
  400. if (keysym == NoSymbol) {
  401. return SDL_SCANCODE_UNKNOWN;
  402. }
  403. /* First check our custom list */
  404. for (i = 0; i < SDL_arraysize(KeySymToSDLScancode); ++i) {
  405. if (keysym == KeySymToSDLScancode[i].keysym) {
  406. return KeySymToSDLScancode[i].scancode;
  407. }
  408. }
  409. /* The rest of the keysyms map to Linux keycodes, so use that mapping */
  410. if (keysym >= 0x10081000 && keysym <= 0x10081FFF) {
  411. /* Per xkbcommon-keysyms.h, this is actually a linux keycode */
  412. linux_keycode = (keysym - 0x10081000);
  413. }
  414. if (!linux_keycode) {
  415. /* See if this keysym is an exact match in our table */
  416. i = (keycode - 8);
  417. if (i >= 0 && i < SDL_arraysize(LinuxKeycodeKeysyms) && keysym == LinuxKeycodeKeysyms[i]) {
  418. linux_keycode = i;
  419. } else {
  420. /* Scan the table for this keysym */
  421. for (i = 0; i < SDL_arraysize(LinuxKeycodeKeysyms); ++i) {
  422. if (keysym == LinuxKeycodeKeysyms[i]) {
  423. linux_keycode = i;
  424. break;
  425. }
  426. }
  427. }
  428. }
  429. if (!linux_keycode) {
  430. /* Scan the extended table for this keysym */
  431. for (i = 0; i < SDL_arraysize(ExtendedLinuxKeycodeKeysyms); ++i) {
  432. if (keysym == ExtendedLinuxKeycodeKeysyms[i].keysym) {
  433. linux_keycode = ExtendedLinuxKeycodeKeysyms[i].linux_keycode;
  434. break;
  435. }
  436. }
  437. }
  438. return SDL_GetScancodeFromTable(SDL_SCANCODE_TABLE_LINUX, linux_keycode);
  439. }
  440. static Uint32
  441. X11_KeyCodeToUcs4(_THIS, KeyCode keycode, unsigned char group)
  442. {
  443. KeySym keysym = X11_KeyCodeToSym(_this, keycode, group);
  444. if (keysym == NoSymbol) {
  445. return 0;
  446. }
  447. return SDL_KeySymToUcs4(keysym);
  448. }
  449. KeySym
  450. X11_KeyCodeToSym(_THIS, KeyCode keycode, unsigned char group)
  451. {
  452. SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  453. KeySym keysym;
  454. #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
  455. if (data->xkb) {
  456. int num_groups = XkbKeyNumGroups(data->xkb, keycode);
  457. unsigned char info = XkbKeyGroupInfo(data->xkb, keycode);
  458. if (num_groups && group >= num_groups) {
  459. int action = XkbOutOfRangeGroupAction(info);
  460. if (action == XkbRedirectIntoRange) {
  461. if ((group = XkbOutOfRangeGroupNumber(info)) >= num_groups) {
  462. group = 0;
  463. }
  464. } else if (action == XkbClampIntoRange) {
  465. group = num_groups - 1;
  466. } else {
  467. group %= num_groups;
  468. }
  469. }
  470. keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0);
  471. } else {
  472. keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
  473. }
  474. #else
  475. keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
  476. #endif
  477. return keysym;
  478. }
  479. int
  480. X11_InitKeyboard(_THIS)
  481. {
  482. SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  483. int i = 0;
  484. int j = 0;
  485. int min_keycode, max_keycode;
  486. struct {
  487. SDL_Scancode scancode;
  488. KeySym keysym;
  489. int value;
  490. } fingerprint[] = {
  491. { SDL_SCANCODE_HOME, XK_Home, 0 },
  492. { SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
  493. { SDL_SCANCODE_UP, XK_Up, 0 },
  494. { SDL_SCANCODE_LEFT, XK_Left, 0 },
  495. { SDL_SCANCODE_DELETE, XK_Delete, 0 },
  496. { SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
  497. };
  498. int best_distance;
  499. int best_index;
  500. int distance;
  501. Bool xkb_repeat = 0;
  502. #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
  503. {
  504. int xkb_major = XkbMajorVersion;
  505. int xkb_minor = XkbMinorVersion;
  506. if (X11_XkbQueryExtension(data->display, NULL, &data->xkb_event, NULL, &xkb_major, &xkb_minor)) {
  507. data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
  508. }
  509. /* This will remove KeyRelease events for held keys */
  510. X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
  511. }
  512. #endif
  513. /* Open a connection to the X input manager */
  514. #ifdef X_HAVE_UTF8_STRING
  515. if (SDL_X11_HAVE_UTF8) {
  516. /* Set the locale, and call XSetLocaleModifiers before XOpenIM so that
  517. Compose keys will work correctly. */
  518. char *prev_locale = setlocale(LC_ALL, NULL);
  519. char *prev_xmods = X11_XSetLocaleModifiers(NULL);
  520. const char *new_xmods = "";
  521. const char *env_xmods = SDL_getenv("XMODIFIERS");
  522. SDL_bool has_dbus_ime_support = SDL_FALSE;
  523. if (prev_locale) {
  524. prev_locale = SDL_strdup(prev_locale);
  525. }
  526. if (prev_xmods) {
  527. prev_xmods = SDL_strdup(prev_xmods);
  528. }
  529. /* IBus resends some key events that were filtered by XFilterEvents
  530. when it is used via XIM which causes issues. Prevent this by forcing
  531. @im=none if XMODIFIERS contains @im=ibus. IBus can still be used via
  532. the DBus implementation, which also has support for pre-editing. */
  533. if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
  534. has_dbus_ime_support = SDL_TRUE;
  535. }
  536. if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
  537. has_dbus_ime_support = SDL_TRUE;
  538. }
  539. if (has_dbus_ime_support || !xkb_repeat) {
  540. new_xmods = "@im=none";
  541. }
  542. setlocale(LC_ALL, "");
  543. X11_XSetLocaleModifiers(new_xmods);
  544. data->im = X11_XOpenIM(data->display, NULL, data->classname, data->classname);
  545. /* Reset the locale + X locale modifiers back to how they were,
  546. locale first because the X locale modifiers depend on it. */
  547. setlocale(LC_ALL, prev_locale);
  548. X11_XSetLocaleModifiers(prev_xmods);
  549. if (prev_locale) {
  550. SDL_free(prev_locale);
  551. }
  552. if (prev_xmods) {
  553. SDL_free(prev_xmods);
  554. }
  555. }
  556. #endif
  557. /* Try to determine which scancodes are being used based on fingerprint */
  558. best_distance = SDL_arraysize(fingerprint) + 1;
  559. best_index = -1;
  560. X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
  561. for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
  562. fingerprint[i].value = X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) - min_keycode;
  563. }
  564. for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
  565. int table_size;
  566. const SDL_Scancode *table = SDL_GetScancodeTable(scancode_set[i], &table_size);
  567. distance = 0;
  568. for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
  569. if (fingerprint[j].value < 0 || fingerprint[j].value >= table_size) {
  570. distance += 1;
  571. } else if (table[fingerprint[j].value] != fingerprint[j].scancode) {
  572. distance += 1;
  573. }
  574. }
  575. if (distance < best_distance) {
  576. best_distance = distance;
  577. best_index = i;
  578. }
  579. }
  580. if (best_index < 0 || best_distance > 2) {
  581. /* This is likely to be SDL_SCANCODE_TABLE_XFREE86_2 with remapped keys, double check a rarely remapped value */
  582. int fingerprint_value = X11_XKeysymToKeycode(data->display, 0x1008FF5B /* XF86Documents */) - min_keycode;
  583. if (fingerprint_value == 235) {
  584. for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
  585. if (scancode_set[i] == SDL_SCANCODE_TABLE_XFREE86_2) {
  586. best_index = i;
  587. best_distance = 0;
  588. break;
  589. }
  590. }
  591. }
  592. }
  593. if (best_index >= 0 && best_distance <= 2) {
  594. SDL_Keycode default_keymap[SDL_NUM_SCANCODES];
  595. int table_size;
  596. const SDL_Scancode *table = SDL_GetScancodeTable(scancode_set[best_index], &table_size);
  597. #ifdef DEBUG_KEYBOARD
  598. SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, table_size);
  599. #endif
  600. /* This should never happen, but just in case... */
  601. if (table_size > (SDL_arraysize(data->key_layout) - min_keycode)) {
  602. table_size = (SDL_arraysize(data->key_layout) - min_keycode);
  603. }
  604. SDL_memcpy(&data->key_layout[min_keycode], table, sizeof(SDL_Scancode) * table_size);
  605. /* Scancodes represent physical locations on the keyboard, unaffected by keyboard mapping.
  606. However, there are a number of extended scancodes that have no standard location, so use
  607. the X11 mapping for all non-character keys.
  608. */
  609. SDL_GetDefaultKeymap(default_keymap);
  610. for (i = min_keycode; i <= max_keycode; ++i) {
  611. SDL_Scancode scancode = X11_KeyCodeToSDLScancode(_this, i);
  612. #ifdef DEBUG_KEYBOARD
  613. {
  614. KeySym sym;
  615. sym = X11_KeyCodeToSym(_this, (KeyCode)i, 0);
  616. SDL_Log("code = %d, sym = 0x%X (%s) ", i - min_keycode,
  617. (unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym));
  618. }
  619. #endif
  620. if (scancode == data->key_layout[i]) {
  621. continue;
  622. }
  623. if (default_keymap[scancode] >= SDLK_SCANCODE_MASK) {
  624. /* Not a character key, safe to remap */
  625. #ifdef DEBUG_KEYBOARD
  626. SDL_Log("Changing scancode, was %d (%s), now %d (%s)\n", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode));
  627. #endif
  628. data->key_layout[i] = scancode;
  629. }
  630. }
  631. } else {
  632. #ifdef DEBUG_SCANCODES
  633. SDL_Log("Keyboard layout unknown, please report the following to the SDL forums/mailing list (https://discourse.libsdl.org/):\n");
  634. #endif
  635. /* Determine key_layout - only works on US QWERTY layout */
  636. for (i = min_keycode; i <= max_keycode; ++i) {
  637. SDL_Scancode scancode = X11_KeyCodeToSDLScancode(_this, i);
  638. #ifdef DEBUG_SCANCODES
  639. {
  640. KeySym sym;
  641. sym = X11_KeyCodeToSym(_this, (KeyCode)i, 0);
  642. SDL_Log("code = %d, sym = 0x%X (%s) ", i - min_keycode,
  643. (unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym));
  644. }
  645. if (scancode == SDL_SCANCODE_UNKNOWN) {
  646. SDL_Log("scancode not found\n");
  647. } else {
  648. SDL_Log("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
  649. }
  650. #endif
  651. data->key_layout[i] = scancode;
  652. }
  653. }
  654. X11_UpdateKeymap(_this, SDL_FALSE);
  655. SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
  656. #ifdef SDL_USE_IME
  657. SDL_IME_Init();
  658. #endif
  659. X11_ReconcileKeyboardState(_this);
  660. return 0;
  661. }
  662. void
  663. X11_UpdateKeymap(_THIS, SDL_bool send_event)
  664. {
  665. SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  666. int i;
  667. SDL_Scancode scancode;
  668. SDL_Keycode keymap[SDL_NUM_SCANCODES];
  669. unsigned char group = 0;
  670. SDL_GetDefaultKeymap(keymap);
  671. #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
  672. if (data->xkb) {
  673. XkbStateRec state;
  674. X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb);
  675. if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
  676. group = state.group;
  677. }
  678. }
  679. #endif
  680. for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
  681. Uint32 key;
  682. /* Make sure this is a valid scancode */
  683. scancode = data->key_layout[i];
  684. if (scancode == SDL_SCANCODE_UNKNOWN) {
  685. continue;
  686. }
  687. /* See if there is a UCS keycode for this scancode */
  688. key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group);
  689. if (key) {
  690. keymap[scancode] = key;
  691. } else {
  692. SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i);
  693. switch (keyScancode) {
  694. case SDL_SCANCODE_RETURN:
  695. keymap[scancode] = SDLK_RETURN;
  696. break;
  697. case SDL_SCANCODE_ESCAPE:
  698. keymap[scancode] = SDLK_ESCAPE;
  699. break;
  700. case SDL_SCANCODE_BACKSPACE:
  701. keymap[scancode] = SDLK_BACKSPACE;
  702. break;
  703. case SDL_SCANCODE_TAB:
  704. keymap[scancode] = SDLK_TAB;
  705. break;
  706. case SDL_SCANCODE_DELETE:
  707. keymap[scancode] = SDLK_DELETE;
  708. break;
  709. default:
  710. keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode);
  711. break;
  712. }
  713. }
  714. }
  715. SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
  716. }
  717. void
  718. X11_QuitKeyboard(_THIS)
  719. {
  720. SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
  721. #if SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
  722. if (data->xkb) {
  723. X11_XkbFreeKeyboard(data->xkb, 0, True);
  724. data->xkb = NULL;
  725. }
  726. #endif
  727. #ifdef SDL_USE_IME
  728. SDL_IME_Quit();
  729. #endif
  730. }
  731. static void
  732. X11_ResetXIM(_THIS)
  733. {
  734. #ifdef X_HAVE_UTF8_STRING
  735. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  736. int i;
  737. if (videodata && videodata->windowlist) {
  738. for (i = 0; i < videodata->numwindows; ++i) {
  739. SDL_WindowData *data = videodata->windowlist[i];
  740. if (data && data->ic) {
  741. /* Clear any partially entered dead keys */
  742. char *contents = X11_Xutf8ResetIC(data->ic);
  743. if (contents) {
  744. X11_XFree(contents);
  745. }
  746. }
  747. }
  748. }
  749. #endif
  750. }
  751. void
  752. X11_StartTextInput(_THIS)
  753. {
  754. X11_ResetXIM(_this);
  755. }
  756. void
  757. X11_StopTextInput(_THIS)
  758. {
  759. X11_ResetXIM(_this);
  760. #ifdef SDL_USE_IME
  761. SDL_IME_Reset();
  762. #endif
  763. }
  764. void
  765. X11_SetTextInputRect(_THIS, const SDL_Rect *rect)
  766. {
  767. if (!rect) {
  768. SDL_InvalidParamError("rect");
  769. return;
  770. }
  771. #ifdef SDL_USE_IME
  772. SDL_IME_UpdateTextRect(rect);
  773. #endif
  774. }
  775. SDL_bool
  776. X11_HasScreenKeyboardSupport(_THIS)
  777. {
  778. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  779. return videodata->is_steam_deck;
  780. }
  781. void
  782. X11_ShowScreenKeyboard(_THIS, SDL_Window *window)
  783. {
  784. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  785. if (videodata->is_steam_deck) {
  786. /* For more documentation of the URL parameters, see:
  787. * https://partner.steamgames.com/doc/api/ISteamUtils#ShowFloatingGamepadTextInput
  788. */
  789. char deeplink[128];
  790. SDL_snprintf(deeplink, sizeof(deeplink),
  791. "steam://open/keyboard?XPosition=0&YPosition=0&Width=0&Height=0&Mode=%d",
  792. SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE) ? 0 : 1);
  793. SDL_OpenURL(deeplink);
  794. videodata->steam_keyboard_open = SDL_TRUE;
  795. }
  796. }
  797. void X11_HideScreenKeyboard(_THIS, SDL_Window *window)
  798. {
  799. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  800. if (videodata->is_steam_deck) {
  801. SDL_OpenURL("steam://close/keyboard");
  802. videodata->steam_keyboard_open = SDL_FALSE;
  803. }
  804. }
  805. SDL_bool X11_IsScreenKeyboardShown(_THIS, SDL_Window *window)
  806. {
  807. SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
  808. return videodata->steam_keyboard_open;
  809. }
  810. #endif /* SDL_VIDEO_DRIVER_X11 */
  811. /* vi: set ts=4 sw=4 expandtab: */