FreeRDP
Loading...
Searching...
No Matches
SDL3/sdl_input.cpp
1
20#include "sdl_input.hpp"
21#include "sdl_disp.hpp"
22#include "sdl_context.hpp"
23#include "sdl_utils.hpp"
24#include "sdl_prefs.hpp"
25#include "sdl_touch.hpp"
26
27#include <SDL3/SDL_oldnames.h>
28
29#include <array>
30#include <map>
31#include <tuple>
32
33#include <freerdp/utils/string.h>
34#include <freerdp/scancode.h>
35#include <freerdp/locale/keyboard.h>
36#include <freerdp/locale/locale.h>
37
38#include <freerdp/log.h>
39
40typedef struct
41{
42 Uint32 sdl;
43 const char* sdl_name;
44 UINT32 rdp;
45 const char* rdp_name;
46} scancode_entry_t;
47
48#define STR(x) #x
49#define ENTRY(x, y) { x, STR(x), y, #y }
50static const scancode_entry_t map[] = {
51 ENTRY(SDL_SCANCODE_UNKNOWN, RDP_SCANCODE_UNKNOWN),
52 ENTRY(SDL_SCANCODE_A, RDP_SCANCODE_KEY_A),
53 ENTRY(SDL_SCANCODE_B, RDP_SCANCODE_KEY_B),
54 ENTRY(SDL_SCANCODE_C, RDP_SCANCODE_KEY_C),
55 ENTRY(SDL_SCANCODE_D, RDP_SCANCODE_KEY_D),
56 ENTRY(SDL_SCANCODE_E, RDP_SCANCODE_KEY_E),
57 ENTRY(SDL_SCANCODE_F, RDP_SCANCODE_KEY_F),
58 ENTRY(SDL_SCANCODE_G, RDP_SCANCODE_KEY_G),
59 ENTRY(SDL_SCANCODE_H, RDP_SCANCODE_KEY_H),
60 ENTRY(SDL_SCANCODE_I, RDP_SCANCODE_KEY_I),
61 ENTRY(SDL_SCANCODE_J, RDP_SCANCODE_KEY_J),
62 ENTRY(SDL_SCANCODE_K, RDP_SCANCODE_KEY_K),
63 ENTRY(SDL_SCANCODE_L, RDP_SCANCODE_KEY_L),
64 ENTRY(SDL_SCANCODE_M, RDP_SCANCODE_KEY_M),
65 ENTRY(SDL_SCANCODE_N, RDP_SCANCODE_KEY_N),
66 ENTRY(SDL_SCANCODE_O, RDP_SCANCODE_KEY_O),
67 ENTRY(SDL_SCANCODE_P, RDP_SCANCODE_KEY_P),
68 ENTRY(SDL_SCANCODE_Q, RDP_SCANCODE_KEY_Q),
69 ENTRY(SDL_SCANCODE_R, RDP_SCANCODE_KEY_R),
70 ENTRY(SDL_SCANCODE_S, RDP_SCANCODE_KEY_S),
71 ENTRY(SDL_SCANCODE_T, RDP_SCANCODE_KEY_T),
72 ENTRY(SDL_SCANCODE_U, RDP_SCANCODE_KEY_U),
73 ENTRY(SDL_SCANCODE_V, RDP_SCANCODE_KEY_V),
74 ENTRY(SDL_SCANCODE_W, RDP_SCANCODE_KEY_W),
75 ENTRY(SDL_SCANCODE_X, RDP_SCANCODE_KEY_X),
76 ENTRY(SDL_SCANCODE_Y, RDP_SCANCODE_KEY_Y),
77 ENTRY(SDL_SCANCODE_Z, RDP_SCANCODE_KEY_Z),
78 ENTRY(SDL_SCANCODE_1, RDP_SCANCODE_KEY_1),
79 ENTRY(SDL_SCANCODE_2, RDP_SCANCODE_KEY_2),
80 ENTRY(SDL_SCANCODE_3, RDP_SCANCODE_KEY_3),
81 ENTRY(SDL_SCANCODE_4, RDP_SCANCODE_KEY_4),
82 ENTRY(SDL_SCANCODE_5, RDP_SCANCODE_KEY_5),
83 ENTRY(SDL_SCANCODE_6, RDP_SCANCODE_KEY_6),
84 ENTRY(SDL_SCANCODE_7, RDP_SCANCODE_KEY_7),
85 ENTRY(SDL_SCANCODE_8, RDP_SCANCODE_KEY_8),
86 ENTRY(SDL_SCANCODE_9, RDP_SCANCODE_KEY_9),
87 ENTRY(SDL_SCANCODE_0, RDP_SCANCODE_KEY_0),
88 ENTRY(SDL_SCANCODE_RETURN, RDP_SCANCODE_RETURN),
89 ENTRY(SDL_SCANCODE_ESCAPE, RDP_SCANCODE_ESCAPE),
90 ENTRY(SDL_SCANCODE_BACKSPACE, RDP_SCANCODE_BACKSPACE),
91 ENTRY(SDL_SCANCODE_TAB, RDP_SCANCODE_TAB),
92 ENTRY(SDL_SCANCODE_SPACE, RDP_SCANCODE_SPACE),
93 ENTRY(SDL_SCANCODE_MINUS, RDP_SCANCODE_OEM_MINUS),
94 ENTRY(SDL_SCANCODE_CAPSLOCK, RDP_SCANCODE_CAPSLOCK),
95 ENTRY(SDL_SCANCODE_F1, RDP_SCANCODE_F1),
96 ENTRY(SDL_SCANCODE_F2, RDP_SCANCODE_F2),
97 ENTRY(SDL_SCANCODE_F3, RDP_SCANCODE_F3),
98 ENTRY(SDL_SCANCODE_F4, RDP_SCANCODE_F4),
99 ENTRY(SDL_SCANCODE_F5, RDP_SCANCODE_F5),
100 ENTRY(SDL_SCANCODE_F6, RDP_SCANCODE_F6),
101 ENTRY(SDL_SCANCODE_F7, RDP_SCANCODE_F7),
102 ENTRY(SDL_SCANCODE_F8, RDP_SCANCODE_F8),
103 ENTRY(SDL_SCANCODE_F9, RDP_SCANCODE_F9),
104 ENTRY(SDL_SCANCODE_F10, RDP_SCANCODE_F10),
105 ENTRY(SDL_SCANCODE_F11, RDP_SCANCODE_F11),
106 ENTRY(SDL_SCANCODE_F12, RDP_SCANCODE_F12),
107 ENTRY(SDL_SCANCODE_F13, RDP_SCANCODE_F13),
108 ENTRY(SDL_SCANCODE_F14, RDP_SCANCODE_F14),
109 ENTRY(SDL_SCANCODE_F15, RDP_SCANCODE_F15),
110 ENTRY(SDL_SCANCODE_F16, RDP_SCANCODE_F16),
111 ENTRY(SDL_SCANCODE_F17, RDP_SCANCODE_F17),
112 ENTRY(SDL_SCANCODE_F18, RDP_SCANCODE_F18),
113 ENTRY(SDL_SCANCODE_F19, RDP_SCANCODE_F19),
114 ENTRY(SDL_SCANCODE_F20, RDP_SCANCODE_F20),
115 ENTRY(SDL_SCANCODE_F21, RDP_SCANCODE_F21),
116 ENTRY(SDL_SCANCODE_F22, RDP_SCANCODE_F22),
117 ENTRY(SDL_SCANCODE_F23, RDP_SCANCODE_F23),
118 ENTRY(SDL_SCANCODE_F24, RDP_SCANCODE_F24),
119 ENTRY(SDL_SCANCODE_NUMLOCKCLEAR, RDP_SCANCODE_NUMLOCK),
120 ENTRY(SDL_SCANCODE_KP_DIVIDE, RDP_SCANCODE_DIVIDE),
121 ENTRY(SDL_SCANCODE_KP_MULTIPLY, RDP_SCANCODE_MULTIPLY),
122 ENTRY(SDL_SCANCODE_KP_MINUS, RDP_SCANCODE_SUBTRACT),
123 ENTRY(SDL_SCANCODE_KP_PLUS, RDP_SCANCODE_ADD),
124 ENTRY(SDL_SCANCODE_KP_ENTER, RDP_SCANCODE_RETURN_KP),
125 ENTRY(SDL_SCANCODE_KP_1, RDP_SCANCODE_NUMPAD1),
126 ENTRY(SDL_SCANCODE_KP_2, RDP_SCANCODE_NUMPAD2),
127 ENTRY(SDL_SCANCODE_KP_3, RDP_SCANCODE_NUMPAD3),
128 ENTRY(SDL_SCANCODE_KP_4, RDP_SCANCODE_NUMPAD4),
129 ENTRY(SDL_SCANCODE_KP_5, RDP_SCANCODE_NUMPAD5),
130 ENTRY(SDL_SCANCODE_KP_6, RDP_SCANCODE_NUMPAD6),
131 ENTRY(SDL_SCANCODE_KP_7, RDP_SCANCODE_NUMPAD7),
132 ENTRY(SDL_SCANCODE_KP_8, RDP_SCANCODE_NUMPAD8),
133 ENTRY(SDL_SCANCODE_KP_9, RDP_SCANCODE_NUMPAD9),
134 ENTRY(SDL_SCANCODE_KP_0, RDP_SCANCODE_NUMPAD0),
135 ENTRY(SDL_SCANCODE_KP_PERIOD, RDP_SCANCODE_DECIMAL),
136 ENTRY(SDL_SCANCODE_LCTRL, RDP_SCANCODE_LCONTROL),
137 ENTRY(SDL_SCANCODE_LSHIFT, RDP_SCANCODE_LSHIFT),
138 ENTRY(SDL_SCANCODE_LALT, RDP_SCANCODE_LMENU),
139 ENTRY(SDL_SCANCODE_LGUI, RDP_SCANCODE_LWIN),
140 ENTRY(SDL_SCANCODE_RCTRL, RDP_SCANCODE_RCONTROL),
141 ENTRY(SDL_SCANCODE_RSHIFT, RDP_SCANCODE_RSHIFT),
142 ENTRY(SDL_SCANCODE_RALT, RDP_SCANCODE_RMENU),
143 ENTRY(SDL_SCANCODE_RGUI, RDP_SCANCODE_RWIN),
144 ENTRY(SDL_SCANCODE_MODE, RDP_SCANCODE_APPS),
145 ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
146 ENTRY(SDL_SCANCODE_VOLUMEUP, RDP_SCANCODE_VOLUME_UP),
147 ENTRY(SDL_SCANCODE_VOLUMEDOWN, RDP_SCANCODE_VOLUME_DOWN),
148 ENTRY(SDL_SCANCODE_GRAVE, RDP_SCANCODE_OEM_3),
149 ENTRY(SDL_SCANCODE_COMMA, RDP_SCANCODE_OEM_COMMA),
150 ENTRY(SDL_SCANCODE_PERIOD, RDP_SCANCODE_OEM_PERIOD),
151 ENTRY(SDL_SCANCODE_SLASH, RDP_SCANCODE_OEM_2),
152 ENTRY(SDL_SCANCODE_BACKSLASH, RDP_SCANCODE_OEM_5),
153 ENTRY(SDL_SCANCODE_SCROLLLOCK, RDP_SCANCODE_SCROLLLOCK),
154 ENTRY(SDL_SCANCODE_INSERT, RDP_SCANCODE_INSERT),
155 ENTRY(SDL_SCANCODE_PRINTSCREEN, RDP_SCANCODE_PRINTSCREEN),
156 ENTRY(SDL_SCANCODE_HOME, RDP_SCANCODE_HOME),
157 ENTRY(SDL_SCANCODE_DELETE, RDP_SCANCODE_DELETE),
158 ENTRY(SDL_SCANCODE_RIGHT, RDP_SCANCODE_RIGHT),
159 ENTRY(SDL_SCANCODE_LEFT, RDP_SCANCODE_LEFT),
160 ENTRY(SDL_SCANCODE_DOWN, RDP_SCANCODE_DOWN),
161 ENTRY(SDL_SCANCODE_UP, RDP_SCANCODE_UP),
162 ENTRY(SDL_SCANCODE_SEMICOLON, RDP_SCANCODE_OEM_1),
163 ENTRY(SDL_SCANCODE_PAUSE, RDP_SCANCODE_PAUSE),
164 ENTRY(SDL_SCANCODE_PAGEUP, RDP_SCANCODE_PRIOR),
165 ENTRY(SDL_SCANCODE_END, RDP_SCANCODE_END),
166 ENTRY(SDL_SCANCODE_PAGEDOWN, RDP_SCANCODE_NEXT),
167 ENTRY(SDL_SCANCODE_MEDIA_NEXT_TRACK, RDP_SCANCODE_MEDIA_NEXT_TRACK),
168 ENTRY(SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, RDP_SCANCODE_MEDIA_PREV_TRACK),
169 ENTRY(SDL_SCANCODE_MEDIA_STOP, RDP_SCANCODE_MEDIA_STOP),
170 ENTRY(SDL_SCANCODE_MEDIA_PLAY, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
171 ENTRY(SDL_SCANCODE_MEDIA_PAUSE, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
172 ENTRY(SDL_SCANCODE_MEDIA_PLAY_PAUSE, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
173 ENTRY(SDL_SCANCODE_MEDIA_SELECT, RDP_SCANCODE_LAUNCH_MEDIA_SELECT),
174 ENTRY(SDL_SCANCODE_SYSREQ, RDP_SCANCODE_SYSREQ),
175 ENTRY(SDL_SCANCODE_LEFTBRACKET, RDP_SCANCODE_OEM_4),
176 ENTRY(SDL_SCANCODE_RIGHTBRACKET, RDP_SCANCODE_OEM_6),
177 ENTRY(SDL_SCANCODE_APOSTROPHE, RDP_SCANCODE_OEM_7),
178 ENTRY(SDL_SCANCODE_NONUSBACKSLASH, RDP_SCANCODE_OEM_102),
179 ENTRY(SDL_SCANCODE_SLEEP, RDP_SCANCODE_SLEEP),
180 ENTRY(SDL_SCANCODE_EQUALS, RDP_SCANCODE_OEM_PLUS),
181 ENTRY(SDL_SCANCODE_KP_COMMA, RDP_SCANCODE_DECIMAL),
182 ENTRY(SDL_SCANCODE_FIND, RDP_SCANCODE_BROWSER_SEARCH),
183 ENTRY(SDL_SCANCODE_RETURN2, RDP_SCANCODE_RETURN_KP),
184 ENTRY(SDL_SCANCODE_AC_SEARCH, RDP_SCANCODE_BROWSER_SEARCH),
185 ENTRY(SDL_SCANCODE_AC_HOME, RDP_SCANCODE_BROWSER_HOME),
186 ENTRY(SDL_SCANCODE_AC_BACK, RDP_SCANCODE_BROWSER_BACK),
187 ENTRY(SDL_SCANCODE_AC_FORWARD, RDP_SCANCODE_BROWSER_FORWARD),
188 ENTRY(SDL_SCANCODE_AC_STOP, RDP_SCANCODE_BROWSER_STOP),
189
190 ENTRY(SDL_SCANCODE_NONUSHASH, RDP_SCANCODE_UNKNOWN),
191 ENTRY(SDL_SCANCODE_APPLICATION, RDP_SCANCODE_APPS),
192 ENTRY(SDL_SCANCODE_POWER, RDP_SCANCODE_UNKNOWN),
193 ENTRY(SDL_SCANCODE_KP_EQUALS, RDP_SCANCODE_UNKNOWN),
194 ENTRY(SDL_SCANCODE_EXECUTE, RDP_SCANCODE_UNKNOWN),
195 ENTRY(SDL_SCANCODE_HELP, RDP_SCANCODE_UNKNOWN),
196 ENTRY(SDL_SCANCODE_MENU, RDP_SCANCODE_UNKNOWN),
197 ENTRY(SDL_SCANCODE_SELECT, RDP_SCANCODE_UNKNOWN),
198 ENTRY(SDL_SCANCODE_STOP, RDP_SCANCODE_UNKNOWN),
199 ENTRY(SDL_SCANCODE_AGAIN, RDP_SCANCODE_UNKNOWN),
200 ENTRY(SDL_SCANCODE_UNDO, RDP_SCANCODE_UNKNOWN),
201 ENTRY(SDL_SCANCODE_CUT, RDP_SCANCODE_UNKNOWN),
202 ENTRY(SDL_SCANCODE_COPY, RDP_SCANCODE_UNKNOWN),
203 ENTRY(SDL_SCANCODE_PASTE, RDP_SCANCODE_UNKNOWN),
204 ENTRY(SDL_SCANCODE_KP_EQUALSAS400, RDP_SCANCODE_UNKNOWN),
205 ENTRY(SDL_SCANCODE_INTERNATIONAL1, RDP_SCANCODE_ABNT_C1),
206 ENTRY(SDL_SCANCODE_INTERNATIONAL2, RDP_SCANCODE_HIRAGANA),
207 ENTRY(SDL_SCANCODE_INTERNATIONAL3, RDP_SCANCODE_BACKSLASH_JP),
208 ENTRY(SDL_SCANCODE_INTERNATIONAL4, RDP_SCANCODE_CONVERT_JP),
209 ENTRY(SDL_SCANCODE_INTERNATIONAL5, RDP_SCANCODE_NONCONVERT_JP),
210 ENTRY(SDL_SCANCODE_INTERNATIONAL6, RDP_SCANCODE_UNKNOWN),
211 ENTRY(SDL_SCANCODE_INTERNATIONAL7, RDP_SCANCODE_UNKNOWN),
212 ENTRY(SDL_SCANCODE_INTERNATIONAL8, RDP_SCANCODE_UNKNOWN),
213 ENTRY(SDL_SCANCODE_INTERNATIONAL9, RDP_SCANCODE_UNKNOWN),
214 ENTRY(SDL_SCANCODE_LANG1, RDP_SCANCODE_KANA_HANGUL),
215 ENTRY(SDL_SCANCODE_LANG2, RDP_SCANCODE_HANJA_KANJI),
216 ENTRY(SDL_SCANCODE_LANG3, RDP_SCANCODE_UNKNOWN),
217 ENTRY(SDL_SCANCODE_LANG4, RDP_SCANCODE_UNKNOWN),
218 ENTRY(SDL_SCANCODE_LANG5, RDP_SCANCODE_UNKNOWN),
219 ENTRY(SDL_SCANCODE_LANG6, RDP_SCANCODE_UNKNOWN),
220 ENTRY(SDL_SCANCODE_LANG7, RDP_SCANCODE_UNKNOWN),
221 ENTRY(SDL_SCANCODE_LANG8, RDP_SCANCODE_UNKNOWN),
222 ENTRY(SDL_SCANCODE_LANG9, RDP_SCANCODE_UNKNOWN),
223 ENTRY(SDL_SCANCODE_ALTERASE, RDP_SCANCODE_UNKNOWN),
224 ENTRY(SDL_SCANCODE_CANCEL, RDP_SCANCODE_UNKNOWN),
225 ENTRY(SDL_SCANCODE_CLEAR, RDP_SCANCODE_UNKNOWN),
226 ENTRY(SDL_SCANCODE_PRIOR, RDP_SCANCODE_UNKNOWN),
227 ENTRY(SDL_SCANCODE_SEPARATOR, RDP_SCANCODE_UNKNOWN),
228 ENTRY(SDL_SCANCODE_OUT, RDP_SCANCODE_UNKNOWN),
229 ENTRY(SDL_SCANCODE_OPER, RDP_SCANCODE_UNKNOWN),
230 ENTRY(SDL_SCANCODE_CLEARAGAIN, RDP_SCANCODE_UNKNOWN),
231 ENTRY(SDL_SCANCODE_CRSEL, RDP_SCANCODE_UNKNOWN),
232 ENTRY(SDL_SCANCODE_EXSEL, RDP_SCANCODE_UNKNOWN),
233 ENTRY(SDL_SCANCODE_KP_00, RDP_SCANCODE_UNKNOWN),
234 ENTRY(SDL_SCANCODE_KP_000, RDP_SCANCODE_UNKNOWN),
235 ENTRY(SDL_SCANCODE_THOUSANDSSEPARATOR, RDP_SCANCODE_UNKNOWN),
236 ENTRY(SDL_SCANCODE_DECIMALSEPARATOR, RDP_SCANCODE_UNKNOWN),
237 ENTRY(SDL_SCANCODE_CURRENCYUNIT, RDP_SCANCODE_UNKNOWN),
238 ENTRY(SDL_SCANCODE_CURRENCYSUBUNIT, RDP_SCANCODE_UNKNOWN),
239 ENTRY(SDL_SCANCODE_KP_LEFTPAREN, RDP_SCANCODE_UNKNOWN),
240 ENTRY(SDL_SCANCODE_KP_RIGHTPAREN, RDP_SCANCODE_UNKNOWN),
241 ENTRY(SDL_SCANCODE_KP_LEFTBRACE, RDP_SCANCODE_UNKNOWN),
242 ENTRY(SDL_SCANCODE_KP_RIGHTBRACE, RDP_SCANCODE_UNKNOWN),
243 ENTRY(SDL_SCANCODE_KP_TAB, RDP_SCANCODE_UNKNOWN),
244 ENTRY(SDL_SCANCODE_KP_BACKSPACE, RDP_SCANCODE_UNKNOWN),
245 ENTRY(SDL_SCANCODE_KP_A, RDP_SCANCODE_UNKNOWN),
246 ENTRY(SDL_SCANCODE_KP_B, RDP_SCANCODE_UNKNOWN),
247 ENTRY(SDL_SCANCODE_KP_C, RDP_SCANCODE_UNKNOWN),
248 ENTRY(SDL_SCANCODE_KP_D, RDP_SCANCODE_UNKNOWN),
249 ENTRY(SDL_SCANCODE_KP_E, RDP_SCANCODE_UNKNOWN),
250 ENTRY(SDL_SCANCODE_KP_F, RDP_SCANCODE_UNKNOWN),
251 ENTRY(SDL_SCANCODE_KP_XOR, RDP_SCANCODE_UNKNOWN),
252 ENTRY(SDL_SCANCODE_KP_POWER, RDP_SCANCODE_UNKNOWN),
253 ENTRY(SDL_SCANCODE_KP_PERCENT, RDP_SCANCODE_UNKNOWN),
254 ENTRY(SDL_SCANCODE_KP_LESS, RDP_SCANCODE_UNKNOWN),
255 ENTRY(SDL_SCANCODE_KP_GREATER, RDP_SCANCODE_UNKNOWN),
256 ENTRY(SDL_SCANCODE_KP_AMPERSAND, RDP_SCANCODE_UNKNOWN),
257 ENTRY(SDL_SCANCODE_KP_DBLAMPERSAND, RDP_SCANCODE_UNKNOWN),
258 ENTRY(SDL_SCANCODE_KP_VERTICALBAR, RDP_SCANCODE_UNKNOWN),
259 ENTRY(SDL_SCANCODE_KP_DBLVERTICALBAR, RDP_SCANCODE_UNKNOWN),
260 ENTRY(SDL_SCANCODE_KP_COLON, RDP_SCANCODE_UNKNOWN),
261 ENTRY(SDL_SCANCODE_KP_HASH, RDP_SCANCODE_UNKNOWN),
262 ENTRY(SDL_SCANCODE_KP_SPACE, RDP_SCANCODE_UNKNOWN),
263 ENTRY(SDL_SCANCODE_KP_AT, RDP_SCANCODE_UNKNOWN),
264 ENTRY(SDL_SCANCODE_KP_EXCLAM, RDP_SCANCODE_UNKNOWN),
265 ENTRY(SDL_SCANCODE_KP_MEMSTORE, RDP_SCANCODE_UNKNOWN),
266 ENTRY(SDL_SCANCODE_KP_MEMRECALL, RDP_SCANCODE_UNKNOWN),
267 ENTRY(SDL_SCANCODE_KP_MEMCLEAR, RDP_SCANCODE_UNKNOWN),
268 ENTRY(SDL_SCANCODE_KP_MEMADD, RDP_SCANCODE_UNKNOWN),
269 ENTRY(SDL_SCANCODE_KP_MEMSUBTRACT, RDP_SCANCODE_UNKNOWN),
270 ENTRY(SDL_SCANCODE_KP_MEMMULTIPLY, RDP_SCANCODE_UNKNOWN),
271 ENTRY(SDL_SCANCODE_KP_MEMDIVIDE, RDP_SCANCODE_UNKNOWN),
272 ENTRY(SDL_SCANCODE_KP_PLUSMINUS, RDP_SCANCODE_UNKNOWN),
273 ENTRY(SDL_SCANCODE_KP_CLEAR, RDP_SCANCODE_UNKNOWN),
274 ENTRY(SDL_SCANCODE_KP_CLEARENTRY, RDP_SCANCODE_UNKNOWN),
275 ENTRY(SDL_SCANCODE_KP_BINARY, RDP_SCANCODE_UNKNOWN),
276 ENTRY(SDL_SCANCODE_KP_OCTAL, RDP_SCANCODE_UNKNOWN),
277 ENTRY(SDL_SCANCODE_KP_DECIMAL, RDP_SCANCODE_DECIMAL),
278 ENTRY(SDL_SCANCODE_KP_HEXADECIMAL, RDP_SCANCODE_UNKNOWN),
279 ENTRY(SDL_SCANCODE_AC_REFRESH, RDP_SCANCODE_UNKNOWN),
280 ENTRY(SDL_SCANCODE_AC_BOOKMARKS, RDP_SCANCODE_UNKNOWN),
281 ENTRY(SDL_SCANCODE_MEDIA_EJECT, RDP_SCANCODE_UNKNOWN),
282 ENTRY(SDL_SCANCODE_MEDIA_REWIND, RDP_SCANCODE_UNKNOWN),
283 ENTRY(SDL_SCANCODE_MEDIA_FAST_FORWARD, RDP_SCANCODE_UNKNOWN)
284};
285
286[[nodiscard]] static UINT32 sdl_get_kbd_flags()
287{
288 UINT32 flags = 0;
289
290 SDL_Keymod mod = SDL_GetModState();
291 if ((mod & SDL_KMOD_NUM) != 0)
292 flags |= KBD_SYNC_NUM_LOCK;
293 if ((mod & SDL_KMOD_CAPS) != 0)
294 flags |= KBD_SYNC_CAPS_LOCK;
295 if ((mod & SDL_KMOD_SCROLL) != 0)
296 flags |= KBD_SYNC_SCROLL_LOCK;
297
298 // TODO: KBD_SYNC_KANA_LOCK
299
300 return flags;
301}
302
303[[nodiscard]] static FREERDP_CLIENT_KBD_MOD sdl_get_kbd_modmask(SDL_Keymod mod)
304{
305 static const std::array<std::pair<SDL_Keymod, uint32_t>, 8> masks = {
306 { { SDL_KMOD_LSHIFT, FREERDP_CLIENT_KBD_MOD_LSHIFT },
307 { SDL_KMOD_RSHIFT, FREERDP_CLIENT_KBD_MOD_RSHIFT },
308 { SDL_KMOD_LALT, FREERDP_CLIENT_KBD_MOD_LMENU },
309 { SDL_KMOD_RALT, FREERDP_CLIENT_KBD_MOD_RMENU },
310 { SDL_KMOD_LCTRL, FREERDP_CLIENT_KBD_MOD_LCONTROL },
311 { SDL_KMOD_RCTRL, FREERDP_CLIENT_KBD_MOD_RCONTROL },
312 { SDL_KMOD_LGUI, FREERDP_CLIENT_KBD_MOD_LWIN },
313 { SDL_KMOD_RGUI, FREERDP_CLIENT_KBD_MOD_RWIN } }
314 };
315
316 uint32_t modmask = FREERDP_CLIENT_KBD_MOD_NONE;
317 for (const auto& [sdl, rdp] : masks)
318 {
319 if ((mod & sdl) != 0)
320 modmask |= rdp;
321 }
322 return static_cast<FREERDP_CLIENT_KBD_MOD>(modmask);
323}
324
325bool sdlInput::keyboard_sync_state()
326{
327 const UINT32 syncFlags = sdl_get_kbd_flags();
328 return freerdp_input_send_synchronize_event(_sdl->context()->input, syncFlags);
329}
330
331bool sdlInput::keyboard_focus_in()
332{
333 auto input = _sdl->context()->input;
334 WINPR_ASSERT(input);
335
336 auto syncFlags = sdl_get_kbd_flags();
337 if (!freerdp_input_send_focus_in_event(input, WINPR_ASSERTING_INT_CAST(uint16_t, syncFlags)))
338 return false;
339
340 /* finish with a mouse pointer position like mstsc.exe if required */
341 // TODO: fullscreen/remote app
342 float fx = 0.0f;
343 float fy = 0.0f;
344 SDL_GetMouseState(&fx, &fy);
345
346 auto w = SDL_GetMouseFocus();
347 const auto& pos = _sdl->screenToPixel(SDL_GetWindowID(w), SDL_FPoint{ fx, fy });
348
349 return freerdp_client_send_button_event(_sdl->common(), FALSE, PTR_FLAGS_MOVE,
350 static_cast<Sint32>(pos.x), static_cast<Sint32>(pos.y));
351}
352
353/* This function is called to update the keyboard indicator LED */
354BOOL sdlInput::keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
355{
356 WINPR_UNUSED(context);
357
358 SDL_Keymod state = SDL_KMOD_NONE;
359
360 if ((led_flags & KBD_SYNC_NUM_LOCK) != 0)
361 state |= SDL_KMOD_NUM;
362 if ((led_flags & KBD_SYNC_CAPS_LOCK) != 0)
363 state |= SDL_KMOD_CAPS;
364 if ((led_flags & KBD_SYNC_SCROLL_LOCK) != 0)
365 state |= SDL_KMOD_SCROLL;
366 if ((led_flags & KBD_SYNC_KANA_LOCK) != 0)
367 state |= SDL_KMOD_LEVEL5;
368
369 SDL_SetModState(state);
370
371 return TRUE;
372}
373
374/* This function is called to set the IME state */
375BOOL sdlInput::keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
376 UINT32 imeConvMode)
377{
378 auto sdl = reinterpret_cast<SdlContext*>(context);
379 if (!context)
380 return FALSE;
381
382 WLog_Print(sdl->getWLog(), WLOG_WARN,
383 "KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
384 ", imeConvMode=%08" PRIx32 ") ignored",
385 imeId, imeState, imeConvMode);
386 return TRUE;
387}
388
389[[nodiscard]] static const std::map<std::string, uint32_t>& getSdlMap()
390{
391 static std::map<std::string, uint32_t> s_map = {
392 { "KMOD_LSHIFT", SDL_KMOD_LSHIFT }, { "KMOD_RSHIFT", SDL_KMOD_RSHIFT },
393 { "KMOD_LCTRL", SDL_KMOD_LCTRL }, { "KMOD_RCTRL", SDL_KMOD_RCTRL },
394 { "KMOD_LALT", SDL_KMOD_LALT }, { "KMOD_RALT", SDL_KMOD_RALT },
395 { "KMOD_LGUI", SDL_KMOD_LGUI }, { "KMOD_RGUI", SDL_KMOD_RGUI },
396 { "KMOD_NUM", SDL_KMOD_NUM }, { "KMOD_CAPS", SDL_KMOD_CAPS },
397 { "KMOD_MODE", SDL_KMOD_MODE }, { "KMOD_SCROLL", SDL_KMOD_SCROLL },
398 { "KMOD_CTRL", SDL_KMOD_CTRL }, { "KMOD_SHIFT", SDL_KMOD_SHIFT },
399 { "KMOD_ALT", SDL_KMOD_ALT }, { "KMOD_GUI", SDL_KMOD_GUI },
400 { "KMOD_NONE", SDL_KMOD_NONE }, { "SDL_KMOD_LSHIFT", SDL_KMOD_LSHIFT },
401 { "SDL_KMOD_RSHIFT", SDL_KMOD_RSHIFT }, { "SDL_KMOD_LCTRL", SDL_KMOD_LCTRL },
402 { "SDL_KMOD_RCTRL", SDL_KMOD_RCTRL }, { "SDL_KMOD_LALT", SDL_KMOD_LALT },
403 { "SDL_KMOD_RALT", SDL_KMOD_RALT }, { "SDL_KMOD_LGUI", SDL_KMOD_LGUI },
404 { "SDL_KMOD_RGUI", SDL_KMOD_RGUI }, { "SDL_KMOD_NUM", SDL_KMOD_NUM },
405 { "SDL_KMOD_CAPS", SDL_KMOD_CAPS }, { "SDL_KMOD_MODE", SDL_KMOD_MODE },
406 { "SDL_KMOD_SCROLL", SDL_KMOD_SCROLL }, { "SDL_KMOD_CTRL", SDL_KMOD_CTRL },
407 { "SDL_KMOD_SHIFT", SDL_KMOD_SHIFT }, { "SDL_KMOD_ALT", SDL_KMOD_ALT },
408 { "SDL_KMOD_GUI", SDL_KMOD_GUI }, { "SDL_KMOD_NONE", SDL_KMOD_NONE },
409 { "SDL_KMOD_MODE", SDL_KMOD_MODE }, { "SDL_KMOD_LEVEL5", SDL_KMOD_LEVEL5 }
410 };
411
412 return s_map;
413}
414
415[[nodiscard]] static std::string modbyvalue(uint32_t val)
416{
417 for (const auto& v : getSdlMap())
418 {
419 if (v.second == val)
420 {
421 return v.first;
422 }
423 }
424 return "KMOD_UNKNONW";
425}
426
427[[nodiscard]] static std::string masktostr(uint32_t mask)
428{
429 if (mask == 0)
430 return "<NONE>";
431
432 std::string str = "<";
433 for (uint32_t x = 0; x < 32; x++)
434 {
435 uint32_t cmask = 1u << x;
436 if ((mask & cmask) != 0)
437 {
438 auto s = modbyvalue(cmask);
439 if (str.size() > 1)
440 {
441 str += ">+<";
442 }
443 str += s;
444 }
445 }
446 str += ">";
447 return str;
448}
449
450bool sdlInput::prefToEnabled()
451{
452 bool enabled = true;
453 const auto& m = getSdlMap();
454 for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
455 {
456 auto it = m.find(val);
457 if (it != m.end())
458 {
459 if (it->second == SDL_KMOD_NONE)
460 enabled = false;
461 }
462 else
463 {
464 WLog_Print(_sdl->getWLog(), WLOG_WARN,
465 "Invalid config::SDL_KeyModMask entry value '%s', disabling hotkeys",
466 val.c_str());
467 enabled = false;
468 }
469 }
470 return enabled;
471}
472
473uint32_t sdlInput::prefToMask()
474{
475 const auto& m = getSdlMap();
476 uint32_t mod = SDL_KMOD_NONE;
477 for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
478 {
479 auto it = m.find(val);
480 if (it != m.end())
481 mod |= it->second;
482 }
483 return mod;
484}
485
486[[nodiscard]] static const char* sdl_scancode_name(Uint32 scancode)
487{
488 for (const auto& cur : map)
489 {
490 if (cur.sdl == scancode)
491 return cur.sdl_name;
492 }
493
494 return "SDL_SCANCODE_UNKNOWN";
495}
496
497[[nodiscard]] static Uint32 sdl_scancode_val(const char* scancodeName)
498{
499 for (const auto& cur : map)
500 {
501 if (strcmp(cur.sdl_name, scancodeName) == 0)
502 return cur.sdl;
503 }
504
505 return SDL_SCANCODE_UNKNOWN;
506}
507
508#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
509[[nodiscard]] static const char* sdl_rdp_scancode_name(UINT32 scancode)
510{
511 for (const auto& cur : map)
512 {
513 if (cur.rdp == scancode)
514 return cur.rdp_name;
515 }
516
517 return "RDP_SCANCODE_UNKNOWN";
518}
519#endif
520
521UINT32 sdlInput::scancode_to_rdp(Uint32 scancode)
522{
523 UINT32 rdp = RDP_SCANCODE_UNKNOWN;
524
525 for (const auto& cur : map)
526 {
527 if (cur.sdl == scancode)
528 {
529 rdp = cur.rdp;
530 break;
531 }
532 }
533
534#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
535 auto code = static_cast<SDL_Scancode>(scancode);
536 WLog_Print(_sdl->getWLog(), WLOG_DEBUG, "got %s [%s] -> [%s]", SDL_GetScancodeName(code),
537 sdl_scancode_name(scancode), sdl_rdp_scancode_name(rdp));
538#endif
539 return rdp;
540}
541
542uint32_t sdlInput::prefKeyValue(const std::string& key, uint32_t fallback)
543{
544 auto item = SdlPref::instance()->get_string(key);
545 if (item.empty())
546 return fallback;
547 auto val = sdl_scancode_val(item.c_str());
548 if (val == SDL_SCANCODE_UNKNOWN)
549 return fallback;
550 return val;
551}
552
553std::list<std::string> sdlInput::tokenize(const std::string& data, const std::string& delimiter)
554{
555 size_t lastpos = 0;
556 size_t pos = 0;
557 std::list<std::string> list;
558 while ((pos = data.find(delimiter, lastpos)) != std::string::npos)
559 {
560 auto token = data.substr(lastpos, pos);
561 lastpos = pos + 1;
562 list.push_back(std::move(token));
563 }
564 auto token = data.substr(lastpos);
565 list.push_back(std::move(token));
566 return list;
567}
568
569bool sdlInput::extract(const std::string& token, uint32_t& key, uint32_t& value)
570{
571 return freerdp_extract_key_value(token.c_str(), &key, &value);
572}
573
574bool sdlInput::handleEvent(const SDL_KeyboardEvent& ev)
575{
576 UINT32 rdp_scancode = scancode_to_rdp(ev.scancode);
577#if defined(_WIN32)
578 /* CJK IMEs on Windows may set the extended bit for Right Shift, producing
579 * the invalid scan code E0 36. SDL maps that event to SDL_SCANCODE_UNKNOWN,
580 * so normalize it in the same way as the native Windows client. */
581 if ((rdp_scancode == RDP_SCANCODE_UNKNOWN) && (ev.raw == 0xE036))
582 rdp_scancode = RDP_SCANCODE_RSHIFT;
583#endif
584 /* The modifiers held when this key was pressed: SDL_GetModState() is the state after every
585 * event already queued, so a hotkey could be missed, or fire on a plain key typed just
586 * before a modifier. */
587 const SDL_Keymod mods = ev.mod;
588
589 if (_hotkeysEnabled && (mods & _hotkeyModmask) == _hotkeyModmask)
590 {
591 if (ev.type == SDL_EVENT_KEY_DOWN)
592 {
593 if (ev.scancode == _hotkeyFullscreen)
594 {
595 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling fullscreen state",
596 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyFullscreen));
597 if (!keyboard_sync_state())
598 return false;
599 return _sdl->toggleFullscreen();
600 }
601 if (ev.scancode == _hotkeyResizable)
602 {
603 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling resizeable state",
604 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyResizable));
605 if (!keyboard_sync_state())
606 return false;
607 return _sdl->toggleResizeable();
608 }
609
610 if (ev.scancode == _hotkeyGrab)
611 {
612 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, toggling grab state",
613 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyGrab));
614 if (!keyboard_sync_state())
615 return false;
616 return keyboard_grab(ev.windowID, !_sdl->grabKeyboard());
617 }
618 if (ev.scancode == _hotkeyDisconnect)
619 {
620 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, disconnecting RDP session",
621 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyDisconnect));
622 if (!keyboard_sync_state())
623 return false;
624 freerdp_abort_connect_context(_sdl->context());
625 return true;
626 }
627 if (ev.scancode == _hotkeyMinimize)
628 {
629 WLog_Print(_sdl->getWLog(), WLOG_INFO, "%s+<%s> pressed, minimizing client",
630 masktostr(_hotkeyModmask).c_str(), sdl_scancode_name(_hotkeyMinimize));
631 if (!keyboard_sync_state())
632 return false;
633 return _sdl->setMinimized();
634 }
635 }
636 }
637
638#if defined(WITH_DEBUG_KBD)
639 {
640 const BOOL ex = RDP_SCANCODE_EXTENDED(rdp_scancode);
641 const DWORD sc = RDP_SCANCODE_CODE(rdp_scancode);
642 WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
643 "SDL keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s",
644 ev.scancode, rdp_scancode, sc, ex ? " extended" : "");
645 }
646#endif
647
648 auto scancode = freerdp_keyboard_remap_key(_remapTable, rdp_scancode);
649#if defined(WITH_DEBUG_KBD)
650 {
651 const BOOL ex = RDP_SCANCODE_EXTENDED(scancode);
652 const DWORD sc = RDP_SCANCODE_CODE(scancode);
653 WLog_Print(_sdl->getWLog(), WLOG_DEBUG,
654 "SDL keycode: %02" PRIX32 " -> remapped rdp code: [%04" PRIx16 "] %02" PRIX8
655 "%s",
656 ev.scancode, scancode, sc, ex ? " extended" : "");
657 }
658#endif
659 if (freerdp_settings_get_bool(_sdl->context()->settings, FreeRDP_UnicodeInput))
660 {
661 /* With key_event false the keycode follows the layout, also for non-Latin ones, where key
662 * events carry the QWERTY letter (SDL_HINT_KEYCODE_OPTIONS). */
663 const auto key = SDL_GetKeyFromScancode(ev.scancode, mods, false);
664 std::array<char, 5> str = {};
665 if ((key >= 0x20) && (key != SDLK_DELETE) && (key <= 0x10FFFF))
666 std::ignore = SDL_UCS4ToUTF8(key, str.data());
667 return freerdp_client_send_key_as_unicode(
668 _sdl->common(), (ev.type == SDL_EVENT_KEY_DOWN) ? 0 : KBD_FLAGS_RELEASE, str.data(),
669 scancode, sdl_get_kbd_modmask(mods));
670 }
671 return freerdp_input_send_keyboard_event_ex(_sdl->context()->input,
672 ev.type == SDL_EVENT_KEY_DOWN, ev.repeat, scancode);
673}
674
675bool sdlInput::keyboard_grab(Uint32 windowID, bool enable)
676{
677 const auto window = _sdl->getWindowForId(windowID);
678 if (!window)
679 return false;
680
681 auto settings = _sdl->context()->settings;
682 auto kbd_enabled = freerdp_settings_get_bool(settings, FreeRDP_GrabKeyboard);
683 auto status = enable && kbd_enabled;
684 if (!_sdl->setGrabKeyboard(status))
685 WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab keyboard");
686 return window->grabKeyboard(status);
687}
688
689bool sdlInput::mouse_focus(Uint32 windowID)
690{
691 if (_lastWindowID != windowID)
692 {
693 _lastWindowID = windowID;
694 auto window = _sdl->getWindowForId(windowID);
695 if (window)
696 window->raise();
697 else
698 return _sdl->getRailChannelContext().ownsWindow(windowID);
699 }
700 return true;
701}
702
703bool sdlInput::mouse_grab(Uint32 windowID, bool enable)
704{
705 auto window = _sdl->getWindowForId(windowID);
706 if (!window)
707 return false;
708 if (!_sdl->setGrabMouse(enable))
709 WLog_Print(_sdl->getWLog(), WLOG_WARN, "Failed to ungrab mouse");
710 return window->grabMouse(enable);
711}
712
713sdlInput::sdlInput(SdlContext* sdl)
714 : _sdl(sdl), _lastWindowID(UINT32_MAX), _hotkeysEnabled(prefToEnabled()),
715 _hotkeyModmask(prefToMask())
716{
717 _hotkeyFullscreen = prefKeyValue("SDL_Fullscreen", SDL_SCANCODE_RETURN);
718 _hotkeyResizable = prefKeyValue("SDL_Resizeable", SDL_SCANCODE_R);
719 _hotkeyGrab = prefKeyValue("SDL_Grab", SDL_SCANCODE_G);
720 _hotkeyDisconnect = prefKeyValue("SDL_Disconnect", SDL_SCANCODE_D);
721 _hotkeyMinimize = prefKeyValue("SDL_Minimize", SDL_SCANCODE_M);
722}
723
724sdlInput::~sdlInput()
725{
726 freerdp_keyboard_remap_free(_remapTable);
727}
728
729bool sdlInput::initialize()
730{
731 auto settings = _sdl->context()->settings;
732 WINPR_ASSERT(settings);
733 WINPR_ASSERT(!_remapTable);
734
735 {
736 auto list = freerdp_settings_get_string(settings, FreeRDP_KeyboardRemappingList);
737 _remapTable = freerdp_keyboard_remap_string_to_list(list);
738 if (!_remapTable)
739 return false;
740 }
741
742 if (freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout) == 0)
743 {
744 DWORD KeyboardLayout = 0;
745
746 freerdp_detect_keyboard_layout_from_system_locale(&KeyboardLayout);
747 if (KeyboardLayout == 0)
748 KeyboardLayout = ENGLISH_UNITED_STATES;
749
750 if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardLayout, KeyboardLayout))
751 return false;
752 }
753 return true;
754}
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.