Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}