Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  *
  9.  * SDL keyboard input support
  10.  *
  11.  *
  12.  */
  13.  
  14. #include <algorithm>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17.  
  18. #include <SDL.h>
  19. #include <SDL_version.h>
  20. #if SDL_MAJOR_VERSION == 2
  21. #include <SDL_keycode.h>
  22. #endif
  23.  
  24. #include "event.h"
  25. #include "dxxerror.h"
  26. #include "key.h"
  27. #include "timer.h"
  28. #include "window.h"
  29. #include "console.h"
  30. #include "args.h"
  31.  
  32. #include "dxxsconf.h"
  33. #include "dsx-ns.h"
  34. #include "compiler-range_for.h"
  35. #include <array>
  36.  
  37. namespace dcx {
  38.  
  39. //-------- Variable accessed by outside functions ---------
  40. static bool keyd_repeat; // 1 = use repeats, 0 no repeats
  41. pressed_keys keyd_pressed;
  42. fix64                   keyd_time_when_last_pressed;
  43. std::array<unsigned char, KEY_BUFFER_SIZE>              unicode_frame_buffer;
  44.  
  45. const std::array<key_props, 256> key_properties = {{
  46. { "",       255,    SDLK_UNKNOWN                 }, // 0
  47. { "ESC",    255,    SDLK_ESCAPE        },
  48. { "1",      '1',    SDLK_1             },
  49. { "2",      '2',    SDLK_2             },
  50. { "3",      '3',    SDLK_3             },
  51. { "4",      '4',    SDLK_4             },
  52. { "5",      '5',    SDLK_5             },
  53. { "6",      '6',    SDLK_6             },
  54. { "7",      '7',    SDLK_7             },
  55. { "8",      '8',    SDLK_8             },
  56. { "9",      '9',    SDLK_9             }, // 10
  57. { "0",      '0',    SDLK_0             },
  58. { "-",      '-',    SDLK_MINUS         },
  59. { "=",      '=',    SDLK_EQUALS        },
  60. { "BSPC",   255,    SDLK_BACKSPACE     },
  61. { "TAB",    255,    SDLK_TAB           },
  62. { "Q",      'q',    SDLK_q             },
  63. { "W",      'w',    SDLK_w             },
  64. { "E",      'e',    SDLK_e             },
  65. { "R",      'r',    SDLK_r             },
  66. { "T",      't',    SDLK_t             }, // 20
  67. { "Y",      'y',    SDLK_y             },
  68. { "U",      'u',    SDLK_u             },
  69. { "I",      'i',    SDLK_i             },
  70. { "O",      'o',    SDLK_o             },
  71. { "P",      'p',    SDLK_p             },
  72. { "[",      '[',    SDLK_LEFTBRACKET   },
  73. { "]",      ']',    SDLK_RIGHTBRACKET  },
  74. { "ENTER",  255,    SDLK_RETURN        },
  75. { "LCTRL",  255,    SDLK_LCTRL         },
  76. { "A",      'a',    SDLK_a             }, // 30
  77. { "S",      's',    SDLK_s             },
  78. { "D",      'd',    SDLK_d             },
  79. { "F",      'f',    SDLK_f             },
  80. { "G",      'g',    SDLK_g             },
  81. { "H",      'h',    SDLK_h             },
  82. { "J",      'j',    SDLK_j             },
  83. { "K",      'k',    SDLK_k             },
  84. { "L",      'l',    SDLK_l             },
  85. { ";",      ';',    SDLK_SEMICOLON     },
  86. { "'",      '\'',   SDLK_QUOTE         }, // 40
  87. { "`",      '`',    SDLK_BACKQUOTE     },
  88. { "LSHFT",  255,    SDLK_LSHIFT        },
  89. { "\\",     '\\',   SDLK_BACKSLASH     },
  90. { "Z",      'z',    SDLK_z             },
  91. { "X",      'x',    SDLK_x             },
  92. { "C",      'c',    SDLK_c             },
  93. { "V",      'v',    SDLK_v             },
  94. { "B",      'b',    SDLK_b             },
  95. { "N",      'n',    SDLK_n             },
  96. { "M",      'm',    SDLK_m             }, // 50
  97. { ",",      ',',    SDLK_COMMA         },
  98. { ".",      '.',    SDLK_PERIOD        },
  99. { "/",      '/',    SDLK_SLASH         },
  100. { "RSHFT",  255,    SDLK_RSHIFT        },
  101. { "PAD*",   '*',    SDLK_KP_MULTIPLY   },
  102. { "LALT",   255,    SDLK_LALT          },
  103. { "SPC",    ' ',    SDLK_SPACE         },
  104. { "CPSLK",  255,    SDLK_CAPSLOCK      },
  105. { "F1",     255,    SDLK_F1            },
  106. { "F2",     255,    SDLK_F2            }, // 60
  107. { "F3",     255,    SDLK_F3            },
  108. { "F4",     255,    SDLK_F4            },
  109. { "F5",     255,    SDLK_F5            },
  110. { "F6",     255,    SDLK_F6            },
  111. { "F7",     255,    SDLK_F7            },
  112. { "F8",     255,    SDLK_F8            },
  113. { "F9",     255,    SDLK_F9            },
  114. { "F10",    255,    SDLK_F10           },
  115. #if SDL_MAJOR_VERSION == 1
  116. #define SDLK_NUMLOCKCLEAR       SDLK_NUMLOCK
  117. #define SDLK_SCROLLLOCK SDLK_SCROLLOCK
  118. #define SDLK_KP_0       SDLK_KP0
  119. #define SDLK_KP_1       SDLK_KP1
  120. #define SDLK_KP_2       SDLK_KP2
  121. #define SDLK_KP_3       SDLK_KP3
  122. #define SDLK_KP_4       SDLK_KP4
  123. #define SDLK_KP_5       SDLK_KP5
  124. #define SDLK_KP_6       SDLK_KP6
  125. #define SDLK_KP_7       SDLK_KP7
  126. #define SDLK_KP_8       SDLK_KP8
  127. #define SDLK_KP_9       SDLK_KP9
  128. #endif
  129. { "NMLCK",  255,    SDLK_NUMLOCKCLEAR  },
  130. { "SCLK",   255,    SDLK_SCROLLLOCK    }, // 70
  131. { "PAD7",   255,    SDLK_KP_7          },
  132. { "PAD8",   255,    SDLK_KP_8          },
  133. { "PAD9",   255,    SDLK_KP_9          },
  134. { "PAD-",   255,    SDLK_KP_MINUS      },
  135. { "PAD4",   255,    SDLK_KP_4          },
  136. { "PAD5",   255,    SDLK_KP_5          },
  137. { "PAD6",   255,    SDLK_KP_6          },
  138. { "PAD+",   255,    SDLK_KP_PLUS       },
  139. { "PAD1",   255,    SDLK_KP_1          },
  140. { "PAD2",   255,    SDLK_KP_2          }, // 80
  141. { "PAD3",   255,    SDLK_KP_3          },
  142. { "PAD0",   255,    SDLK_KP_0          },
  143. { "PAD.",   255,    SDLK_KP_PERIOD     },
  144. { "",       255,    SDLK_UNKNOWN                 },
  145. { "",       255,    SDLK_UNKNOWN                 },
  146. { "",       255,    SDLK_UNKNOWN                 },
  147. { "F11",    255,    SDLK_F11           },
  148. { "F12",    255,    SDLK_F12           },
  149. { "",       255,    SDLK_UNKNOWN                 },
  150. { "",       255,    SDLK_UNKNOWN                 }, // 90
  151. { "",       255,    SDLK_UNKNOWN                 },
  152. { "",       255,    SDLK_UNKNOWN                 },
  153. { "",       255,    SDLK_UNKNOWN                 },
  154. { "",       255,    SDLK_UNKNOWN                 },
  155. { "",       255,    SDLK_UNKNOWN                 },
  156. { "",       255,    SDLK_UNKNOWN                 },
  157. { "PAUSE",  255,    SDLK_PAUSE         },
  158. #if SDL_MAJOR_VERSION == 2
  159. #define SDLK_WORLD_0    SDLK_UNKNOWN
  160. #define SDLK_WORLD_1    SDLK_UNKNOWN
  161. #define SDLK_WORLD_2    SDLK_UNKNOWN
  162. #define SDLK_WORLD_3    SDLK_UNKNOWN
  163. #define SDLK_WORLD_4    SDLK_UNKNOWN
  164. #define SDLK_WORLD_5    SDLK_UNKNOWN
  165. #define SDLK_WORLD_6    SDLK_UNKNOWN
  166. #define SDLK_WORLD_7    SDLK_UNKNOWN
  167. #define SDLK_WORLD_8    SDLK_UNKNOWN
  168. #define SDLK_WORLD_9    SDLK_UNKNOWN
  169. #define SDLK_WORLD_10   SDLK_UNKNOWN
  170. #define SDLK_WORLD_11   SDLK_UNKNOWN
  171. #define SDLK_WORLD_12   SDLK_UNKNOWN
  172. #define SDLK_WORLD_13   SDLK_UNKNOWN
  173. #define SDLK_WORLD_14   SDLK_UNKNOWN
  174. #define SDLK_WORLD_15   SDLK_UNKNOWN
  175. #define SDLK_WORLD_16   SDLK_UNKNOWN
  176. #define SDLK_WORLD_17   SDLK_UNKNOWN
  177. #define SDLK_WORLD_18   SDLK_UNKNOWN
  178. #define SDLK_WORLD_19   SDLK_UNKNOWN
  179. #define SDLK_WORLD_20   SDLK_UNKNOWN
  180. #define SDLK_WORLD_21   SDLK_UNKNOWN
  181. #define SDLK_WORLD_22   SDLK_UNKNOWN
  182. #define SDLK_WORLD_23   SDLK_UNKNOWN
  183. #define SDLK_WORLD_24   SDLK_UNKNOWN
  184. #define SDLK_WORLD_25   SDLK_UNKNOWN
  185. #define SDLK_WORLD_26   SDLK_UNKNOWN
  186. #define SDLK_WORLD_27   SDLK_UNKNOWN
  187. #define SDLK_WORLD_28   SDLK_UNKNOWN
  188. #define SDLK_WORLD_29   SDLK_UNKNOWN
  189. #define SDLK_WORLD_30   SDLK_UNKNOWN
  190. #define SDLK_WORLD_31   SDLK_UNKNOWN
  191. #define SDLK_WORLD_32   SDLK_UNKNOWN
  192. #define SDLK_WORLD_33   SDLK_UNKNOWN
  193. #define SDLK_WORLD_34   SDLK_UNKNOWN
  194. #define SDLK_WORLD_35   SDLK_UNKNOWN
  195. #define SDLK_WORLD_36   SDLK_UNKNOWN
  196. #define SDLK_WORLD_37   SDLK_UNKNOWN
  197. #define SDLK_WORLD_38   SDLK_UNKNOWN
  198. #define SDLK_WORLD_39   SDLK_UNKNOWN
  199. #define SDLK_WORLD_40   SDLK_UNKNOWN
  200. #define SDLK_WORLD_41   SDLK_UNKNOWN
  201. #define SDLK_WORLD_42   SDLK_UNKNOWN
  202. #define SDLK_WORLD_43   SDLK_UNKNOWN
  203. #define SDLK_WORLD_44   SDLK_UNKNOWN
  204. #define SDLK_WORLD_45   SDLK_UNKNOWN
  205. #define SDLK_WORLD_46   SDLK_UNKNOWN
  206. #define SDLK_WORLD_47   SDLK_UNKNOWN
  207. #define SDLK_WORLD_48   SDLK_UNKNOWN
  208. #define SDLK_WORLD_49   SDLK_UNKNOWN
  209. #define SDLK_WORLD_50   SDLK_UNKNOWN
  210. #define SDLK_WORLD_51   SDLK_UNKNOWN
  211. #endif
  212. { "W0",     255,    SDLK_WORLD_0       },
  213. { "W1",     255,    SDLK_WORLD_1       },
  214. { "W2",     255,    SDLK_WORLD_2       }, // 100
  215. { "W3",     255,    SDLK_WORLD_3       },
  216. { "W4",     255,    SDLK_WORLD_4       },
  217. { "W5",     255,    SDLK_WORLD_5       },
  218. { "W6",     255,    SDLK_WORLD_6       },
  219. { "W7",     255,    SDLK_WORLD_7       },
  220. { "W8",     255,    SDLK_WORLD_8       },
  221. { "W9",     255,    SDLK_WORLD_9       },
  222. { "W10",    255,    SDLK_WORLD_10      },
  223. { "W11",    255,    SDLK_WORLD_11      },
  224. { "W12",    255,    SDLK_WORLD_12      }, // 110
  225. { "W13",    255,    SDLK_WORLD_13      },
  226. { "W14",    255,    SDLK_WORLD_14      },
  227. { "W15",    255,    SDLK_WORLD_15      },
  228. { "W16",    255,    SDLK_WORLD_16      },
  229. { "W17",    255,    SDLK_WORLD_17      },
  230. { "W18",    255,    SDLK_WORLD_18      },
  231. { "W19",    255,    SDLK_WORLD_19      },
  232. { "W20",    255,    SDLK_WORLD_20      },
  233. { "W21",    255,    SDLK_WORLD_21      },
  234. { "W22",    255,    SDLK_WORLD_22      }, // 120
  235. { "W23",    255,    SDLK_WORLD_23      },
  236. { "W24",    255,    SDLK_WORLD_24      },
  237. { "W25",    255,    SDLK_WORLD_25      },
  238. { "W26",    255,    SDLK_WORLD_26      },
  239. { "W27",    255,    SDLK_WORLD_27      },
  240. { "W28",    255,    SDLK_WORLD_28      },
  241. { "W29",    255,    SDLK_WORLD_29      },
  242. { "W30",    255,    SDLK_WORLD_30      },
  243. { "W31",    255,    SDLK_WORLD_31      },
  244. { "W32",    255,    SDLK_WORLD_32      }, // 130
  245. { "W33",    255,    SDLK_WORLD_33      },
  246. { "W34",    255,    SDLK_WORLD_34      },
  247. { "W35",    255,    SDLK_WORLD_35      },
  248. { "W36",    255,    SDLK_WORLD_36      },
  249. { "W37",    255,    SDLK_WORLD_37      },
  250. { "W38",    255,    SDLK_WORLD_38      },
  251. { "W39",    255,    SDLK_WORLD_39      },
  252. { "W40",    255,    SDLK_WORLD_40      },
  253. { "W41",    255,    SDLK_WORLD_41      },
  254. { "W42",    255,    SDLK_WORLD_42      }, // 140
  255. { "W43",    255,    SDLK_WORLD_43      },
  256. { "W44",    255,    SDLK_WORLD_44      },
  257. { "W45",    255,    SDLK_WORLD_45      },
  258. { "W46",    255,    SDLK_WORLD_46      },
  259. { "W47",    255,    SDLK_WORLD_47      },
  260. { "W48",    255,    SDLK_WORLD_48      },
  261. { "W49",    255,    SDLK_WORLD_49      },
  262. { "W50",    255,    SDLK_WORLD_50      },
  263. { "W51",    255,    SDLK_WORLD_51      },
  264. { "",       255,    SDLK_UNKNOWN                 }, // 150
  265. { "",       255,    SDLK_UNKNOWN                 },
  266. { "",       255,    SDLK_UNKNOWN                 },
  267. { "",       255,    SDLK_UNKNOWN                 },
  268. { "",       255,    SDLK_UNKNOWN                 },
  269. { "",       255,    SDLK_UNKNOWN                 },
  270. { "PAD",    255,    SDLK_KP_ENTER      },
  271. { "RCTRL",  255,    SDLK_RCTRL         },
  272. #if SDL_MAJOR_VERSION == 2
  273. #define SDLK_LMETA      SDLK_UNKNOWN
  274. #define SDLK_RMETA      SDLK_UNKNOWN
  275. #endif
  276. { "LCMD",   255,    SDLK_LMETA         },
  277. { "RCMD",   255,    SDLK_RMETA         },
  278. { "",       255,    SDLK_UNKNOWN                 }, // 160
  279. { "",       255,    SDLK_UNKNOWN                 },
  280. { "",       255,    SDLK_UNKNOWN                 },
  281. { "",       255,    SDLK_UNKNOWN                 },
  282. { "",       255,    SDLK_UNKNOWN                 },
  283. { "",       255,    SDLK_UNKNOWN                 },
  284. { "",       255,    SDLK_UNKNOWN                 },
  285. { "",       255,    SDLK_UNKNOWN                 },
  286. { "",       255,    SDLK_UNKNOWN                 },
  287. { "",       255,    SDLK_UNKNOWN                 },
  288. { "",       255,    SDLK_UNKNOWN                 }, // 170
  289. { "",       255,    SDLK_UNKNOWN                 },
  290. { "",       255,    SDLK_UNKNOWN                 },
  291. { "",       255,    SDLK_UNKNOWN                 },
  292. { "",       255,    SDLK_UNKNOWN                 },
  293. { "",       255,    SDLK_UNKNOWN                 },
  294. { "",       255,    SDLK_UNKNOWN                 },
  295. { "",       255,    SDLK_UNKNOWN                 },
  296. { "",       255,    SDLK_UNKNOWN                 },
  297. { "",       255,    SDLK_UNKNOWN                 },
  298. { "",       255,    SDLK_UNKNOWN                 }, // 180
  299. { "PAD/",   255,    SDLK_KP_DIVIDE     },
  300. { "",       255,    SDLK_UNKNOWN                 },
  301. #if SDL_MAJOR_VERSION == 1
  302. #define SDLK_PRINTSCREEN        SDLK_PRINT
  303. #endif
  304. { "PRSCR",  255,    SDLK_PRINTSCREEN   },
  305. { "RALT",   255,    SDLK_RALT          },
  306. { "",       255,    SDLK_UNKNOWN                 },
  307. { "",       255,    SDLK_UNKNOWN                 },
  308. { "",       255,    SDLK_UNKNOWN                 },
  309. { "",       255,    SDLK_UNKNOWN                 },
  310. { "",       255,    SDLK_UNKNOWN                 },
  311. { "",       255,    SDLK_UNKNOWN                 }, // 190
  312. { "",       255,    SDLK_UNKNOWN                 },
  313. { "",       255,    SDLK_UNKNOWN                 },
  314. { "",       255,    SDLK_UNKNOWN                 },
  315. { "",       255,    SDLK_UNKNOWN                 },
  316. { "",       255,    SDLK_UNKNOWN                 },
  317. { "",       255,    SDLK_UNKNOWN                 },
  318. { "",       255,    SDLK_UNKNOWN                 },
  319. { "",       255,    SDLK_UNKNOWN                 },
  320. { "HOME",   255,    SDLK_HOME          },
  321. { "UP",     255,    SDLK_UP            }, // 200
  322. { "PGUP",   255,    SDLK_PAGEUP        },
  323. { "",       255,    SDLK_UNKNOWN                 },
  324. { "LEFT",   255,    SDLK_LEFT          },
  325. { "",       255,    SDLK_UNKNOWN                 },
  326. { "RIGHT",  255,    SDLK_RIGHT         },
  327. { "",       255,    SDLK_UNKNOWN                 },
  328. { "END",    255,    SDLK_END           },
  329. { "DOWN",   255,    SDLK_DOWN          },
  330. { "PGDN",   255,    SDLK_PAGEDOWN      },
  331. { "INS",    255,    SDLK_INSERT        }, // 210
  332. { "DEL",    255,    SDLK_DELETE        },
  333. #if SDL_MAJOR_VERSION == 1
  334. { "W52",    255,    SDLK_WORLD_52      },
  335. { "W53",    255,    SDLK_WORLD_53      },
  336. { "W54",    255,    SDLK_WORLD_54      },
  337. { "W55",    255,    SDLK_WORLD_55      },
  338. { "W56",    255,    SDLK_WORLD_56      },
  339. { "W57",    255,    SDLK_WORLD_57      },
  340. { "W58",    255,    SDLK_WORLD_58      },
  341. { "W59",    255,    SDLK_WORLD_59      },
  342. { "W60",    255,    SDLK_WORLD_60      }, // 220
  343. { "W61",    255,    SDLK_WORLD_61      },
  344. { "W62",    255,    SDLK_WORLD_62      },
  345. { "W63",    255,    SDLK_WORLD_63      },
  346. { "W64",    255,    SDLK_WORLD_64      },
  347. { "W65",    255,    SDLK_WORLD_65      },
  348. { "W66",    255,    SDLK_WORLD_66      },
  349. { "W67",    255,    SDLK_WORLD_67      },
  350. { "W68",    255,    SDLK_WORLD_68      },
  351. { "W69",    255,    SDLK_WORLD_69      },
  352. { "W70",    255,    SDLK_WORLD_70      }, // 230
  353. { "W71",    255,    SDLK_WORLD_71      },
  354. { "W72",    255,    SDLK_WORLD_72      },
  355. { "W73",    255,    SDLK_WORLD_73      },
  356. { "W74",    255,    SDLK_WORLD_74      },
  357. { "W75",    255,    SDLK_WORLD_75      },
  358. { "W76",    255,    SDLK_WORLD_76      },
  359. { "W77",    255,    SDLK_WORLD_77      },
  360. { "W78",    255,    SDLK_WORLD_78      },
  361. { "W79",    255,    SDLK_WORLD_79      },
  362. { "W80",    255,    SDLK_WORLD_80      }, // 240
  363. { "W81",    255,    SDLK_WORLD_81      },
  364. { "W82",    255,    SDLK_WORLD_82      },
  365. { "W83",    255,    SDLK_WORLD_83      },
  366. { "W84",    255,    SDLK_WORLD_84      },
  367. { "W85",    255,    SDLK_WORLD_85      },
  368. { "W86",    255,    SDLK_WORLD_86      },
  369. { "W87",    255,    SDLK_WORLD_87      },
  370. { "W88",    255,    SDLK_WORLD_88      },
  371. { "W89",    255,    SDLK_WORLD_89      },
  372. { "W90",    255,    SDLK_WORLD_90      }, // 250
  373. { "W91",    255,    SDLK_WORLD_91      },
  374. { "W92",    255,    SDLK_WORLD_92      },
  375. { "W93",    255,    SDLK_WORLD_93      },
  376. { "W94",    255,    SDLK_WORLD_94      },
  377. { "W95",    255,    SDLK_WORLD_95      }, // 255
  378. #endif
  379. }};
  380.  
  381. namespace {
  382.  
  383. struct d_event_keycommand : d_event
  384. {
  385.         const unsigned keycode;
  386.         constexpr d_event_keycommand(const event_type t, const unsigned k) :
  387.                 d_event(t), keycode(k)
  388.         {
  389.         }
  390. };
  391.  
  392. }
  393.  
  394. static int key_ismodlck(int keycode)
  395. {
  396.         switch (keycode)
  397.         {
  398.                 case KEY_LSHIFT:
  399.                 case KEY_RSHIFT:
  400.                 case KEY_LALT:
  401.                 case KEY_RALT:
  402.                 case KEY_LCTRL:
  403.                 case KEY_RCTRL:
  404.                 case KEY_LMETA:
  405.                 case KEY_RMETA:
  406.                         return KEY_ISMOD;
  407.                 case KEY_NUMLOCK:
  408.                 case KEY_SCROLLOCK:
  409.                 case KEY_CAPSLOCK:
  410.                         return KEY_ISLCK;
  411.                 default:
  412.                         return 0;
  413.         }
  414. }
  415.  
  416. unsigned char key_ascii()
  417. {
  418.         using std::move;
  419.         using std::next;
  420.         static std::array<unsigned char, KEY_BUFFER_SIZE> unibuffer;
  421.         auto src = begin(unicode_frame_buffer);
  422.         auto dst = next(begin(unibuffer), strlen(reinterpret_cast<const char *>(&unibuffer[0])));
  423.        
  424.         // move temporal chars from unicode_frame_buffer to empty space behind last unibuffer char (if any)
  425.         for (; dst != end(unibuffer); ++dst)
  426.                 if (*src != '\0')
  427.                 {
  428.                         *dst = *src;
  429.                         *src = '\0';
  430.                         ++src;
  431.                 }
  432.  
  433.         // unibuffer is not empty. store first char, remove it, shift all chars one step left and then print our char
  434.         if (unibuffer[0] != '\0')
  435.         {
  436.                 unsigned char retval = unibuffer[0];
  437.                 *move(next(unibuffer.begin()), unibuffer.end(), unibuffer.begin()) = 0;
  438.                 return retval;
  439.         }
  440.         else
  441.                 return 255;
  442. }
  443.  
  444. void pressed_keys::update(const std::size_t keycode, const uint8_t down)
  445. {
  446.         constexpr unsigned all_modifiers_combined = KEY_SHIFTED | KEY_ALTED | KEY_CTRLED | KEY_DEBUGGED | KEY_METAED;
  447.         constexpr unsigned all_modifiers_shifted = all_modifiers_combined >> modifier_shift;
  448.         static_assert(all_modifiers_combined == all_modifiers_shifted << modifier_shift, "shift error");
  449.         static_assert(all_modifiers_shifted == static_cast<uint8_t>(all_modifiers_shifted), "truncation error");
  450.         uint8_t mask;
  451.         keyd_pressed.update_pressed(keycode, down);
  452.         switch (keycode)
  453.         {
  454.                 case KEY_LSHIFT:
  455.                 case KEY_RSHIFT:
  456.                         mask = KEY_SHIFTED >> modifier_shift;
  457.                         break;
  458.                 case KEY_LALT:
  459.                 case KEY_RALT:
  460.                         mask = KEY_ALTED >> modifier_shift;
  461.                         break;
  462.                 case KEY_LCTRL:
  463.                 case KEY_RCTRL:
  464.                         mask = KEY_CTRLED >> modifier_shift;
  465.                         break;
  466.                 case KEY_DELETE:
  467.                         mask = KEY_DEBUGGED >> modifier_shift;
  468.                         break;
  469.                 case KEY_LMETA:
  470.                 case KEY_RMETA:
  471.                         mask = KEY_METAED >> modifier_shift;
  472.                         break;
  473.                 default:
  474.                         return;
  475.         }
  476.         if (down)
  477.                 modifier_cache |= mask;
  478.         else
  479.                 modifier_cache &= ~mask;
  480. }
  481.  
  482. window_event_result key_handler(const SDL_KeyboardEvent *const kevent)
  483. {
  484.         // Read SDLK symbol and state
  485.         const auto event_keysym = kevent->keysym.sym;
  486.         if (event_keysym == SDLK_UNKNOWN)
  487.                 return window_event_result::ignored;
  488.         const auto key_state = (kevent->state != SDL_RELEASED);
  489.  
  490.         // fill the unicode frame-related unicode buffer
  491.         if (key_state)
  492.         {
  493. #if SDL_MAJOR_VERSION == 1
  494.                 const auto sym = kevent->keysym.unicode;
  495. #elif SDL_MAJOR_VERSION == 2
  496.                 const auto sym = kevent->keysym.sym;
  497. #endif
  498.                 if (sym > 31 && sym < 255)
  499.                 {
  500.                         range_for (auto &i, unicode_frame_buffer)
  501.                                 if (i == '\0')
  502.                                 {
  503.                                         i = sym;
  504.                                         break;
  505.                                 }
  506.                 }
  507.         }
  508.  
  509.         //=====================================================
  510.         auto re = key_properties.rend();
  511.         auto fi = std::find_if(key_properties.rbegin(), re, [event_keysym](const key_props &k) { return k.sym == event_keysym; });
  512.         if (fi == re)
  513.                 return window_event_result::ignored;
  514.         unsigned keycode = std::distance(key_properties.begin(), std::next(fi).base());
  515.         if (keycode == 0)
  516.                 return window_event_result::ignored;
  517.  
  518.         /*
  519.          * process the key if:
  520.          * - it's a valid key AND
  521.          * - if the keystate has changed OR
  522.          * - key state same as last one and game accepts key repeats but keep out mod/lock keys
  523.          */
  524.         if (key_state != keyd_pressed[keycode] || (keyd_repeat && !key_ismodlck(keycode)))
  525.         {
  526.                 // now update the key props
  527.                 keyd_pressed.update(keycode, key_state);
  528.                 const auto raw_keycode = keycode;
  529.                 keycode |= keyd_pressed.get_modifiers();
  530.  
  531.                 // We allowed the key to be added to the queue for now,
  532.                 // because there are still input loops without associated windows
  533.                 const d_event_keycommand event{key_state ? EVENT_KEY_COMMAND : EVENT_KEY_RELEASE, keycode};
  534.                 con_printf(CON_DEBUG, "Sending event %s: %s %s %s %s %s %s",
  535.                                 (key_state)                  ? "EVENT_KEY_COMMAND": "EVENT_KEY_RELEASE",
  536.                                 (keycode & KEY_METAED)  ? "META" : "",
  537.                                 (keycode & KEY_DEBUGGED)        ? "DEBUG" : "",
  538.                                 (keycode & KEY_CTRLED)  ? "CTRL" : "",
  539.                                 (keycode & KEY_ALTED)   ? "ALT" : "",
  540.                                 (keycode & KEY_SHIFTED) ? "SHIFT" : "",
  541.                                 key_properties[raw_keycode].key_text
  542.                                 );
  543.                 return event_send(event);
  544.         }
  545.         return window_event_result::ignored;
  546. }
  547.  
  548. void key_init()
  549. {
  550. #if SDL_MAJOR_VERSION == 1
  551.         SDL_EnableUNICODE(1);
  552. #endif
  553.         key_toggle_repeat(1);
  554.  
  555.         keyd_time_when_last_pressed = timer_query();
  556.         // Clear the keyboard array
  557.         key_flush();
  558. }
  559.  
  560. static void restore_sticky_key(const uint8_t *keystate, const unsigned i)
  561. {
  562. #if SDL_MAJOR_VERSION == 1
  563.         const auto ki = key_properties[i].sym;
  564. #elif SDL_MAJOR_VERSION == 2
  565.         const auto ki = i;
  566. #endif
  567.         const auto v = keystate[ki];    // do not flush status of sticky keys
  568.         keyd_pressed.update_pressed(i, v);
  569. }
  570.  
  571. void key_flush()
  572. {
  573.         //Clear the unicode buffer
  574.         unicode_frame_buffer = {};
  575.         keyd_pressed = {};
  576.         if (unlikely(CGameArg.CtlNoStickyKeys))
  577.                 return;
  578. #if SDL_MAJOR_VERSION == 1
  579.         const auto &keystate = SDL_GetKeyState(nullptr);
  580. #define DXX_SDL_STICKY_KEYS     {KEY_CAPSLOCK, KEY_NUMLOCK, KEY_SCROLLOCK}
  581. #elif SDL_MAJOR_VERSION == 2
  582.         const auto &keystate = SDL_GetKeyboardState(nullptr);
  583. #define DXX_SDL_STICKY_KEYS     {SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_NUMLOCKCLEAR}
  584. #endif
  585.         range_for (const auto key, DXX_SDL_STICKY_KEYS)
  586. #undef DXX_SDL_STICKY_KEYS
  587.                 restore_sticky_key(keystate, key);
  588. }
  589.  
  590. void event_keycommand_send(unsigned key) {
  591.         const d_event_keycommand event{EVENT_KEY_COMMAND, key};
  592.         event_send(event);
  593. }
  594.  
  595. int event_key_get(const d_event &event)
  596. {
  597.         auto &e = static_cast<const d_event_keycommand &>(event);
  598.         Assert(e.type == EVENT_KEY_COMMAND || e.type == EVENT_KEY_RELEASE);
  599.         return e.keycode;
  600. }
  601.  
  602. // same as above but without mod states
  603. int event_key_get_raw(const d_event &event)
  604. {
  605.         return event_key_get(event) & ~(KEY_SHIFTED | KEY_ALTED | KEY_CTRLED | KEY_DEBUGGED | KEY_METAED);
  606. }
  607.  
  608. void key_toggle_repeat1()
  609. {
  610. #if SDL_MAJOR_VERSION == 1
  611.         if (SDL_EnableKeyRepeat(KEY_REPEAT_DELAY, KEY_REPEAT_INTERVAL) == 0)
  612. #endif
  613.                 keyd_repeat = 1;
  614.         key_flush();
  615. }
  616.  
  617. void key_toggle_repeat0()
  618. {
  619. #if SDL_MAJOR_VERSION == 1
  620.         SDL_EnableKeyRepeat(0, 0);
  621. #endif
  622.         keyd_repeat = 0;
  623.         key_flush();
  624. }
  625.  
  626. }
  627.