23#include <winpr/config.h>
24#include <winpr/assert.h>
26#include <winpr/path.h>
27#include <winpr/json.h>
29#include <winpr/input.h>
32#define TAG WINPR_TAG("input.scancode")
34#define KBD_ARRAY_SIZE 256
37#define MIN(x, y) (((x) < (y)) ? (x) : (y))
42 DWORD multivk[KBD_ARRAY_SIZE];
43 DWORD kbdext[KBD_ARRAY_SIZE];
44 DWORD normal[KBD_ARRAY_SIZE];
47static const char KEYBOARD_CONFIG_FILE_NAME[] =
"KeyboardMapping.json";
48static INIT_ONCE VKmapInitialized = INIT_ONCE_STATIC_INIT;
49static ScancodeToVKMap_t VKmap[8];
62static const DWORD KBD4T[KBD_ARRAY_SIZE] = {
63 KBD4_T00, KBD4_T01, KBD4_T02, KBD4_T03, KBD4_T04, KBD4_T05, KBD4_T06, KBD4_T07, KBD4_T08,
64 KBD4_T09, KBD4_T0A, KBD4_T0B, KBD4_T0C, KBD4_T0D, KBD4_T0E, KBD4_T0F, KBD4_T10, KBD4_T11,
65 KBD4_T12, KBD4_T13, KBD4_T14, KBD4_T15, KBD4_T16, KBD4_T17, KBD4_T18, KBD4_T19, KBD4_T1A,
66 KBD4_T1B, KBD4_T1C, KBD4_T1D, KBD4_T1E, KBD4_T1F, KBD4_T20, KBD4_T21, KBD4_T22, KBD4_T23,
67 KBD4_T24, KBD4_T25, KBD4_T26, KBD4_T27, KBD4_T28, KBD4_T29, KBD4_T2A, KBD4_T2B, KBD4_T2C,
68 KBD4_T2D, KBD4_T2E, KBD4_T2F, KBD4_T30, KBD4_T31, KBD4_T32, KBD4_T33, KBD4_T34, KBD4_T35,
69 KBD4_T36, KBD4_T37, KBD4_T38, KBD4_T39, KBD4_T3A, KBD4_T3B, KBD4_T3C, KBD4_T3D, KBD4_T3E,
70 KBD4_T3F, KBD4_T40, KBD4_T41, KBD4_T42, KBD4_T43, KBD4_T44, KBD4_T45, KBD4_T46, KBD4_T47,
71 KBD4_T48, KBD4_T49, KBD4_T4A, KBD4_T4B, KBD4_T4C, KBD4_T4D, KBD4_T4E, KBD4_T4F, KBD4_T50,
72 KBD4_T51, KBD4_T52, KBD4_T53, KBD4_T54, KBD4_T55, KBD4_T56, KBD4_T57, KBD4_T58, KBD4_T59,
73 KBD4_T5A, KBD4_T5B, KBD4_T5C, KBD4_T5D, KBD4_T5E, KBD4_T5F, KBD4_T60, KBD4_T61, KBD4_T62,
74 KBD4_T63, KBD4_T64, KBD4_T65, KBD4_T66, KBD4_T67, KBD4_T68, KBD4_T69, KBD4_T6A, KBD4_T6B,
75 KBD4_T6C, KBD4_T6D, KBD4_T6E, KBD4_T6F, KBD4_T70, KBD4_T71, KBD4_T72, KBD4_T73, KBD4_T74,
76 KBD4_T75, KBD4_T76, KBD4_T77, KBD4_T78, KBD4_T79, KBD4_T7A, KBD4_T7B, KBD4_T7C, KBD4_T7D,
80static const DWORD KBD4X[KBD_ARRAY_SIZE] = {
81 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
82 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, KBD4_X10, VK_NONE,
83 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, KBD4_X19, VK_NONE,
84 VK_NONE, KBD4_X1C, KBD4_X1D, VK_NONE, VK_NONE, KBD4_X20, KBD4_X21, KBD4_X22, VK_NONE,
85 KBD4_X24, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
86 VK_NONE, KBD4_X2E, VK_NONE, KBD4_X30, VK_NONE, KBD4_X32, VK_NONE, VK_NONE, KBD4_X35,
87 VK_NONE, KBD4_X37, KBD4_X38, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
88 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, KBD4_X46, KBD4_X47,
89 KBD4_X48, KBD4_X49, VK_NONE, KBD4_X4B, VK_NONE, KBD4_X4D, VK_NONE, KBD4_X4F, KBD4_X50,
90 KBD4_X51, KBD4_X52, KBD4_X53, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
91 VK_NONE, KBD4_X5B, KBD4_X5C, KBD4_X5D, KBD4_X5E, KBD4_X5F, VK_NONE, VK_NONE, VK_NONE,
92 VK_NONE, VK_NONE, KBD4_X65, KBD4_X66, KBD4_X67, KBD4_X68, KBD4_X69, KBD4_X6A, KBD4_X6B,
93 KBD4_X6C, KBD4_X6D, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
94 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
98static const DWORD KBD4X_1[KBD_ARRAY_SIZE] = {
99 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
100 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
101 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_PAUSE,
102 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
103 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
104 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
105 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
106 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
107 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
108 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
109 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
110 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
111 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE
121static const DWORD KBD7T[KBD_ARRAY_SIZE] = {
122 KBD7_T00, KBD7_T01, KBD7_T02, KBD7_T03, KBD7_T04, KBD7_T05, KBD7_T06, KBD7_T07, KBD7_T08,
123 KBD7_T09, KBD7_T0A, KBD7_T0B, KBD7_T0C, KBD7_T0D, KBD7_T0E, KBD7_T0F, KBD7_T10, KBD7_T11,
124 KBD7_T12, KBD7_T13, KBD7_T14, KBD7_T15, KBD7_T16, KBD7_T17, KBD7_T18, KBD7_T19, KBD7_T1A,
125 KBD7_T1B, KBD7_T1C, KBD7_T1D, KBD7_T1E, KBD7_T1F, KBD7_T20, KBD7_T21, KBD7_T22, KBD7_T23,
126 KBD7_T24, KBD7_T25, KBD7_T26, KBD7_T27, KBD7_T28, KBD7_T29, KBD7_T2A, KBD7_T2B, KBD7_T2C,
127 KBD7_T2D, KBD7_T2E, KBD7_T2F, KBD7_T30, KBD7_T31, KBD7_T32, KBD7_T33, KBD7_T34, KBD7_T35,
128 KBD7_T36, KBD7_T37, KBD7_T38, KBD7_T39, KBD7_T3A, KBD7_T3B, KBD7_T3C, KBD7_T3D, KBD7_T3E,
129 KBD7_T3F, KBD7_T40, KBD7_T41, KBD7_T42, KBD7_T43, KBD7_T44, KBD7_T45, KBD7_T46, KBD7_T47,
130 KBD7_T48, KBD7_T49, KBD7_T4A, KBD7_T4B, KBD7_T4C, KBD7_T4D, KBD7_T4E, KBD7_T4F, KBD7_T50,
131 KBD7_T51, KBD7_T52, KBD7_T53, KBD7_T54, KBD7_T55, KBD7_T56, KBD7_T57, KBD7_T58, KBD7_T59,
132 KBD7_T5A, KBD7_T5B, KBD7_T5C, KBD7_T5D, KBD7_T5E, KBD7_T5F, KBD7_T60, KBD7_T61, KBD7_T62,
133 KBD7_T63, KBD7_T64, KBD7_T65, KBD7_T66, KBD7_T67, KBD7_T68, KBD7_T69, KBD7_T6A, KBD7_T6B,
134 KBD7_T6C, KBD7_T6D, KBD7_T6E, KBD7_T6F, KBD7_T70, KBD7_T71, KBD7_T72, KBD7_T73, KBD7_T74,
135 KBD7_T75, KBD7_T76, KBD7_T77, KBD7_T78, KBD7_T79, KBD7_T7A, KBD7_T7B, KBD7_T7C, KBD7_T7D,
139static const DWORD KBD7X[KBD_ARRAY_SIZE] = {
140 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
141 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, KBD7_X10, VK_NONE,
142 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, KBD7_X19, VK_NONE,
143 VK_NONE, KBD7_X1C, KBD7_X1D, VK_NONE, VK_NONE, KBD7_X20, KBD7_X21, KBD7_X22, VK_NONE,
144 KBD7_X24, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
145 VK_NONE, KBD7_X2E, VK_NONE, KBD7_X30, VK_NONE, KBD7_X32, KBD7_X33, VK_NONE, KBD7_X35,
146 VK_NONE, KBD7_X37, KBD7_X38, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
147 VK_NONE, VK_NONE, VK_NONE, KBD7_X42, KBD7_X43, KBD7_X44, VK_NONE, KBD7_X46, KBD7_X47,
148 KBD7_X48, KBD7_X49, VK_NONE, KBD7_X4B, VK_NONE, KBD7_X4D, VK_NONE, KBD7_X4F, KBD7_X50,
149 KBD7_X51, KBD7_X52, KBD7_X53, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
150 VK_NONE, KBD7_X5B, KBD7_X5C, KBD7_X5D, KBD7_X5E, KBD7_X5F, VK_NONE, VK_NONE, VK_NONE,
151 VK_NONE, VK_NONE, KBD7_X65, KBD7_X66, KBD7_X67, KBD7_X68, KBD7_X69, KBD7_X6A, KBD7_X6B,
152 KBD7_X6C, KBD7_X6D, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
153 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
154 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
155 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
156 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
157 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
158 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
159 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
160 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
161 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
162 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
163 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
164 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
165 KBD7_XF1, KBD7_XF2, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
166 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE
169static const DWORD KBD7X_1[KBD_ARRAY_SIZE] = {
170 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
171 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
172 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_PAUSE,
173 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
174 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
175 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
176 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
177 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
178 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
179 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
180 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
181 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
182 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE
191static const DWORD KBD8T[KBD_ARRAY_SIZE] = {
198 VK_OEM_MINUS, VK_OEM_PLUS,
206 VK_RETURN, VK_LCONTROL,
217 VK_KEY_M, VK_OEM_COMMA,
218 VK_OEM_PERIOD, VK_OEM_2,
219 VK_RSHIFT, VK_MULTIPLY,
229 VK_SUBTRACT, VK_LEFT,
233 VK_INSERT, VK_DELETE,
234 VK_SNAPSHOT, VK_NONE,
237 VK_OEM_WSCTRL, VK_DBE_KATAKANA,
238 VK_OEM_JUMP, VK_DBE_FLUSHSTRING,
239 VK_OEM_BACKTAB, VK_OEM_AUTO,
240 VK_NONE, VK_DBE_NOCODEINPUT,
248 VK_NONE, VK_OEM_RESET,
255 VK_ABNT_C2, VK_OEM_PA2
258static const DWORD KBD8X[KBD_ARRAY_SIZE] = {
361 VK_BROWSER_FAVORITES,
368 VK_LAUNCH_MEDIA_SELECT,
502static const DWORD KBD8X_1[KBD_ARRAY_SIZE] = {
503 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
504 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
505 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_PAUSE,
506 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
507 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
508 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
509 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
510 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
511 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
512 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
513 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
514 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE,
515 VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE, VK_NONE
519static BOOL setup(
void);
522static DWORD GetVirtualKeyCodeFromVirtualScanCodeMap(DWORD scancode,
const ScancodeToVKMap_t* map)
525 const DWORD codeIndex = scancode & 0xFF;
529 if (scancode & KBDMULTIVK)
530 return map->multivk[codeIndex];
531 if (scancode & KBDEXT)
532 return map->kbdext[codeIndex];
533 return map->normal[codeIndex];
536DWORD GetVirtualKeyCodeFromVirtualScanCode(DWORD scancode, DWORD dwKeyboardType)
541 switch (dwKeyboardType)
544 case WINPR_KBD_TYPE_IBM_PC_XT:
545 case WINPR_KBD_TYPE_OLIVETTI_ICO:
546 case WINPR_KBD_TYPE_IBM_PC_AT:
547 case WINPR_KBD_TYPE_IBM_ENHANCED:
548 case WINPR_KBD_TYPE_JAPANESE:
549 case WINPR_KBD_TYPE_KOREAN:
550 case WINPR_KBD_TYPE_NOKIA_1050:
551 case WINPR_KBD_TYPE_NOKIA_9140:
552 return GetVirtualKeyCodeFromVirtualScanCodeMap(scancode, &VKmap[dwKeyboardType - 1]);
554 WLog_ERR(TAG,
"dwKeyboardType=0x%08" PRIx32
" not supported", dwKeyboardType);
560static DWORD get_scancode(
size_t offset, DWORD vkcode,
const DWORD* array,
size_t arraysize,
564 for (
size_t x = offset; x < arraysize; x++)
566 const DWORD cur = array[x];
569 const DWORD sc = WINPR_ASSERTING_INT_CAST(DWORD, x);
579static DWORD get_scancodes(DWORD vkcode,
const DWORD* array,
size_t arraysize, DWORD flag,
580 DWORD* pdwScanCodeBuffer,
size_t ScanCodeBufferSize)
587 const BOOL nobuffer = ScanCodeBufferSize == 0;
590 sc = get_scancode(offset, vkcode, array, arraysize, flag);
595 if (count < ScanCodeBufferSize)
596 pdwScanCodeBuffer[count] = sc;
599 offset = (sc & ~flag) + 1;
601 }
while ((sc != 0) && ((count < ScanCodeBufferSize) || nobuffer));
606DWORD GetVirtualScanCodeFromVirtualKeyCode(DWORD vkcode, DWORD dwKeyboardType)
608 DWORD scancodes[1] = WINPR_C_ARRAY_INIT;
609 const DWORD count = GetVirtualScanCodesFromVirtualKeyCode(vkcode, dwKeyboardType, scancodes,
610 ARRAYSIZE(scancodes));
617static const char* kbdTypeStr(
enum WINPR_KBD_TYPE type)
625 EVCASE(WINPR_KBD_TYPE_IBM_PC_XT);
626 EVCASE(WINPR_KBD_TYPE_OLIVETTI_ICO);
627 EVCASE(WINPR_KBD_TYPE_IBM_PC_AT);
628 EVCASE(WINPR_KBD_TYPE_IBM_ENHANCED);
629 EVCASE(WINPR_KBD_TYPE_NOKIA_1050);
630 EVCASE(WINPR_KBD_TYPE_NOKIA_9140);
631 EVCASE(WINPR_KBD_TYPE_JAPANESE);
632 EVCASE(WINPR_KBD_TYPE_KOREAN);
634 WLog_WARN(TAG,
"Unsupported WINPR_KBD_TYPE %08" PRIx32, type);
641static DWORD VKStrToInteger(WINPR_JSON* val,
size_t pos,
const char* section)
643 WINPR_ASSERT(section);
647 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, NULL value",
648 KEYBOARD_CONFIG_FILE_NAME, section, pos);
655 if (isnan(nr) || isinf(nr))
657 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, floating NaN/INF value %lf",
658 KEYBOARD_CONFIG_FILE_NAME, section, pos, nr);
663 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, negative value %lf",
664 KEYBOARD_CONFIG_FILE_NAME, section, pos, nr);
672 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, not a string value",
673 KEYBOARD_CONFIG_FILE_NAME, section, pos);
679#define EVCASE(str, x) \
680 if (strcmp(#x, str) == 0) \
683 EVCASE(strval, VK_LBUTTON);
684 EVCASE(strval, VK_RBUTTON);
685 EVCASE(strval, VK_CANCEL);
686 EVCASE(strval, VK_MBUTTON);
687 EVCASE(strval, VK_XBUTTON1);
688 EVCASE(strval, VK_XBUTTON2);
689 EVCASE(strval, VK_BACK);
690 EVCASE(strval, VK_TAB);
691 EVCASE(strval, VK_CLEAR);
692 EVCASE(strval, VK_RETURN);
693 EVCASE(strval, VK_SHIFT);
694 EVCASE(strval, VK_CONTROL);
695 EVCASE(strval, VK_MENU);
696 EVCASE(strval, VK_PAUSE);
697 EVCASE(strval, VK_CAPITAL);
698 EVCASE(strval, VK_KANA);
699 EVCASE(strval, VK_HANGUEL);
700 EVCASE(strval, VK_HANGUL);
701 EVCASE(strval, VK_IME_ON);
702 EVCASE(strval, VK_JUNJA);
703 EVCASE(strval, VK_FINAL);
704 EVCASE(strval, VK_HANJA);
705 EVCASE(strval, VK_KANJI);
706 EVCASE(strval, VK_HKTG);
707 EVCASE(strval, VK_IME_OFF);
708 EVCASE(strval, VK_ESCAPE);
709 EVCASE(strval, VK_CONVERT);
710 EVCASE(strval, VK_NONCONVERT);
711 EVCASE(strval, VK_ACCEPT);
712 EVCASE(strval, VK_MODECHANGE);
713 EVCASE(strval, VK_SPACE);
714 EVCASE(strval, VK_PRIOR);
715 EVCASE(strval, VK_NEXT);
716 EVCASE(strval, VK_END);
717 EVCASE(strval, VK_HOME);
718 EVCASE(strval, VK_LEFT);
719 EVCASE(strval, VK_UP);
720 EVCASE(strval, VK_RIGHT);
721 EVCASE(strval, VK_DOWN);
722 EVCASE(strval, VK_SELECT);
723 EVCASE(strval, VK_PRINT);
724 EVCASE(strval, VK_EXECUTE);
725 EVCASE(strval, VK_SNAPSHOT);
726 EVCASE(strval, VK_INSERT);
727 EVCASE(strval, VK_DELETE);
728 EVCASE(strval, VK_HELP);
729 EVCASE(strval, VK_KEY_0);
730 EVCASE(strval, VK_KEY_1);
731 EVCASE(strval, VK_KEY_2);
732 EVCASE(strval, VK_KEY_3);
733 EVCASE(strval, VK_KEY_4);
734 EVCASE(strval, VK_KEY_5);
735 EVCASE(strval, VK_KEY_6);
736 EVCASE(strval, VK_KEY_7);
737 EVCASE(strval, VK_KEY_8);
738 EVCASE(strval, VK_KEY_9);
739 EVCASE(strval, VK_KEY_A);
740 EVCASE(strval, VK_KEY_B);
741 EVCASE(strval, VK_KEY_C);
742 EVCASE(strval, VK_KEY_D);
743 EVCASE(strval, VK_KEY_E);
744 EVCASE(strval, VK_KEY_F);
745 EVCASE(strval, VK_KEY_G);
746 EVCASE(strval, VK_KEY_H);
747 EVCASE(strval, VK_KEY_I);
748 EVCASE(strval, VK_KEY_J);
749 EVCASE(strval, VK_KEY_K);
750 EVCASE(strval, VK_KEY_L);
751 EVCASE(strval, VK_KEY_M);
752 EVCASE(strval, VK_KEY_N);
753 EVCASE(strval, VK_KEY_O);
754 EVCASE(strval, VK_KEY_P);
755 EVCASE(strval, VK_KEY_Q);
756 EVCASE(strval, VK_KEY_R);
757 EVCASE(strval, VK_KEY_S);
758 EVCASE(strval, VK_KEY_T);
759 EVCASE(strval, VK_KEY_U);
760 EVCASE(strval, VK_KEY_V);
761 EVCASE(strval, VK_KEY_W);
762 EVCASE(strval, VK_KEY_X);
763 EVCASE(strval, VK_KEY_Y);
764 EVCASE(strval, VK_KEY_Z);
765 EVCASE(strval, VK_LWIN);
766 EVCASE(strval, VK_RWIN);
767 EVCASE(strval, VK_APPS);
768 EVCASE(strval, VK_POWER);
769 EVCASE(strval, VK_SLEEP);
770 EVCASE(strval, VK_NUMPAD0);
771 EVCASE(strval, VK_NUMPAD1);
772 EVCASE(strval, VK_NUMPAD2);
773 EVCASE(strval, VK_NUMPAD3);
774 EVCASE(strval, VK_NUMPAD4);
775 EVCASE(strval, VK_NUMPAD5);
776 EVCASE(strval, VK_NUMPAD6);
777 EVCASE(strval, VK_NUMPAD7);
778 EVCASE(strval, VK_NUMPAD8);
779 EVCASE(strval, VK_NUMPAD9);
780 EVCASE(strval, VK_MULTIPLY);
781 EVCASE(strval, VK_ADD);
782 EVCASE(strval, VK_SEPARATOR);
783 EVCASE(strval, VK_SUBTRACT);
784 EVCASE(strval, VK_DECIMAL);
785 EVCASE(strval, VK_DIVIDE);
786 EVCASE(strval, VK_F1);
787 EVCASE(strval, VK_F2);
788 EVCASE(strval, VK_F3);
789 EVCASE(strval, VK_F4);
790 EVCASE(strval, VK_F5);
791 EVCASE(strval, VK_F6);
792 EVCASE(strval, VK_F7);
793 EVCASE(strval, VK_F8);
794 EVCASE(strval, VK_F9);
795 EVCASE(strval, VK_F10);
796 EVCASE(strval, VK_F11);
797 EVCASE(strval, VK_F12);
798 EVCASE(strval, VK_F13);
799 EVCASE(strval, VK_F14);
800 EVCASE(strval, VK_F15);
801 EVCASE(strval, VK_F16);
802 EVCASE(strval, VK_F17);
803 EVCASE(strval, VK_F18);
804 EVCASE(strval, VK_F19);
805 EVCASE(strval, VK_F20);
806 EVCASE(strval, VK_F21);
807 EVCASE(strval, VK_F22);
808 EVCASE(strval, VK_F23);
809 EVCASE(strval, VK_F24);
810 EVCASE(strval, VK_NUMLOCK);
811 EVCASE(strval, VK_SCROLL);
812 EVCASE(strval, VK_LSHIFT);
813 EVCASE(strval, VK_RSHIFT);
814 EVCASE(strval, VK_LCONTROL);
815 EVCASE(strval, VK_RCONTROL);
816 EVCASE(strval, VK_LMENU);
817 EVCASE(strval, VK_RMENU);
818 EVCASE(strval, VK_BROWSER_BACK);
819 EVCASE(strval, VK_BROWSER_FORWARD);
820 EVCASE(strval, VK_BROWSER_REFRESH);
821 EVCASE(strval, VK_BROWSER_STOP);
822 EVCASE(strval, VK_BROWSER_SEARCH);
823 EVCASE(strval, VK_BROWSER_FAVORITES);
824 EVCASE(strval, VK_BROWSER_HOME);
825 EVCASE(strval, VK_VOLUME_MUTE);
826 EVCASE(strval, VK_VOLUME_DOWN);
827 EVCASE(strval, VK_VOLUME_UP);
828 EVCASE(strval, VK_MEDIA_NEXT_TRACK);
829 EVCASE(strval, VK_MEDIA_PREV_TRACK);
830 EVCASE(strval, VK_MEDIA_STOP);
831 EVCASE(strval, VK_MEDIA_PLAY_PAUSE);
832 EVCASE(strval, VK_LAUNCH_MAIL);
833 EVCASE(strval, VK_MEDIA_SELECT);
834 EVCASE(strval, VK_LAUNCH_MEDIA_SELECT);
835 EVCASE(strval, VK_LAUNCH_APP1);
836 EVCASE(strval, VK_LAUNCH_APP2);
837 EVCASE(strval, VK_OEM_1);
838 EVCASE(strval, VK_OEM_PLUS);
839 EVCASE(strval, VK_OEM_COMMA);
840 EVCASE(strval, VK_OEM_MINUS);
841 EVCASE(strval, VK_OEM_PERIOD);
842 EVCASE(strval, VK_OEM_2);
843 EVCASE(strval, VK_OEM_3);
844 EVCASE(strval, VK_ABNT_C1);
845 EVCASE(strval, VK_ABNT_C2);
846 EVCASE(strval, VK_OEM_4);
847 EVCASE(strval, VK_OEM_5);
848 EVCASE(strval, VK_OEM_6);
849 EVCASE(strval, VK_OEM_7);
850 EVCASE(strval, VK_OEM_8);
851 EVCASE(strval, VK_OEM_AX);
852 EVCASE(strval, VK_OEM_102);
853 EVCASE(strval, VK_PROCESSKEY);
854 EVCASE(strval, VK_PACKET);
855 EVCASE(strval, VK_OEM_RESET);
856 EVCASE(strval, VK_OEM_JUMP);
857 EVCASE(strval, VK_OEM_PA1);
858 EVCASE(strval, VK_OEM_PA2);
859 EVCASE(strval, VK_OEM_PA3);
860 EVCASE(strval, VK_OEM_WSCTRL);
861 EVCASE(strval, VK_OEM_CUSEL);
862 EVCASE(strval, VK_OEM_ATTN);
863 EVCASE(strval, VK_OEM_FINISH);
864 EVCASE(strval, VK_OEM_COPY);
865 EVCASE(strval, VK_OEM_AUTO);
866 EVCASE(strval, VK_OEM_ENLW);
867 EVCASE(strval, VK_OEM_BACKTAB);
868 EVCASE(strval, VK_ATTN);
869 EVCASE(strval, VK_CRSEL);
870 EVCASE(strval, VK_EXSEL);
871 EVCASE(strval, VK_EREOF);
872 EVCASE(strval, VK_PLAY);
873 EVCASE(strval, VK_ZOOM);
874 EVCASE(strval, VK_NONAME);
875 EVCASE(strval, VK_PA1);
876 EVCASE(strval, VK_OEM_CLEAR);
877 EVCASE(strval, VK_NONE);
878 EVCASE(strval, VK_DBE_ALPHANUMERIC);
879 EVCASE(strval, VK_DBE_KATAKANA);
880 EVCASE(strval, VK_DBE_HIRAGANA);
881 EVCASE(strval, VK_DBE_SBCSCHAR);
882 EVCASE(strval, VK_DBE_DBCSCHAR);
883 EVCASE(strval, VK_DBE_ROMAN);
884 EVCASE(strval, VK_DBE_NOROMAN);
885 EVCASE(strval, VK_DBE_ENTERWORDREGISTERMODE);
886 EVCASE(strval, VK_DBE_ENTERIMECONFIGMODE);
887 EVCASE(strval, VK_DBE_FLUSHSTRING);
888 EVCASE(strval, VK_DBE_CODEINPUT);
889 EVCASE(strval, VK_DBE_NOCODEINPUT);
891 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, unknown value '%s'",
892 KEYBOARD_CONFIG_FILE_NAME, section, pos, strval);
896static void loadKeyboardTypeArray(WINPR_JSON* json,
const char* section, DWORD* array,
size_t count)
898 WINPR_ASSERT(section);
902 WLog_WARN(TAG,
"[%s:%s] invalid section entry, NULL or not a JSON array",
903 KEYBOARD_CONFIG_FILE_NAME, section);
907 WINPR_ASSERT(array || (count == 0));
912 const DWORD val = VKStrToInteger(vk, x, section);
917static void loadKeyboardType(WINPR_JSON* json,
enum WINPR_KBD_TYPE type)
927 "[%s] configuration file, no entry for keyboard type '%s' or element not a JSON Object",
928 KEYBOARD_CONFIG_FILE_NAME, kbdTypeStr(type));
932 ScancodeToVKMap_t* cur = &VKmap[type - 1];
935 loadKeyboardTypeArray(multivk,
"multivk", cur->multivk, ARRAYSIZE(cur->multivk));
938 loadKeyboardTypeArray(kbdext,
"kbdext", cur->kbdext, ARRAYSIZE(cur->kbdext));
941 loadKeyboardTypeArray(normal,
"normal", cur->normal, ARRAYSIZE(cur->normal));
945static BOOL CALLBACK loadFromSettings(WINPR_ATTR_UNUSED
PINIT_ONCE InitOnce,
946 WINPR_ATTR_UNUSED PVOID Parameter,
947 WINPR_ATTR_UNUSED PVOID* Context)
949 WINPR_STATIC_ASSERT(ARRAYSIZE(VKmap) >= WINPR_KBD_TYPE_KOREAN);
951 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_IBM_PC_XT - 1];
953 WINPR_STATIC_ASSERT(
sizeof(KBD4X_1) ==
sizeof(cur->multivk));
954 WINPR_STATIC_ASSERT(
sizeof(KBD4X) ==
sizeof(cur->kbdext));
955 WINPR_STATIC_ASSERT(
sizeof(KBD4T) ==
sizeof(cur->normal));
956 WINPR_STATIC_ASSERT(
sizeof(ScancodeToVKMap_t) ==
sizeof(VKmap[0]));
958 memcpy(cur->multivk, KBD4X_1,
sizeof(KBD4X_1));
959 memcpy(cur->kbdext, KBD4X,
sizeof(KBD4X));
960 memcpy(cur->normal, KBD4T,
sizeof(KBD4T));
962 memcpy(&VKmap[WINPR_KBD_TYPE_OLIVETTI_ICO - 1], cur,
sizeof(ScancodeToVKMap_t));
963 memcpy(&VKmap[WINPR_KBD_TYPE_IBM_PC_AT - 1], cur,
sizeof(ScancodeToVKMap_t));
964 memcpy(&VKmap[WINPR_KBD_TYPE_IBM_ENHANCED - 1], cur,
sizeof(ScancodeToVKMap_t));
967 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_NOKIA_1050 - 1];
968 for (
size_t x = 0; x < ARRAYSIZE(cur->multivk); x++)
969 cur->multivk[x] = VK_NONE;
970 for (
size_t x = 0; x < ARRAYSIZE(cur->kbdext); x++)
971 cur->kbdext[x] = VK_NONE;
972 for (
size_t x = 0; x < ARRAYSIZE(cur->normal); x++)
973 cur->normal[x] = VK_NONE;
975 memcpy(&VKmap[WINPR_KBD_TYPE_NOKIA_9140 - 1], cur,
sizeof(ScancodeToVKMap_t));
978 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_JAPANESE - 1];
980 WINPR_STATIC_ASSERT(
sizeof(KBD7X_1) ==
sizeof(cur->multivk));
981 WINPR_STATIC_ASSERT(
sizeof(KBD7X) ==
sizeof(cur->kbdext));
982 WINPR_STATIC_ASSERT(
sizeof(KBD7T) ==
sizeof(cur->normal));
984 memcpy(cur->multivk, KBD7X_1,
sizeof(KBD7X_1));
985 memcpy(cur->kbdext, KBD7X,
sizeof(KBD7X));
986 memcpy(cur->normal, KBD7T,
sizeof(KBD7T));
989 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_KOREAN - 1];
991 WINPR_STATIC_ASSERT(
sizeof(KBD8X_1) ==
sizeof(cur->multivk));
992 WINPR_STATIC_ASSERT(
sizeof(KBD8X) ==
sizeof(cur->kbdext));
993 WINPR_STATIC_ASSERT(
sizeof(KBD8T) ==
sizeof(cur->normal));
995 memcpy(cur->multivk, KBD8X_1,
sizeof(KBD8X_1));
996 memcpy(cur->kbdext, KBD8X,
sizeof(KBD8X));
997 memcpy(cur->normal, KBD8T,
sizeof(KBD8T));
1000 char* filename = GetCombinedPath(WINPR_RESOURCE_ROOT, KEYBOARD_CONFIG_FILE_NAME);
1001 if (!filename || !winpr_PathFileExists(filename))
1003 WLog_DBG(TAG,
"[%s] configuration file does not exist at %s, skipping...",
1004 KEYBOARD_CONFIG_FILE_NAME, filename);
1013 "[%s] invalid JSON configuration at top level, element NULL or not a JSON Object",
1014 KEYBOARD_CONFIG_FILE_NAME);
1018 loadKeyboardType(json, WINPR_KBD_TYPE_IBM_PC_XT);
1019 loadKeyboardType(json, WINPR_KBD_TYPE_OLIVETTI_ICO);
1020 loadKeyboardType(json, WINPR_KBD_TYPE_IBM_PC_AT);
1021 loadKeyboardType(json, WINPR_KBD_TYPE_IBM_ENHANCED);
1022 loadKeyboardType(json, WINPR_KBD_TYPE_NOKIA_1050);
1023 loadKeyboardType(json, WINPR_KBD_TYPE_NOKIA_9140);
1024 loadKeyboardType(json, WINPR_KBD_TYPE_JAPANESE);
1025 loadKeyboardType(json, WINPR_KBD_TYPE_KOREAN);
1033 return InitOnceExecuteOnce(&VKmapInitialized, loadFromSettings,
nullptr,
nullptr);
1037static DWORD GetVirtualScanCodesFromVirtualKeyCodeMap(DWORD vkcode,
const ScancodeToVKMap_t* map,
1038 DWORD* pdwScanCodeBuffer,
1039 size_t ScanCodeBufferSize)
1042 DWORD codeIndex = vkcode & 0xFF;
1043 if (codeIndex == VK_NONE)
1046 if (vkcode & KBDMULTIVK)
1047 return get_scancodes(codeIndex, map->multivk, ARRAYSIZE(map->multivk), KBDMULTIVK,
1048 pdwScanCodeBuffer, ScanCodeBufferSize);
1049 if (vkcode & KBDEXT)
1050 return get_scancodes(codeIndex, map->kbdext, ARRAYSIZE(map->kbdext), KBDEXT,
1051 pdwScanCodeBuffer, ScanCodeBufferSize);
1053 return get_scancodes(codeIndex, map->normal, ARRAYSIZE(map->normal), 0, pdwScanCodeBuffer,
1054 ScanCodeBufferSize);
1057DWORD GetVirtualScanCodesFromVirtualKeyCode(DWORD vkcode, DWORD dwKeyboardType,
1058 DWORD* pdwScanCodeBuffer,
size_t ScanCodeBufferSize)
1063 switch (dwKeyboardType)
1065 case WINPR_KBD_TYPE_IBM_PC_XT:
1066 case WINPR_KBD_TYPE_OLIVETTI_ICO:
1067 case WINPR_KBD_TYPE_IBM_PC_AT:
1068 case WINPR_KBD_TYPE_IBM_ENHANCED:
1069 case WINPR_KBD_TYPE_JAPANESE:
1070 case WINPR_KBD_TYPE_KOREAN:
1071 case WINPR_KBD_TYPE_NOKIA_1050:
1072 case WINPR_KBD_TYPE_NOKIA_9140:
1073 return GetVirtualScanCodesFromVirtualKeyCodeMap(vkcode, &VKmap[dwKeyboardType - 1],
1074 pdwScanCodeBuffer, ScanCodeBufferSize);
1076 WLog_ERR(TAG,
"dwKeyboardType=0x%08" PRIx32
" not supported", dwKeyboardType);
WINPR_ATTR_NODISCARD WINPR_API BOOL WINPR_JSON_IsNumber(const WINPR_JSON *item)
Check if JSON item is of type Number.
WINPR_ATTR_NODISCARD WINPR_API size_t WINPR_JSON_GetArraySize(const WINPR_JSON *array)
Get the number of arrayitems from an array.
WINPR_API WINPR_JSON * WINPR_JSON_ParseFromFile(const char *filename)
Parse a JSON string read from a file filename.
WINPR_ATTR_NODISCARD WINPR_API WINPR_JSON * WINPR_JSON_GetObjectItemCaseSensitive(const WINPR_JSON *object, const char *string)
Same as WINPR_JSON_GetObjectItem but with case sensitive matching.
WINPR_ATTR_NODISCARD WINPR_API BOOL WINPR_JSON_IsString(const WINPR_JSON *item)
Check if JSON item is of type String.
WINPR_ATTR_NODISCARD WINPR_API WINPR_JSON * WINPR_JSON_GetArrayItem(const WINPR_JSON *array, size_t index)
Return a pointer to an item in the array.
WINPR_ATTR_NODISCARD WINPR_API double WINPR_JSON_GetNumberValue(const WINPR_JSON *item)
Return the Number value of a JSON item.
WINPR_ATTR_NODISCARD WINPR_API BOOL WINPR_JSON_IsArray(const WINPR_JSON *item)
Check if JSON item is of type Array.
WINPR_ATTR_NODISCARD WINPR_API BOOL WINPR_JSON_IsObject(const WINPR_JSON *item)
Check if JSON item is of type Object.
WINPR_API void WINPR_JSON_Delete(WINPR_JSON *item)
Delete a WinPR JSON wrapper object.
WINPR_ATTR_NODISCARD WINPR_API const char * WINPR_JSON_GetStringValue(WINPR_JSON *item)
Return the String value of a JSON item.