FreeRDP
Loading...
Searching...
No Matches
keyboard.c
1
20#include <freerdp/config.h>
21
22#include <stdio.h>
23#include <string.h>
24#include <stdint.h>
25
26#include <winpr/assert.h>
27#include <winpr/crt.h>
28
29#include <freerdp/utils/string.h>
30#include <freerdp/types.h>
31#include <freerdp/locale/keyboard.h>
32#include <freerdp/locale/locale.h>
33
34#include <freerdp/log.h>
35
36#include "liblocale.h"
37
38#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
39#define TAG FREERDP_TAG("locale.keyboard")
40
41#if defined(__MACOSX__)
42#include "keyboard_apple.h"
43#endif
44
45#ifdef WITH_X11
46#include "keyboard_x11.h"
47
48#ifdef WITH_XKBFILE
49#include "keyboard_xkbfile.h"
50#endif
51#endif
52
53#endif
54
55#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
56static WINPR_KEYCODE_TYPE maptype = WINPR_KEYCODE_TYPE_NONE;
57static DWORD VIRTUAL_SCANCODE_TO_X11_KEYCODE[256][2] = { 0 };
58static DWORD X11_KEYCODE_TO_VIRTUAL_SCANCODE[256] = { 0 };
59static DWORD REMAPPING_TABLE[0x10000] = { 0 };
60#endif
61
62struct rdp_remap_table
63{
64 DWORD table[0x10000];
65};
66
67struct scancode_map_entry
68{
69 DWORD scancode;
70 const char* name;
71};
72
73static const struct scancode_map_entry RDP_SCANCODE_MAP[] = {
74 { RDP_SCANCODE_ESCAPE, "VK_ESCAPE" },
75 { RDP_SCANCODE_KEY_1, "VK_KEY_1" },
76 { RDP_SCANCODE_KEY_2, "VK_KEY_2" },
77 { RDP_SCANCODE_KEY_3, "VK_KEY_3" },
78 { RDP_SCANCODE_KEY_4, "VK_KEY_4" },
79 { RDP_SCANCODE_KEY_5, "VK_KEY_5" },
80 { RDP_SCANCODE_KEY_6, "VK_KEY_6" },
81 { RDP_SCANCODE_KEY_7, "VK_KEY_7" },
82 { RDP_SCANCODE_KEY_8, "VK_KEY_8" },
83 { RDP_SCANCODE_KEY_9, "VK_KEY_9" },
84 { RDP_SCANCODE_KEY_0, "VK_KEY_0" },
85 { RDP_SCANCODE_OEM_MINUS, "VK_OEM_MINUS" },
86 { RDP_SCANCODE_OEM_PLUS, "VK_OEM_PLUS" },
87 { RDP_SCANCODE_BACKSPACE, "VK_BACK Backspace" },
88 { RDP_SCANCODE_TAB, "VK_TAB" },
89 { RDP_SCANCODE_KEY_Q, "VK_KEY_Q" },
90 { RDP_SCANCODE_KEY_W, "VK_KEY_W" },
91 { RDP_SCANCODE_KEY_E, "VK_KEY_E" },
92 { RDP_SCANCODE_KEY_R, "VK_KEY_R" },
93 { RDP_SCANCODE_KEY_T, "VK_KEY_T" },
94 { RDP_SCANCODE_KEY_Y, "VK_KEY_Y" },
95 { RDP_SCANCODE_KEY_U, "VK_KEY_U" },
96 { RDP_SCANCODE_KEY_I, "VK_KEY_I" },
97 { RDP_SCANCODE_KEY_O, "VK_KEY_O" },
98 { RDP_SCANCODE_KEY_P, "VK_KEY_P" },
99 { RDP_SCANCODE_OEM_4, "VK_OEM_4 '[' on US" },
100 { RDP_SCANCODE_OEM_6, "VK_OEM_6 ']' on US" },
101 { RDP_SCANCODE_RETURN, "VK_RETURN Normal Enter" },
102 { RDP_SCANCODE_LCONTROL, "VK_LCONTROL" },
103 { RDP_SCANCODE_KEY_A, "VK_KEY_A" },
104 { RDP_SCANCODE_KEY_S, "VK_KEY_S" },
105 { RDP_SCANCODE_KEY_D, "VK_KEY_D" },
106 { RDP_SCANCODE_KEY_F, "VK_KEY_F" },
107 { RDP_SCANCODE_KEY_G, "VK_KEY_G" },
108 { RDP_SCANCODE_KEY_H, "VK_KEY_H" },
109 { RDP_SCANCODE_KEY_J, "VK_KEY_J" },
110 { RDP_SCANCODE_KEY_K, "VK_KEY_K" },
111 { RDP_SCANCODE_KEY_L, "VK_KEY_L" },
112 { RDP_SCANCODE_OEM_1, "VK_OEM_1 ';' on US" },
113 { RDP_SCANCODE_OEM_7, "VK_OEM_7 on US" },
114 { RDP_SCANCODE_OEM_3, "VK_OEM_3 Top left, '`' on US, JP DBE_SBCSCHAR" },
115 { RDP_SCANCODE_LSHIFT, "VK_LSHIFT" },
116 { RDP_SCANCODE_OEM_5, "VK_OEM_5 Next to Enter, '\' on US" },
117 { RDP_SCANCODE_KEY_Z, "VK_KEY_Z" },
118 { RDP_SCANCODE_KEY_X, "VK_KEY_X" },
119 { RDP_SCANCODE_KEY_C, "VK_KEY_C" },
120 { RDP_SCANCODE_KEY_V, "VK_KEY_V" },
121 { RDP_SCANCODE_KEY_B, "VK_KEY_B" },
122 { RDP_SCANCODE_KEY_N, "VK_KEY_N" },
123 { RDP_SCANCODE_KEY_M, "VK_KEY_M" },
124 { RDP_SCANCODE_OEM_COMMA, "VK_OEM_COMMA" },
125 { RDP_SCANCODE_OEM_PERIOD, "VK_OEM_PERIOD" },
126 { RDP_SCANCODE_OEM_2, "VK_OEM_2 '/' on US" },
127 { RDP_SCANCODE_RSHIFT, "VK_RSHIFT" },
128 { RDP_SCANCODE_MULTIPLY, "VK_MULTIPLY Numerical" },
129 { RDP_SCANCODE_LMENU, "VK_LMENU Left 'Alt' key" },
130 { RDP_SCANCODE_SPACE, "VK_SPACE" },
131 { RDP_SCANCODE_CAPSLOCK, "VK_CAPITAL 'Caps Lock', JP DBE_ALPHANUMERIC" },
132 { RDP_SCANCODE_F1, "VK_F1" },
133 { RDP_SCANCODE_F2, "VK_F2" },
134 { RDP_SCANCODE_F3, "VK_F3" },
135 { RDP_SCANCODE_F4, "VK_F4" },
136 { RDP_SCANCODE_F5, "VK_F5" },
137 { RDP_SCANCODE_F6, "VK_F6" },
138 { RDP_SCANCODE_F7, "VK_F7" },
139 { RDP_SCANCODE_F8, "VK_F8" },
140 { RDP_SCANCODE_F9, "VK_F9" },
141 { RDP_SCANCODE_F10, "VK_F10" },
142 { RDP_SCANCODE_NUMLOCK, "VK_NUMLOCK" },
143 { RDP_SCANCODE_SCROLLLOCK, "VK_SCROLL 'Scroll Lock', JP OEM_SCROLL" },
144 { RDP_SCANCODE_NUMPAD7, "VK_NUMPAD7" },
145 { RDP_SCANCODE_NUMPAD8, "VK_NUMPAD8" },
146 { RDP_SCANCODE_NUMPAD9, "VK_NUMPAD9" },
147 { RDP_SCANCODE_SUBTRACT, "VK_SUBTRACT" },
148 { RDP_SCANCODE_NUMPAD4, "VK_NUMPAD4" },
149 { RDP_SCANCODE_NUMPAD5, "VK_NUMPAD5" },
150 { RDP_SCANCODE_NUMPAD6, "VK_NUMPAD6" },
151 { RDP_SCANCODE_ADD, "VK_ADD" },
152 { RDP_SCANCODE_NUMPAD1, "VK_NUMPAD1" },
153 { RDP_SCANCODE_NUMPAD2, "VK_NUMPAD2" },
154 { RDP_SCANCODE_NUMPAD3, "VK_NUMPAD3" },
155 { RDP_SCANCODE_NUMPAD0, "VK_NUMPAD0" },
156 { RDP_SCANCODE_DECIMAL, "VK_DECIMAL Numerical, '.' on US" },
157 { RDP_SCANCODE_SYSREQ, "Sys Req" },
158 { RDP_SCANCODE_OEM_102, "VK_OEM_102 Lower left '\' on US" },
159 { RDP_SCANCODE_F11, "VK_F11" },
160 { RDP_SCANCODE_F12, "VK_F12" },
161 { RDP_SCANCODE_SLEEP, "VK_SLEEP OEM_8 on FR (undocumented?)" },
162 { RDP_SCANCODE_ZOOM, "VK_ZOOM (undocumented?)" },
163 { RDP_SCANCODE_HELP, "VK_HELP (undocumented?)" },
164 { RDP_SCANCODE_F13, "VK_F13" },
165 { RDP_SCANCODE_F14, "VK_F14" },
166 { RDP_SCANCODE_F15, "VK_F15" },
167 { RDP_SCANCODE_F16, "VK_F16" },
168 { RDP_SCANCODE_F17, "VK_F17" },
169 { RDP_SCANCODE_F18, "VK_F18" },
170 { RDP_SCANCODE_F19, "VK_F19" },
171 { RDP_SCANCODE_F20, "VK_F20" },
172 { RDP_SCANCODE_F21, "VK_F21" },
173 { RDP_SCANCODE_F22, "VK_F22" },
174 { RDP_SCANCODE_F23, "VK_F23" },
175 { RDP_SCANCODE_F24, "VK_F24" },
176 { RDP_SCANCODE_HIRAGANA, "JP DBE_HIRAGANA" },
177 { RDP_SCANCODE_HANJA_KANJI, "VK_HANJA / VK_KANJI (undocumented?)" },
178 { RDP_SCANCODE_KANA_HANGUL, "VK_KANA / VK_HANGUL (undocumented?)" },
179 { RDP_SCANCODE_ABNT_C1, "VK_ABNT_C1 JP OEM_102" },
180 { RDP_SCANCODE_F24_JP, "JP F24" },
181 { RDP_SCANCODE_CONVERT_JP, "JP VK_CONVERT" },
182 { RDP_SCANCODE_NONCONVERT_JP, "JP VK_NONCONVERT" },
183 { RDP_SCANCODE_TAB_JP, "JP TAB" },
184 { RDP_SCANCODE_BACKSLASH_JP, "JP OEM_5 ('\')" },
185 { RDP_SCANCODE_ABNT_C2, "VK_ABNT_C2, JP" },
186 { RDP_SCANCODE_HANJA, "KR VK_HANJA" },
187 { RDP_SCANCODE_HANGUL, "KR VK_HANGUL" },
188 { RDP_SCANCODE_RETURN_KP, "not RDP_SCANCODE_RETURN Numerical Enter" },
189 { RDP_SCANCODE_RCONTROL, "VK_RCONTROL" },
190 { RDP_SCANCODE_DIVIDE, "VK_DIVIDE Numerical" },
191 { RDP_SCANCODE_PRINTSCREEN, "VK_EXECUTE/VK_PRINT/VK_SNAPSHOT Print Screen" },
192 { RDP_SCANCODE_RMENU, "VK_RMENU Right 'Alt' / 'Alt Gr'" },
193 { RDP_SCANCODE_PAUSE, "VK_PAUSE Pause / Break (Slightly special handling)" },
194 { RDP_SCANCODE_HOME, "VK_HOME" },
195 { RDP_SCANCODE_UP, "VK_UP" },
196 { RDP_SCANCODE_PRIOR, "VK_PRIOR 'Page Up'" },
197 { RDP_SCANCODE_LEFT, "VK_LEFT" },
198 { RDP_SCANCODE_RIGHT, "VK_RIGHT" },
199 { RDP_SCANCODE_END, "VK_END" },
200 { RDP_SCANCODE_DOWN, "VK_DOWN" },
201 { RDP_SCANCODE_NEXT, "VK_NEXT 'Page Down'" },
202 { RDP_SCANCODE_INSERT, "VK_INSERT" },
203 { RDP_SCANCODE_DELETE, "VK_DELETE" },
204 { RDP_SCANCODE_NULL, "<00>" },
205 { RDP_SCANCODE_HELP2, "Help - documented, different from VK_HELP" },
206 { RDP_SCANCODE_LWIN, "VK_LWIN" },
207 { RDP_SCANCODE_RWIN, "VK_RWIN" },
208 { RDP_SCANCODE_APPS, "VK_APPS Application" },
209 { RDP_SCANCODE_POWER_JP, "JP POWER" },
210 { RDP_SCANCODE_SLEEP_JP, "JP SLEEP" },
211 { RDP_SCANCODE_NUMLOCK_EXTENDED, "should be RDP_SCANCODE_NUMLOCK" },
212 { RDP_SCANCODE_RSHIFT_EXTENDED, "should be RDP_SCANCODE_RSHIFT" },
213 { RDP_SCANCODE_VOLUME_MUTE, "VK_VOLUME_MUTE" },
214 { RDP_SCANCODE_VOLUME_DOWN, "VK_VOLUME_DOWN" },
215 { RDP_SCANCODE_VOLUME_UP, "VK_VOLUME_UP" },
216 { RDP_SCANCODE_MEDIA_NEXT_TRACK, "VK_MEDIA_NEXT_TRACK" },
217 { RDP_SCANCODE_MEDIA_PREV_TRACK, "VK_MEDIA_PREV_TRACK" },
218 { RDP_SCANCODE_MEDIA_STOP, "VK_MEDIA_MEDIA_STOP" },
219 { RDP_SCANCODE_MEDIA_PLAY_PAUSE, "VK_MEDIA_MEDIA_PLAY_PAUSE" },
220 { RDP_SCANCODE_BROWSER_BACK, "VK_BROWSER_BACK" },
221 { RDP_SCANCODE_BROWSER_FORWARD, "VK_BROWSER_FORWARD" },
222 { RDP_SCANCODE_BROWSER_REFRESH, "VK_BROWSER_REFRESH" },
223 { RDP_SCANCODE_BROWSER_STOP, "VK_BROWSER_STOP" },
224 { RDP_SCANCODE_BROWSER_SEARCH, "VK_BROWSER_SEARCH" },
225 { RDP_SCANCODE_BROWSER_FAVORITES, "VK_BROWSER_FAVORITES" },
226 { RDP_SCANCODE_BROWSER_HOME, "VK_BROWSER_HOME" },
227 { RDP_SCANCODE_LAUNCH_MAIL, "VK_LAUNCH_MAIL" },
228 { RDP_SCANCODE_LAUNCH_MEDIA_SELECT, "VK_LAUNCH_MEDIA_SELECT" },
229 { RDP_SCANCODE_LAUNCH_APP1, "VK_LAUNCH_APP1" },
230 { RDP_SCANCODE_LAUNCH_APP2, "VK_LAUNCH_APP2" },
231};
232
233#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
234static int freerdp_detect_keyboard(DWORD* keyboardLayoutId)
235{
236#if defined(_WIN32)
237 CHAR name[KL_NAMELENGTH + 1] = { 0 };
238 if (GetKeyboardLayoutNameA(name))
239 {
240 ULONG rc;
241
242 errno = 0;
243 rc = strtoul(name, NULL, 16);
244 if (errno == 0)
245 *keyboardLayoutId = rc;
246 }
247
248 if (*keyboardLayoutId == 0)
249 {
250 const HKL layout = GetKeyboardLayout(0);
251 const uint32_t masked = (uint32_t)(((uintptr_t)layout >> 16) & 0xFFFF);
252 *keyboardLayoutId = masked;
253 }
254#endif
255
256#if defined(__MACOSX__)
257 if (*keyboardLayoutId == 0)
258 freerdp_detect_keyboard_layout_from_cf(keyboardLayoutId);
259#endif
260
261#ifdef WITH_X11
262 if (*keyboardLayoutId == 0)
263 freerdp_detect_keyboard_layout_from_xkb(keyboardLayoutId);
264#endif
265
266 if (*keyboardLayoutId == 0)
267 freerdp_detect_keyboard_layout_from_system_locale(keyboardLayoutId);
268
269 if (*keyboardLayoutId == 0)
270 *keyboardLayoutId = ENGLISH_UNITED_STATES;
271
272 return 0;
273}
274
275#if defined(__APPLE__)
276static int freerdp_keyboard_init_apple(WINPR_ATTR_UNUSED const DWORD* keyboardLayoutId,
277 DWORD* x11_keycode_to_rdp_scancode, size_t count)
278{
279 WINPR_ASSERT(x11_keycode_to_rdp_scancode);
280 WINPR_ASSERT(keyboardLayoutId);
281 WINPR_ASSERT(count <= UINT32_MAX);
282 for (size_t keycode = 8; keycode < count; keycode++)
283 {
284 const DWORD vkcode =
285 GetVirtualKeyCodeFromKeycode((UINT32)keycode - 8u, WINPR_KEYCODE_TYPE_APPLE);
286 x11_keycode_to_rdp_scancode[keycode] =
287 GetVirtualScanCodeFromVirtualKeyCode(vkcode, WINPR_KBD_TYPE_IBM_ENHANCED);
288 }
289
290 maptype = WINPR_KEYCODE_TYPE_APPLE;
291 return 0;
292}
293#endif
294
295static int freerdp_keyboard_init_x11_evdev(WINPR_ATTR_UNUSED const DWORD* keyboardLayoutId,
296 DWORD* x11_keycode_to_rdp_scancode, size_t count)
297{
298 WINPR_ASSERT(keyboardLayoutId);
299 WINPR_ASSERT(x11_keycode_to_rdp_scancode);
300 WINPR_ASSERT(count <= UINT32_MAX);
301
302 for (size_t keycode = 0; keycode < count; keycode++)
303 {
304 const DWORD vkcode =
305 GetVirtualKeyCodeFromKeycode((UINT32)keycode, WINPR_KEYCODE_TYPE_EVDEV);
306 x11_keycode_to_rdp_scancode[keycode] =
307 GetVirtualScanCodeFromVirtualKeyCode(vkcode, WINPR_KBD_TYPE_IBM_ENHANCED);
308 }
309 maptype = WINPR_KEYCODE_TYPE_EVDEV;
310
311 return 0;
312}
313
314DWORD freerdp_keyboard_init(DWORD keyboardLayoutId)
315{
316 int status = -1;
317
318#if defined(__APPLE__)
319 if (status < 0)
320 status = freerdp_keyboard_init_apple(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE,
321 ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
322#endif
323
324#if defined(WITH_X11) || defined(WITH_WAYLAND)
325
326#ifdef WITH_XKBFILE
327 if (status < 0)
328 {
329 status = freerdp_keyboard_init_xkbfile(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE,
330 ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
331 if (status >= 0)
332 maptype = WINPR_KEYCODE_TYPE_XKB;
333 }
334#endif
335
336 if (status < 0)
337 status = freerdp_keyboard_init_x11_evdev(&keyboardLayoutId, X11_KEYCODE_TO_VIRTUAL_SCANCODE,
338 ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
339
340#endif
341
342 if (status < 0)
343 WLog_DBG(TAG, "Platform keyboard detection failed, trying autodetection");
344
345 freerdp_detect_keyboard(&keyboardLayoutId);
346
347 ZeroMemory(VIRTUAL_SCANCODE_TO_X11_KEYCODE, sizeof(VIRTUAL_SCANCODE_TO_X11_KEYCODE));
348
349 WINPR_STATIC_ASSERT(ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE) <= UINT32_MAX);
350 for (size_t keycode = 0; keycode < ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE); keycode++)
351 {
352 const DWORD x11 = X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode];
353 const DWORD sc = RDP_SCANCODE_CODE(x11);
354 const BOOL ex = RDP_SCANCODE_EXTENDED(x11);
355 VIRTUAL_SCANCODE_TO_X11_KEYCODE[sc][ex ? 1 : 0] = (UINT32)keycode;
356 }
357
358 return keyboardLayoutId;
359}
360#endif
361
362FREERDP_REMAP_TABLE* freerdp_keyboard_remap_string_to_list(const char* list)
363{
364 const size_t remap_table_size = 0x10000;
365
366 FREERDP_REMAP_TABLE* remap_table = calloc(1, sizeof(FREERDP_REMAP_TABLE));
367 if (!remap_table)
368 return NULL;
369
370 for (size_t x = 0; x < ARRAYSIZE(remap_table->table); x++)
371 remap_table->table[x] = (UINT32)x;
372
373 if (!list)
374 return remap_table;
375
376 BOOL success = FALSE;
377 char* copy = _strdup(list);
378 if (!copy)
379 goto fail;
380
381 char* context = NULL;
382 char* token = strtok_s(copy, ",", &context);
383 while (token)
384 {
385 DWORD key = 0;
386 DWORD value = 0;
387 if (!freerdp_extract_key_value(token, &key, &value))
388 goto fail;
389 if (key >= remap_table_size)
390 goto fail;
391 remap_table->table[key] = value;
392 token = strtok_s(NULL, ",", &context);
393 }
394
395 success = TRUE;
396
397fail:
398 free(copy);
399
400 if (!success)
401 {
402 free(remap_table);
403 return NULL;
404 }
405 return remap_table;
406}
407
408#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
409DWORD freerdp_keyboard_init_ex(DWORD keyboardLayoutId, const char* keyboardRemappingList)
410{
411 DWORD res = freerdp_keyboard_init(keyboardLayoutId);
412
413 memset(REMAPPING_TABLE, 0, sizeof(REMAPPING_TABLE));
414 if (keyboardRemappingList)
415 {
416 char* copy = _strdup(keyboardRemappingList);
417 char* context = NULL;
418 char* token = NULL;
419 if (!copy)
420 goto fail;
421 token = strtok_s(copy, ",", &context);
422 while (token)
423 {
424 DWORD key = 0;
425 DWORD value = 0;
426 if (!freerdp_extract_key_value(token, &key, &value))
427 goto fail;
428 if (key >= ARRAYSIZE(REMAPPING_TABLE))
429 goto fail;
430 REMAPPING_TABLE[key] = value;
431 token = strtok_s(NULL, ",", &context);
432 }
433 fail:
434 free(copy);
435 }
436 return res;
437}
438
439DWORD freerdp_keyboard_get_rdp_scancode_from_x11_keycode(DWORD keycode)
440{
441 if (keycode >= ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE))
442 {
443 WLog_ERR(TAG, "KeyCode %" PRIu32 " exceeds allowed value range [0,%" PRIuz "]", keycode,
444 ARRAYSIZE(X11_KEYCODE_TO_VIRTUAL_SCANCODE));
445 return 0;
446 }
447
448 const DWORD scancode = X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode];
449 if (scancode >= ARRAYSIZE(REMAPPING_TABLE))
450 {
451 WLog_ERR(TAG, "ScanCode %" PRIu32 " exceeds allowed value range [0,%" PRIuz "]", scancode,
452 ARRAYSIZE(REMAPPING_TABLE));
453 return 0;
454 }
455
456 const DWORD remapped = REMAPPING_TABLE[scancode];
457#if defined(WITH_DEBUG_KBD)
458 const BOOL ex = RDP_SCANCODE_EXTENDED(scancode);
459 const DWORD sc = RDP_SCANCODE_CODE(scancode);
460#endif
461
462 DEBUG_KBD("x11 keycode: %02" PRIX32 " -> rdp code: [%04" PRIx16 "] %02" PRIX8 "%s", keycode,
463 scancode, sc, ex ? " extended" : "");
464
465 if (remapped != 0)
466 {
467#if defined(WITH_DEBUG_KBD)
468 const DWORD rsc = RDP_SCANCODE_CODE(remapped);
469 const BOOL rex = RDP_SCANCODE_EXTENDED(remapped);
470#endif
471
472 DEBUG_KBD("remapped scancode: [%04" PRIx16 "] %02" PRIX8 "[%s] -> [%04" PRIx16 "] %02" PRIX8
473 "[%s]",
474 scancode, sc, ex ? " extended" : "", remapped, rsc, rex ? " extended" : "");
475 return remapped;
476 }
477 return scancode;
478}
479
480DWORD freerdp_keyboard_get_x11_keycode_from_rdp_scancode(DWORD scancode, BOOL extended)
481{
482 if (scancode >= ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE))
483 {
484 WLog_ERR(TAG, "ScanCode %" PRIu32 " exceeds allowed value range [0,%" PRIuz "]", scancode,
485 ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE));
486 return 0;
487 }
488
489 const DWORD* x11 = VIRTUAL_SCANCODE_TO_X11_KEYCODE[scancode];
490 WINPR_ASSERT(x11);
491
492 if (extended)
493 return x11[1];
494 else
495 return x11[0];
496}
497#endif
498
499const char* freerdp_keyboard_scancode_name(DWORD scancode)
500{
501 for (size_t x = 0; x < ARRAYSIZE(RDP_SCANCODE_MAP); x++)
502 {
503 const struct scancode_map_entry* entry = &RDP_SCANCODE_MAP[x];
504 if (entry->scancode == scancode)
505 return entry->name;
506 }
507
508 return NULL;
509}
510
511DWORD freerdp_keyboard_remap_key(const FREERDP_REMAP_TABLE* remap_table, DWORD rdpScanCode)
512{
513 if (!remap_table || (ARRAYSIZE(remap_table->table) <= rdpScanCode))
514 return 0;
515
516 return remap_table->table[rdpScanCode];
517}
518
519void freerdp_keyboard_remap_free(FREERDP_REMAP_TABLE* table)
520{
521 free(table);
522}