FreeRDP
Loading...
Searching...
No Matches
sdl_kbd.cpp
1
20#include <winpr/cast.h>
21
22#include "sdl_kbd.hpp"
23#include "sdl_disp.hpp"
24#include "sdl_freerdp.hpp"
25#include "sdl_utils.hpp"
26#include "sdl_prefs.hpp"
27#include "sdl_touch.hpp"
28
29#include <map>
30
31#include <freerdp/utils/string.h>
32#include <freerdp/scancode.h>
33
34#include <freerdp/log.h>
35#define TAG CLIENT_TAG("SDL.kbd")
36
37using scancode_entry_t = struct
38{
39 Uint32 sdl;
40 const char* sdl_name;
41 UINT32 rdp;
42 const char* rdp_name;
43};
44
45#define STR(x) #x
46#define ENTRY(x, y) { x, STR(x), y, #y }
47
48// clang-format off
49static const scancode_entry_t map[] = {
50 ENTRY(SDL_SCANCODE_UNKNOWN, RDP_SCANCODE_UNKNOWN),
51 ENTRY(SDL_SCANCODE_A, RDP_SCANCODE_KEY_A),
52 ENTRY(SDL_SCANCODE_B, RDP_SCANCODE_KEY_B),
53 ENTRY(SDL_SCANCODE_C, RDP_SCANCODE_KEY_C),
54 ENTRY(SDL_SCANCODE_D, RDP_SCANCODE_KEY_D),
55 ENTRY(SDL_SCANCODE_E, RDP_SCANCODE_KEY_E),
56 ENTRY(SDL_SCANCODE_F, RDP_SCANCODE_KEY_F),
57 ENTRY(SDL_SCANCODE_G, RDP_SCANCODE_KEY_G),
58 ENTRY(SDL_SCANCODE_H, RDP_SCANCODE_KEY_H),
59 ENTRY(SDL_SCANCODE_I, RDP_SCANCODE_KEY_I),
60 ENTRY(SDL_SCANCODE_J, RDP_SCANCODE_KEY_J),
61 ENTRY(SDL_SCANCODE_K, RDP_SCANCODE_KEY_K),
62 ENTRY(SDL_SCANCODE_L, RDP_SCANCODE_KEY_L),
63 ENTRY(SDL_SCANCODE_M, RDP_SCANCODE_KEY_M),
64 ENTRY(SDL_SCANCODE_N, RDP_SCANCODE_KEY_N),
65 ENTRY(SDL_SCANCODE_O, RDP_SCANCODE_KEY_O),
66 ENTRY(SDL_SCANCODE_P, RDP_SCANCODE_KEY_P),
67 ENTRY(SDL_SCANCODE_Q, RDP_SCANCODE_KEY_Q),
68 ENTRY(SDL_SCANCODE_R, RDP_SCANCODE_KEY_R),
69 ENTRY(SDL_SCANCODE_S, RDP_SCANCODE_KEY_S),
70 ENTRY(SDL_SCANCODE_T, RDP_SCANCODE_KEY_T),
71 ENTRY(SDL_SCANCODE_U, RDP_SCANCODE_KEY_U),
72 ENTRY(SDL_SCANCODE_V, RDP_SCANCODE_KEY_V),
73 ENTRY(SDL_SCANCODE_W, RDP_SCANCODE_KEY_W),
74 ENTRY(SDL_SCANCODE_X, RDP_SCANCODE_KEY_X),
75 ENTRY(SDL_SCANCODE_Y, RDP_SCANCODE_KEY_Y),
76 ENTRY(SDL_SCANCODE_Z, RDP_SCANCODE_KEY_Z),
77 ENTRY(SDL_SCANCODE_1, RDP_SCANCODE_KEY_1),
78 ENTRY(SDL_SCANCODE_2, RDP_SCANCODE_KEY_2),
79 ENTRY(SDL_SCANCODE_3, RDP_SCANCODE_KEY_3),
80 ENTRY(SDL_SCANCODE_4, RDP_SCANCODE_KEY_4),
81 ENTRY(SDL_SCANCODE_5, RDP_SCANCODE_KEY_5),
82 ENTRY(SDL_SCANCODE_6, RDP_SCANCODE_KEY_6),
83 ENTRY(SDL_SCANCODE_7, RDP_SCANCODE_KEY_7),
84 ENTRY(SDL_SCANCODE_8, RDP_SCANCODE_KEY_8),
85 ENTRY(SDL_SCANCODE_9, RDP_SCANCODE_KEY_9),
86 ENTRY(SDL_SCANCODE_0, RDP_SCANCODE_KEY_0),
87 ENTRY(SDL_SCANCODE_RETURN, RDP_SCANCODE_RETURN),
88 ENTRY(SDL_SCANCODE_ESCAPE, RDP_SCANCODE_ESCAPE),
89 ENTRY(SDL_SCANCODE_BACKSPACE, RDP_SCANCODE_BACKSPACE),
90 ENTRY(SDL_SCANCODE_TAB, RDP_SCANCODE_TAB),
91 ENTRY(SDL_SCANCODE_SPACE, RDP_SCANCODE_SPACE),
92 ENTRY(SDL_SCANCODE_MINUS, RDP_SCANCODE_OEM_MINUS),
93 ENTRY(SDL_SCANCODE_CAPSLOCK, RDP_SCANCODE_CAPSLOCK),
94 ENTRY(SDL_SCANCODE_F1, RDP_SCANCODE_F1),
95 ENTRY(SDL_SCANCODE_F2, RDP_SCANCODE_F2),
96 ENTRY(SDL_SCANCODE_F3, RDP_SCANCODE_F3),
97 ENTRY(SDL_SCANCODE_F4, RDP_SCANCODE_F4),
98 ENTRY(SDL_SCANCODE_F5, RDP_SCANCODE_F5),
99 ENTRY(SDL_SCANCODE_F6, RDP_SCANCODE_F6),
100 ENTRY(SDL_SCANCODE_F7, RDP_SCANCODE_F7),
101 ENTRY(SDL_SCANCODE_F8, RDP_SCANCODE_F8),
102 ENTRY(SDL_SCANCODE_F9, RDP_SCANCODE_F9),
103 ENTRY(SDL_SCANCODE_F10, RDP_SCANCODE_F10),
104 ENTRY(SDL_SCANCODE_F11, RDP_SCANCODE_F11),
105 ENTRY(SDL_SCANCODE_F12, RDP_SCANCODE_F12),
106 ENTRY(SDL_SCANCODE_F13, RDP_SCANCODE_F13),
107 ENTRY(SDL_SCANCODE_F14, RDP_SCANCODE_F14),
108 ENTRY(SDL_SCANCODE_F15, RDP_SCANCODE_F15),
109 ENTRY(SDL_SCANCODE_F16, RDP_SCANCODE_F16),
110 ENTRY(SDL_SCANCODE_F17, RDP_SCANCODE_F17),
111 ENTRY(SDL_SCANCODE_F18, RDP_SCANCODE_F18),
112 ENTRY(SDL_SCANCODE_F19, RDP_SCANCODE_F19),
113 ENTRY(SDL_SCANCODE_F20, RDP_SCANCODE_F20),
114 ENTRY(SDL_SCANCODE_F21, RDP_SCANCODE_F21),
115 ENTRY(SDL_SCANCODE_F22, RDP_SCANCODE_F22),
116 ENTRY(SDL_SCANCODE_F23, RDP_SCANCODE_F23),
117 ENTRY(SDL_SCANCODE_F24, RDP_SCANCODE_F24),
118 ENTRY(SDL_SCANCODE_NUMLOCKCLEAR, RDP_SCANCODE_NUMLOCK),
119 ENTRY(SDL_SCANCODE_KP_DIVIDE, RDP_SCANCODE_DIVIDE),
120 ENTRY(SDL_SCANCODE_KP_MULTIPLY, RDP_SCANCODE_MULTIPLY),
121 ENTRY(SDL_SCANCODE_KP_MINUS, RDP_SCANCODE_SUBTRACT),
122 ENTRY(SDL_SCANCODE_KP_PLUS, RDP_SCANCODE_ADD),
123 ENTRY(SDL_SCANCODE_KP_ENTER, RDP_SCANCODE_RETURN_KP),
124 ENTRY(SDL_SCANCODE_KP_1, RDP_SCANCODE_NUMPAD1),
125 ENTRY(SDL_SCANCODE_KP_2, RDP_SCANCODE_NUMPAD2),
126 ENTRY(SDL_SCANCODE_KP_3, RDP_SCANCODE_NUMPAD3),
127 ENTRY(SDL_SCANCODE_KP_4, RDP_SCANCODE_NUMPAD4),
128 ENTRY(SDL_SCANCODE_KP_5, RDP_SCANCODE_NUMPAD5),
129 ENTRY(SDL_SCANCODE_KP_6, RDP_SCANCODE_NUMPAD6),
130 ENTRY(SDL_SCANCODE_KP_7, RDP_SCANCODE_NUMPAD7),
131 ENTRY(SDL_SCANCODE_KP_8, RDP_SCANCODE_NUMPAD8),
132 ENTRY(SDL_SCANCODE_KP_9, RDP_SCANCODE_NUMPAD9),
133 ENTRY(SDL_SCANCODE_KP_0, RDP_SCANCODE_NUMPAD0),
134 ENTRY(SDL_SCANCODE_KP_PERIOD, RDP_SCANCODE_OEM_PERIOD),
135 ENTRY(SDL_SCANCODE_LCTRL, RDP_SCANCODE_LCONTROL),
136 ENTRY(SDL_SCANCODE_LSHIFT, RDP_SCANCODE_LSHIFT),
137 ENTRY(SDL_SCANCODE_LALT, RDP_SCANCODE_LMENU),
138 ENTRY(SDL_SCANCODE_LGUI, RDP_SCANCODE_LWIN),
139 ENTRY(SDL_SCANCODE_RCTRL, RDP_SCANCODE_RCONTROL),
140 ENTRY(SDL_SCANCODE_RSHIFT, RDP_SCANCODE_RSHIFT),
141 ENTRY(SDL_SCANCODE_RALT, RDP_SCANCODE_RMENU),
142 ENTRY(SDL_SCANCODE_RGUI, RDP_SCANCODE_RWIN),
143 ENTRY(SDL_SCANCODE_MODE, RDP_SCANCODE_APPS),
144 ENTRY(SDL_SCANCODE_MUTE, RDP_SCANCODE_VOLUME_MUTE),
145 ENTRY(SDL_SCANCODE_VOLUMEUP, RDP_SCANCODE_VOLUME_UP),
146 ENTRY(SDL_SCANCODE_VOLUMEDOWN, RDP_SCANCODE_VOLUME_DOWN),
147 ENTRY(SDL_SCANCODE_GRAVE, RDP_SCANCODE_OEM_3),
148 ENTRY(SDL_SCANCODE_COMMA, RDP_SCANCODE_OEM_COMMA),
149 ENTRY(SDL_SCANCODE_PERIOD, RDP_SCANCODE_OEM_PERIOD),
150 ENTRY(SDL_SCANCODE_SLASH, RDP_SCANCODE_OEM_2),
151 ENTRY(SDL_SCANCODE_BACKSLASH, RDP_SCANCODE_OEM_5),
152 ENTRY(SDL_SCANCODE_SCROLLLOCK, RDP_SCANCODE_SCROLLLOCK),
153 ENTRY(SDL_SCANCODE_INSERT, RDP_SCANCODE_INSERT),
154 ENTRY(SDL_SCANCODE_PRINTSCREEN, RDP_SCANCODE_PRINTSCREEN),
155 ENTRY(SDL_SCANCODE_HOME, RDP_SCANCODE_HOME),
156 ENTRY(SDL_SCANCODE_DELETE, RDP_SCANCODE_DELETE),
157 ENTRY(SDL_SCANCODE_RIGHT, RDP_SCANCODE_RIGHT),
158 ENTRY(SDL_SCANCODE_LEFT, RDP_SCANCODE_LEFT),
159 ENTRY(SDL_SCANCODE_DOWN, RDP_SCANCODE_DOWN),
160 ENTRY(SDL_SCANCODE_UP, RDP_SCANCODE_UP),
161 ENTRY(SDL_SCANCODE_SEMICOLON, RDP_SCANCODE_OEM_1),
162 ENTRY(SDL_SCANCODE_PAUSE, RDP_SCANCODE_PAUSE),
163 ENTRY(SDL_SCANCODE_PAGEUP, RDP_SCANCODE_PRIOR),
164 ENTRY(SDL_SCANCODE_END, RDP_SCANCODE_END),
165 ENTRY(SDL_SCANCODE_PAGEDOWN, RDP_SCANCODE_NEXT),
166 ENTRY(SDL_SCANCODE_AUDIONEXT, RDP_SCANCODE_MEDIA_NEXT_TRACK),
167 ENTRY(SDL_SCANCODE_AUDIOPREV, RDP_SCANCODE_MEDIA_PREV_TRACK),
168 ENTRY(SDL_SCANCODE_AUDIOSTOP, RDP_SCANCODE_MEDIA_STOP),
169 ENTRY(SDL_SCANCODE_AUDIOPLAY, RDP_SCANCODE_MEDIA_PLAY_PAUSE),
170 ENTRY(SDL_SCANCODE_AUDIOMUTE, RDP_SCANCODE_VOLUME_MUTE),
171 ENTRY(SDL_SCANCODE_MEDIASELECT, RDP_SCANCODE_LAUNCH_MEDIA_SELECT),
172 ENTRY(SDL_SCANCODE_MAIL, RDP_SCANCODE_LAUNCH_MAIL),
173 ENTRY(SDL_SCANCODE_APP1, RDP_SCANCODE_LAUNCH_APP1),
174 ENTRY(SDL_SCANCODE_APP2, RDP_SCANCODE_LAUNCH_APP2),
175 ENTRY(SDL_SCANCODE_SYSREQ, RDP_SCANCODE_SYSREQ),
176 ENTRY(SDL_SCANCODE_WWW, RDP_SCANCODE_BROWSER_HOME),
177 ENTRY(SDL_SCANCODE_LEFTBRACKET, RDP_SCANCODE_OEM_4),
178 ENTRY(SDL_SCANCODE_RIGHTBRACKET, RDP_SCANCODE_OEM_6),
179 ENTRY(SDL_SCANCODE_APOSTROPHE, RDP_SCANCODE_OEM_7),
180 ENTRY(SDL_SCANCODE_NONUSBACKSLASH, RDP_SCANCODE_OEM_102),
181 ENTRY(SDL_SCANCODE_SLEEP, RDP_SCANCODE_SLEEP),
182 ENTRY(SDL_SCANCODE_EQUALS, RDP_SCANCODE_OEM_PLUS),
183 ENTRY(SDL_SCANCODE_KP_COMMA, RDP_SCANCODE_DECIMAL),
184 ENTRY(SDL_SCANCODE_FIND, RDP_SCANCODE_BROWSER_SEARCH),
185 ENTRY(SDL_SCANCODE_RETURN2, RDP_SCANCODE_RETURN_KP),
186 ENTRY(SDL_SCANCODE_AC_SEARCH, RDP_SCANCODE_BROWSER_SEARCH),
187 ENTRY(SDL_SCANCODE_AC_HOME, RDP_SCANCODE_BROWSER_HOME),
188 ENTRY(SDL_SCANCODE_AC_BACK, RDP_SCANCODE_BROWSER_BACK),
189 ENTRY(SDL_SCANCODE_AC_FORWARD, RDP_SCANCODE_BROWSER_FORWARD),
190 ENTRY(SDL_SCANCODE_AC_STOP, RDP_SCANCODE_BROWSER_STOP),
191
192 // TODO: unmapped
193 ENTRY(SDL_SCANCODE_NONUSHASH, RDP_SCANCODE_UNKNOWN),
194 ENTRY(SDL_SCANCODE_APPLICATION, RDP_SCANCODE_UNKNOWN),
195 ENTRY(SDL_SCANCODE_POWER, RDP_SCANCODE_UNKNOWN),
196 ENTRY(SDL_SCANCODE_KP_EQUALS, RDP_SCANCODE_UNKNOWN),
197 ENTRY(SDL_SCANCODE_EXECUTE, RDP_SCANCODE_UNKNOWN),
198 ENTRY(SDL_SCANCODE_HELP, RDP_SCANCODE_UNKNOWN),
199 ENTRY(SDL_SCANCODE_MENU, RDP_SCANCODE_UNKNOWN),
200 ENTRY(SDL_SCANCODE_SELECT, RDP_SCANCODE_UNKNOWN),
201 ENTRY(SDL_SCANCODE_STOP, RDP_SCANCODE_UNKNOWN),
202 ENTRY(SDL_SCANCODE_AGAIN, RDP_SCANCODE_UNKNOWN),
203 ENTRY(SDL_SCANCODE_UNDO, RDP_SCANCODE_UNKNOWN),
204 ENTRY(SDL_SCANCODE_CUT, RDP_SCANCODE_UNKNOWN),
205 ENTRY(SDL_SCANCODE_COPY, RDP_SCANCODE_UNKNOWN),
206 ENTRY(SDL_SCANCODE_PASTE, RDP_SCANCODE_UNKNOWN),
207 ENTRY(SDL_SCANCODE_KP_EQUALSAS400, RDP_SCANCODE_UNKNOWN),
208 ENTRY(SDL_SCANCODE_INTERNATIONAL1, RDP_SCANCODE_UNKNOWN),
209 ENTRY(SDL_SCANCODE_INTERNATIONAL2, RDP_SCANCODE_UNKNOWN),
210 ENTRY(SDL_SCANCODE_INTERNATIONAL3, RDP_SCANCODE_UNKNOWN),
211 ENTRY(SDL_SCANCODE_INTERNATIONAL4, RDP_SCANCODE_UNKNOWN),
212 ENTRY(SDL_SCANCODE_INTERNATIONAL5, RDP_SCANCODE_UNKNOWN),
213 ENTRY(SDL_SCANCODE_INTERNATIONAL6, RDP_SCANCODE_UNKNOWN),
214 ENTRY(SDL_SCANCODE_INTERNATIONAL7, RDP_SCANCODE_UNKNOWN),
215 ENTRY(SDL_SCANCODE_INTERNATIONAL8, RDP_SCANCODE_UNKNOWN),
216 ENTRY(SDL_SCANCODE_INTERNATIONAL9, RDP_SCANCODE_UNKNOWN),
217 ENTRY(SDL_SCANCODE_LANG1, RDP_SCANCODE_UNKNOWN),
218 ENTRY(SDL_SCANCODE_LANG2, RDP_SCANCODE_UNKNOWN),
219 ENTRY(SDL_SCANCODE_LANG3, RDP_SCANCODE_UNKNOWN),
220 ENTRY(SDL_SCANCODE_LANG4, RDP_SCANCODE_UNKNOWN),
221 ENTRY(SDL_SCANCODE_LANG5, RDP_SCANCODE_UNKNOWN),
222 ENTRY(SDL_SCANCODE_LANG6, RDP_SCANCODE_UNKNOWN),
223 ENTRY(SDL_SCANCODE_LANG7, RDP_SCANCODE_UNKNOWN),
224 ENTRY(SDL_SCANCODE_LANG8, RDP_SCANCODE_UNKNOWN),
225 ENTRY(SDL_SCANCODE_LANG9, RDP_SCANCODE_UNKNOWN),
226 ENTRY(SDL_SCANCODE_ALTERASE, RDP_SCANCODE_UNKNOWN),
227 ENTRY(SDL_SCANCODE_CANCEL, RDP_SCANCODE_UNKNOWN),
228 ENTRY(SDL_SCANCODE_CLEAR, RDP_SCANCODE_UNKNOWN),
229 ENTRY(SDL_SCANCODE_PRIOR, RDP_SCANCODE_UNKNOWN),
230 ENTRY(SDL_SCANCODE_SEPARATOR, RDP_SCANCODE_UNKNOWN),
231 ENTRY(SDL_SCANCODE_OUT, RDP_SCANCODE_UNKNOWN),
232 ENTRY(SDL_SCANCODE_OPER, RDP_SCANCODE_UNKNOWN),
233 ENTRY(SDL_SCANCODE_CLEARAGAIN, RDP_SCANCODE_UNKNOWN),
234 ENTRY(SDL_SCANCODE_CRSEL, RDP_SCANCODE_UNKNOWN),
235 ENTRY(SDL_SCANCODE_EXSEL, RDP_SCANCODE_UNKNOWN),
236 ENTRY(SDL_SCANCODE_KP_00, RDP_SCANCODE_UNKNOWN),
237 ENTRY(SDL_SCANCODE_KP_000, RDP_SCANCODE_UNKNOWN),
238 ENTRY(SDL_SCANCODE_THOUSANDSSEPARATOR, RDP_SCANCODE_UNKNOWN),
239 ENTRY(SDL_SCANCODE_DECIMALSEPARATOR, RDP_SCANCODE_UNKNOWN),
240 ENTRY(SDL_SCANCODE_CURRENCYUNIT, RDP_SCANCODE_UNKNOWN),
241 ENTRY(SDL_SCANCODE_CURRENCYSUBUNIT, RDP_SCANCODE_UNKNOWN),
242 ENTRY(SDL_SCANCODE_KP_LEFTPAREN, RDP_SCANCODE_UNKNOWN),
243 ENTRY(SDL_SCANCODE_KP_RIGHTPAREN, RDP_SCANCODE_UNKNOWN),
244 ENTRY(SDL_SCANCODE_KP_LEFTBRACE, RDP_SCANCODE_UNKNOWN),
245 ENTRY(SDL_SCANCODE_KP_RIGHTBRACE, RDP_SCANCODE_UNKNOWN),
246 ENTRY(SDL_SCANCODE_KP_TAB, RDP_SCANCODE_UNKNOWN),
247 ENTRY(SDL_SCANCODE_KP_BACKSPACE, RDP_SCANCODE_UNKNOWN),
248 ENTRY(SDL_SCANCODE_KP_A, RDP_SCANCODE_UNKNOWN),
249 ENTRY(SDL_SCANCODE_KP_B, RDP_SCANCODE_UNKNOWN),
250 ENTRY(SDL_SCANCODE_KP_C, RDP_SCANCODE_UNKNOWN),
251 ENTRY(SDL_SCANCODE_KP_D, RDP_SCANCODE_UNKNOWN),
252 ENTRY(SDL_SCANCODE_KP_E, RDP_SCANCODE_UNKNOWN),
253 ENTRY(SDL_SCANCODE_KP_F, RDP_SCANCODE_UNKNOWN),
254 ENTRY(SDL_SCANCODE_KP_XOR, RDP_SCANCODE_UNKNOWN),
255 ENTRY(SDL_SCANCODE_KP_POWER, RDP_SCANCODE_UNKNOWN),
256 ENTRY(SDL_SCANCODE_KP_PERCENT, RDP_SCANCODE_UNKNOWN),
257 ENTRY(SDL_SCANCODE_KP_LESS, RDP_SCANCODE_UNKNOWN),
258 ENTRY(SDL_SCANCODE_KP_GREATER, RDP_SCANCODE_UNKNOWN),
259 ENTRY(SDL_SCANCODE_KP_AMPERSAND, RDP_SCANCODE_UNKNOWN),
260 ENTRY(SDL_SCANCODE_KP_DBLAMPERSAND, RDP_SCANCODE_UNKNOWN),
261 ENTRY(SDL_SCANCODE_KP_VERTICALBAR, RDP_SCANCODE_UNKNOWN),
262 ENTRY(SDL_SCANCODE_KP_DBLVERTICALBAR, RDP_SCANCODE_UNKNOWN),
263 ENTRY(SDL_SCANCODE_KP_COLON, RDP_SCANCODE_UNKNOWN),
264 ENTRY(SDL_SCANCODE_KP_HASH, RDP_SCANCODE_UNKNOWN),
265 ENTRY(SDL_SCANCODE_KP_SPACE, RDP_SCANCODE_UNKNOWN),
266 ENTRY(SDL_SCANCODE_KP_AT, RDP_SCANCODE_UNKNOWN),
267 ENTRY(SDL_SCANCODE_KP_EXCLAM, RDP_SCANCODE_UNKNOWN),
268 ENTRY(SDL_SCANCODE_KP_MEMSTORE, RDP_SCANCODE_UNKNOWN),
269 ENTRY(SDL_SCANCODE_KP_MEMRECALL, RDP_SCANCODE_UNKNOWN),
270 ENTRY(SDL_SCANCODE_KP_MEMCLEAR, RDP_SCANCODE_UNKNOWN),
271 ENTRY(SDL_SCANCODE_KP_MEMADD, RDP_SCANCODE_UNKNOWN),
272 ENTRY(SDL_SCANCODE_KP_MEMSUBTRACT, RDP_SCANCODE_UNKNOWN),
273 ENTRY(SDL_SCANCODE_KP_MEMMULTIPLY, RDP_SCANCODE_UNKNOWN),
274 ENTRY(SDL_SCANCODE_KP_MEMDIVIDE, RDP_SCANCODE_UNKNOWN),
275 ENTRY(SDL_SCANCODE_KP_PLUSMINUS, RDP_SCANCODE_UNKNOWN),
276 ENTRY(SDL_SCANCODE_KP_CLEAR, RDP_SCANCODE_UNKNOWN),
277 ENTRY(SDL_SCANCODE_KP_CLEARENTRY, RDP_SCANCODE_UNKNOWN),
278 ENTRY(SDL_SCANCODE_KP_BINARY, RDP_SCANCODE_UNKNOWN),
279 ENTRY(SDL_SCANCODE_KP_OCTAL, RDP_SCANCODE_UNKNOWN),
280 ENTRY(SDL_SCANCODE_KP_DECIMAL, RDP_SCANCODE_UNKNOWN),
281 ENTRY(SDL_SCANCODE_KP_HEXADECIMAL, RDP_SCANCODE_UNKNOWN),
282 ENTRY(SDL_SCANCODE_CALCULATOR, RDP_SCANCODE_UNKNOWN),
283 ENTRY(SDL_SCANCODE_COMPUTER, RDP_SCANCODE_UNKNOWN),
284 ENTRY(SDL_SCANCODE_AC_REFRESH, RDP_SCANCODE_UNKNOWN),
285 ENTRY(SDL_SCANCODE_AC_BOOKMARKS, RDP_SCANCODE_UNKNOWN),
286 ENTRY(SDL_SCANCODE_BRIGHTNESSDOWN, RDP_SCANCODE_UNKNOWN),
287 ENTRY(SDL_SCANCODE_BRIGHTNESSUP, RDP_SCANCODE_UNKNOWN),
288 ENTRY(SDL_SCANCODE_DISPLAYSWITCH, RDP_SCANCODE_UNKNOWN),
289 ENTRY(SDL_SCANCODE_KBDILLUMTOGGLE, RDP_SCANCODE_UNKNOWN),
290 ENTRY(SDL_SCANCODE_KBDILLUMDOWN, RDP_SCANCODE_UNKNOWN),
291 ENTRY(SDL_SCANCODE_KBDILLUMUP, RDP_SCANCODE_UNKNOWN),
292 ENTRY(SDL_SCANCODE_EJECT, RDP_SCANCODE_UNKNOWN),
293 ENTRY(SDL_SCANCODE_AUDIOREWIND, RDP_SCANCODE_UNKNOWN),
294 ENTRY(SDL_SCANCODE_AUDIOFASTFORWARD, RDP_SCANCODE_UNKNOWN)
295};
296// clang-format on
297
298static UINT16 sdl_get_kbd_flags()
299{
300 UINT16 flags = 0;
301
302 SDL_Keymod mod = SDL_GetModState();
303 if ((mod & KMOD_NUM) != 0)
304 flags |= KBD_SYNC_NUM_LOCK;
305 if ((mod & KMOD_CAPS) != 0)
306 flags |= KBD_SYNC_CAPS_LOCK;
307#if SDL_VERSION_ATLEAST(2, 0, 18)
308 if ((mod & KMOD_SCROLL) != 0)
309 flags |= KBD_SYNC_SCROLL_LOCK;
310#endif
311
312 // TODO: KBD_SYNC_KANA_LOCK
313
314 return flags;
315}
316
317BOOL sdlInput::keyboard_sync_state()
318{
319 const auto syncFlags = sdl_get_kbd_flags();
320 return freerdp_input_send_synchronize_event(_sdl->context()->input, syncFlags);
321}
322
323BOOL sdlInput::keyboard_focus_in()
324{
325 auto input = _sdl->context()->input;
326 WINPR_ASSERT(input);
327
328 auto syncFlags = sdl_get_kbd_flags();
329 freerdp_input_send_focus_in_event(input, WINPR_ASSERTING_INT_CAST(UINT16, syncFlags));
330
331 /* finish with a mouse pointer position like mstsc.exe if required */
332 // TODO: fullscreen/remote app
333 int x = 0;
334 int y = 0;
335 if (_sdl->fullscreen)
336 {
337 SDL_GetGlobalMouseState(&x, &y);
338 }
339 else
340 {
341 SDL_GetMouseState(&x, &y);
342 }
343 auto w = SDL_GetMouseFocus();
344 if (w)
345 {
346 auto id = SDL_GetWindowID(w);
347 sdl_scale_coordinates(_sdl, id, &x, &y, TRUE, TRUE);
348 }
349 return freerdp_client_send_button_event(_sdl->common(), FALSE, PTR_FLAGS_MOVE, x, y);
350}
351
352/* This function is called to update the keyboard indicator LED */
353BOOL sdlInput::keyboard_set_indicators(rdpContext* context, UINT16 led_flags)
354{
355 WINPR_UNUSED(context);
356
357 int state = KMOD_NONE;
358
359 if ((led_flags & KBD_SYNC_NUM_LOCK) != 0)
360 state |= KMOD_NUM;
361 if ((led_flags & KBD_SYNC_CAPS_LOCK) != 0)
362 state |= KMOD_CAPS;
363#if SDL_VERSION_ATLEAST(2, 0, 18)
364 if ((led_flags & KBD_SYNC_SCROLL_LOCK) != 0)
365 state |= KMOD_SCROLL;
366#endif
367
368 // TODO: KBD_SYNC_KANA_LOCK
369
370 // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange)
371 SDL_SetModState(static_cast<SDL_Keymod>(state));
372
373 return TRUE;
374}
375
376/* This function is called to set the IME state */
377BOOL sdlInput::keyboard_set_ime_status(rdpContext* context, UINT16 imeId, UINT32 imeState,
378 UINT32 imeConvMode)
379{
380 if (!context)
381 return FALSE;
382
383 WLog_WARN(TAG,
384 "KeyboardSetImeStatus(unitId=%04" PRIx16 ", imeState=%08" PRIx32
385 ", imeConvMode=%08" PRIx32 ") ignored",
386 imeId, imeState, imeConvMode);
387 return TRUE;
388}
389
390static const std::map<std::string, uint32_t>& getSdlMap()
391{
392 static std::map<std::string, uint32_t> s_map = {
393 { "KMOD_LSHIFT", KMOD_LSHIFT }, { "KMOD_RSHIFT", KMOD_RSHIFT },
394 { "KMOD_LCTRL", KMOD_LCTRL }, { "KMOD_RCTRL", KMOD_RCTRL },
395 { "KMOD_LALT", KMOD_LALT }, { "KMOD_RALT", KMOD_RALT },
396 { "KMOD_LGUI", KMOD_LGUI }, { "KMOD_RGUI", KMOD_RGUI },
397 { "KMOD_NUM", KMOD_NUM }, { "KMOD_CAPS", KMOD_CAPS },
398 { "KMOD_MODE", KMOD_MODE },
399#if SDL_VERSION_ATLEAST(2, 0, 18)
400 { "KMOD_SCROLL", KMOD_SCROLL },
401#endif
402 { "KMOD_CTRL", KMOD_CTRL }, { "KMOD_SHIFT", KMOD_SHIFT },
403 { "KMOD_ALT", KMOD_ALT }, { "KMOD_GUI", KMOD_GUI },
404 { "KMOD_NONE", KMOD_NONE }, { "SDL_KMOD_LSHIFT", KMOD_LSHIFT },
405 { "SDL_KMOD_RSHIFT", KMOD_RSHIFT }, { "SDL_KMOD_LCTRL", KMOD_LCTRL },
406 { "SDL_KMOD_RCTRL", KMOD_RCTRL }, { "SDL_KMOD_LALT", KMOD_LALT },
407 { "SDL_KMOD_RALT", KMOD_RALT }, { "SDL_KMOD_LGUI", KMOD_LGUI },
408 { "SDL_KMOD_RGUI", KMOD_RGUI }, { "SDL_KMOD_NUM", KMOD_NUM },
409 { "SDL_KMOD_CAPS", KMOD_CAPS }, { "SDL_KMOD_MODE", KMOD_MODE },
410 { "SDL_KMOD_SCROLL", KMOD_SCROLL }, { "SDL_KMOD_CTRL", KMOD_CTRL },
411 { "SDL_KMOD_SHIFT", KMOD_SHIFT }, { "SDL_KMOD_ALT", KMOD_ALT },
412 { "SDL_KMOD_GUI", KMOD_GUI }, { "SDL_KMOD_NONE", KMOD_NONE }
413 };
414
415 return s_map;
416}
417
418bool sdlInput::prefToEnabled()
419{
420 bool enable = true;
421 const auto& m = getSdlMap();
422 for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
423 {
424 auto it = m.find(val);
425 if (it != m.end())
426 {
427 if (it->second == KMOD_NONE)
428 enable = false;
429 }
430 else
431 {
432 WLog_WARN(TAG, "Invalid config::SDL_KeyModMask entry value '%s', disabling hotkeys",
433 val.c_str());
434 enable = false;
435 }
436 }
437 return enable;
438}
439
440uint32_t sdlInput::prefToMask()
441{
442 const auto& mapping = getSdlMap();
443 uint32_t mod = KMOD_NONE;
444 for (const auto& val : SdlPref::instance()->get_array("SDL_KeyModMask", { "KMOD_RSHIFT" }))
445 {
446 auto it = mapping.find(val);
447 if (it != mapping.end())
448 mod |= it->second;
449 }
450 return mod;
451}
452
453static Uint32 sdl_scancode_val(const char* scancodeName)
454{
455 for (const auto& cur : map)
456 {
457 if (strcmp(cur.sdl_name, scancodeName) == 0)
458 return cur.sdl;
459 }
460
461 return SDL_SCANCODE_UNKNOWN;
462}
463
464static UINT32 sdl_scancode_to_rdp(Uint32 scancode)
465{
466 UINT32 rdp = RDP_SCANCODE_UNKNOWN;
467
468 for (const auto& cur : map)
469 {
470 if (cur.sdl == scancode)
471 {
472 rdp = cur.rdp;
473 break;
474 }
475 }
476
477#if defined(WITH_DEBUG_SDL_KBD_EVENTS)
478 auto code = static_cast<SDL_Scancode>(scancode);
479 WLog_DBG(TAG, "got %s [0x%08" PRIx32 "] -> [%s]", SDL_GetScancodeName(code), scancode,
480 freerdp_keyboard_scancode_name(rdp));
481#endif
482 return rdp;
483}
484
485uint32_t sdlInput::prefKeyValue(const std::string& key, uint32_t fallback)
486{
487 auto item = SdlPref::instance()->get_string(key);
488 if (item.empty())
489 return fallback;
490 auto val = sdl_scancode_val(item.c_str());
491 if (val == SDL_SCANCODE_UNKNOWN)
492 return fallback;
493 return val;
494}
495
496std::list<std::string> sdlInput::tokenize(const std::string& data, const std::string& delimiter)
497{
498 size_t lastpos = 0;
499 size_t pos = 0;
500 std::list<std::string> list;
501 while ((pos = data.find(delimiter, lastpos)) != std::string::npos)
502 {
503 auto token = data.substr(lastpos, pos);
504 lastpos = pos + 1;
505 list.push_back(std::move(token));
506 }
507 auto token = data.substr(lastpos);
508 list.push_back(std::move(token));
509 return list;
510}
511
512bool sdlInput::extract(const std::string& token, uint32_t& key, uint32_t& value)
513{
514 return freerdp_extract_key_value(token.c_str(), &key, &value);
515}
516
517BOOL sdlInput::keyboard_handle_event(const SDL_KeyboardEvent* ev)
518{
519 WINPR_ASSERT(ev);
520 const UINT32 rdp_scancode = sdl_scancode_to_rdp(ev->keysym.scancode);
521 const SDL_Keymod mods = SDL_GetModState();
522
523 if (_hotkeysEnabled && (mods & _hotkeyModmask) == _hotkeyModmask)
524 {
525 if (ev->type == SDL_KEYDOWN)
526 {
527 if (ev->keysym.scancode == _hotkeyFullscreen)
528 {
529 _sdl->update_fullscreen(!_sdl->fullscreen);
530 return TRUE;
531 }
532 if (ev->keysym.scancode == _hotkeyResizable)
533 {
534 _sdl->update_resizeable(!_sdl->resizeable);
535 return TRUE;
536 }
537
538 if (ev->keysym.scancode == _hotkeyGrab)
539 {
540 keyboard_grab(ev->windowID, !_sdl->grab_kbd);
541 return TRUE;
542 }
543 if (ev->keysym.scancode == _hotkeyDisconnect)
544 {
545 freerdp_abort_connect_context(_sdl->context());
546 return TRUE;
547 }
548 if (ev->keysym.scancode == _hotkeyMinimize)
549 {
550 _sdl->update_minimize();
551 return TRUE;
552 }
553 }
554 }
555
556 auto scancode = freerdp_keyboard_remap_key(_remapTable, rdp_scancode);
557 return freerdp_input_send_keyboard_event_ex(_sdl->context()->input, ev->type == SDL_KEYDOWN,
558 ev->repeat, scancode);
559}
560
561BOOL sdlInput::keyboard_grab(Uint32 windowID, bool enable)
562{
563 auto it = _sdl->windows.find(windowID);
564 if (it == _sdl->windows.end())
565 return FALSE;
566
567 auto status = enable && _sdl->grab_kbd_enabled;
568 _sdl->grab_kbd = status;
569 return it->second.grabKeyboard(status);
570}
571
572BOOL sdlInput::mouse_focus(Uint32 windowID)
573{
574 if (_lastWindowID != windowID)
575 {
576 _lastWindowID = windowID;
577 auto it = _sdl->windows.find(windowID);
578 if (it == _sdl->windows.end())
579 return FALSE;
580
581 it->second.raise();
582 }
583 return TRUE;
584}
585
586BOOL sdlInput::mouse_grab(Uint32 windowID, SDL_bool enable)
587{
588 auto it = _sdl->windows.find(windowID);
589 if (it == _sdl->windows.end())
590 return FALSE;
591 _sdl->grab_mouse = enable;
592 return it->second.grabMouse(enable);
593}
594
595sdlInput::sdlInput(SdlContext* sdl)
596 : _sdl(sdl), _lastWindowID(UINT32_MAX), _hotkeysEnabled(prefToEnabled()),
597 _hotkeyModmask(prefToMask())
598{
599 auto list =
600 freerdp_settings_get_string(_sdl->context()->settings, FreeRDP_KeyboardRemappingList);
601 _remapTable = freerdp_keyboard_remap_string_to_list(list);
602 assert(_remapTable);
603 _hotkeyFullscreen = prefKeyValue("SDL_Fullscreen", SDL_SCANCODE_RETURN);
604 _hotkeyResizable = prefKeyValue("SDL_Resizeable", SDL_SCANCODE_R);
605 _hotkeyGrab = prefKeyValue("SDL_Grab", SDL_SCANCODE_G);
606 _hotkeyDisconnect = prefKeyValue("SDL_Disconnect", SDL_SCANCODE_D);
607 _hotkeyMinimize = prefKeyValue("SDL_Minimize", SDL_SCANCODE_M);
608}
609
610sdlInput::~sdlInput()
611{
612 freerdp_keyboard_remap_free(_remapTable);
613}
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.