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];
536BOOL WinPR_IsKeyboardTypeSupported(DWORD dwKeyboardType)
538 switch (dwKeyboardType)
540 case WINPR_KBD_TYPE_IBM_PC_XT:
541 case WINPR_KBD_TYPE_OLIVETTI_ICO:
542 case WINPR_KBD_TYPE_IBM_PC_AT:
543 case WINPR_KBD_TYPE_IBM_ENHANCED:
544 case WINPR_KBD_TYPE_NOKIA_1050:
545 case WINPR_KBD_TYPE_NOKIA_9140:
546 case WINPR_KBD_TYPE_JAPANESE:
547 case WINPR_KBD_TYPE_KOREAN:
554DWORD GetVirtualKeyCodeFromVirtualScanCode(DWORD scancode, DWORD dwKeyboardType)
559 if (WinPR_IsKeyboardTypeSupported(dwKeyboardType))
560 return GetVirtualKeyCodeFromVirtualScanCodeMap(scancode, &VKmap[dwKeyboardType - 1]);
562 WLog_ERR(TAG,
"dwKeyboardType=0x%08" PRIx32
" not supported", dwKeyboardType);
567static DWORD get_scancode(
size_t offset, DWORD vkcode,
const DWORD* array,
size_t arraysize,
571 for (
size_t x = offset; x < arraysize; x++)
573 const DWORD cur = array[x];
576 const DWORD sc = WINPR_ASSERTING_INT_CAST(DWORD, x);
586static DWORD get_scancodes(DWORD vkcode,
const DWORD* array,
size_t arraysize, DWORD flag,
587 DWORD* pdwScanCodeBuffer,
size_t ScanCodeBufferSize)
594 const BOOL nobuffer = ScanCodeBufferSize == 0;
597 sc = get_scancode(offset, vkcode, array, arraysize, flag);
602 if (count < ScanCodeBufferSize)
603 pdwScanCodeBuffer[count] = sc;
606 offset = (sc & ~flag) + 1;
608 }
while ((sc != 0) && ((count < ScanCodeBufferSize) || nobuffer));
613DWORD GetVirtualScanCodeFromVirtualKeyCode(DWORD vkcode, DWORD dwKeyboardType)
615 DWORD scancodes[1] = WINPR_C_ARRAY_INIT;
616 const DWORD count = GetVirtualScanCodesFromVirtualKeyCode(vkcode, dwKeyboardType, scancodes,
617 ARRAYSIZE(scancodes));
624static const char* kbdTypeStr(
enum WINPR_KBD_TYPE type)
632 EVCASE(WINPR_KBD_TYPE_IBM_PC_XT);
633 EVCASE(WINPR_KBD_TYPE_OLIVETTI_ICO);
634 EVCASE(WINPR_KBD_TYPE_IBM_PC_AT);
635 EVCASE(WINPR_KBD_TYPE_IBM_ENHANCED);
636 EVCASE(WINPR_KBD_TYPE_NOKIA_1050);
637 EVCASE(WINPR_KBD_TYPE_NOKIA_9140);
638 EVCASE(WINPR_KBD_TYPE_JAPANESE);
639 EVCASE(WINPR_KBD_TYPE_KOREAN);
641 WLog_WARN(TAG,
"Unsupported WINPR_KBD_TYPE %08" PRIx32, type);
648static DWORD VKStrToInteger(WINPR_JSON* val,
size_t pos,
const char* section)
650 WINPR_ASSERT(section);
654 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, NULL value",
655 KEYBOARD_CONFIG_FILE_NAME, section, pos);
662 if (isnan(nr) || isinf(nr))
664 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, floating NaN/INF value %lf",
665 KEYBOARD_CONFIG_FILE_NAME, section, pos, nr);
670 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, negative value %lf",
671 KEYBOARD_CONFIG_FILE_NAME, section, pos, nr);
679 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, not a string value",
680 KEYBOARD_CONFIG_FILE_NAME, section, pos);
686#define EVCASE(str, x) \
687 if (strcmp(#x, str) == 0) \
690 EVCASE(strval, VK_LBUTTON);
691 EVCASE(strval, VK_RBUTTON);
692 EVCASE(strval, VK_CANCEL);
693 EVCASE(strval, VK_MBUTTON);
694 EVCASE(strval, VK_XBUTTON1);
695 EVCASE(strval, VK_XBUTTON2);
696 EVCASE(strval, VK_BACK);
697 EVCASE(strval, VK_TAB);
698 EVCASE(strval, VK_CLEAR);
699 EVCASE(strval, VK_RETURN);
700 EVCASE(strval, VK_SHIFT);
701 EVCASE(strval, VK_CONTROL);
702 EVCASE(strval, VK_MENU);
703 EVCASE(strval, VK_PAUSE);
704 EVCASE(strval, VK_CAPITAL);
705 EVCASE(strval, VK_KANA);
706 EVCASE(strval, VK_HANGUEL);
707 EVCASE(strval, VK_HANGUL);
708 EVCASE(strval, VK_IME_ON);
709 EVCASE(strval, VK_JUNJA);
710 EVCASE(strval, VK_FINAL);
711 EVCASE(strval, VK_HANJA);
712 EVCASE(strval, VK_KANJI);
713 EVCASE(strval, VK_HKTG);
714 EVCASE(strval, VK_IME_OFF);
715 EVCASE(strval, VK_ESCAPE);
716 EVCASE(strval, VK_CONVERT);
717 EVCASE(strval, VK_NONCONVERT);
718 EVCASE(strval, VK_ACCEPT);
719 EVCASE(strval, VK_MODECHANGE);
720 EVCASE(strval, VK_SPACE);
721 EVCASE(strval, VK_PRIOR);
722 EVCASE(strval, VK_NEXT);
723 EVCASE(strval, VK_END);
724 EVCASE(strval, VK_HOME);
725 EVCASE(strval, VK_LEFT);
726 EVCASE(strval, VK_UP);
727 EVCASE(strval, VK_RIGHT);
728 EVCASE(strval, VK_DOWN);
729 EVCASE(strval, VK_SELECT);
730 EVCASE(strval, VK_PRINT);
731 EVCASE(strval, VK_EXECUTE);
732 EVCASE(strval, VK_SNAPSHOT);
733 EVCASE(strval, VK_INSERT);
734 EVCASE(strval, VK_DELETE);
735 EVCASE(strval, VK_HELP);
736 EVCASE(strval, VK_KEY_0);
737 EVCASE(strval, VK_KEY_1);
738 EVCASE(strval, VK_KEY_2);
739 EVCASE(strval, VK_KEY_3);
740 EVCASE(strval, VK_KEY_4);
741 EVCASE(strval, VK_KEY_5);
742 EVCASE(strval, VK_KEY_6);
743 EVCASE(strval, VK_KEY_7);
744 EVCASE(strval, VK_KEY_8);
745 EVCASE(strval, VK_KEY_9);
746 EVCASE(strval, VK_KEY_A);
747 EVCASE(strval, VK_KEY_B);
748 EVCASE(strval, VK_KEY_C);
749 EVCASE(strval, VK_KEY_D);
750 EVCASE(strval, VK_KEY_E);
751 EVCASE(strval, VK_KEY_F);
752 EVCASE(strval, VK_KEY_G);
753 EVCASE(strval, VK_KEY_H);
754 EVCASE(strval, VK_KEY_I);
755 EVCASE(strval, VK_KEY_J);
756 EVCASE(strval, VK_KEY_K);
757 EVCASE(strval, VK_KEY_L);
758 EVCASE(strval, VK_KEY_M);
759 EVCASE(strval, VK_KEY_N);
760 EVCASE(strval, VK_KEY_O);
761 EVCASE(strval, VK_KEY_P);
762 EVCASE(strval, VK_KEY_Q);
763 EVCASE(strval, VK_KEY_R);
764 EVCASE(strval, VK_KEY_S);
765 EVCASE(strval, VK_KEY_T);
766 EVCASE(strval, VK_KEY_U);
767 EVCASE(strval, VK_KEY_V);
768 EVCASE(strval, VK_KEY_W);
769 EVCASE(strval, VK_KEY_X);
770 EVCASE(strval, VK_KEY_Y);
771 EVCASE(strval, VK_KEY_Z);
772 EVCASE(strval, VK_LWIN);
773 EVCASE(strval, VK_RWIN);
774 EVCASE(strval, VK_APPS);
775 EVCASE(strval, VK_POWER);
776 EVCASE(strval, VK_SLEEP);
777 EVCASE(strval, VK_NUMPAD0);
778 EVCASE(strval, VK_NUMPAD1);
779 EVCASE(strval, VK_NUMPAD2);
780 EVCASE(strval, VK_NUMPAD3);
781 EVCASE(strval, VK_NUMPAD4);
782 EVCASE(strval, VK_NUMPAD5);
783 EVCASE(strval, VK_NUMPAD6);
784 EVCASE(strval, VK_NUMPAD7);
785 EVCASE(strval, VK_NUMPAD8);
786 EVCASE(strval, VK_NUMPAD9);
787 EVCASE(strval, VK_MULTIPLY);
788 EVCASE(strval, VK_ADD);
789 EVCASE(strval, VK_SEPARATOR);
790 EVCASE(strval, VK_SUBTRACT);
791 EVCASE(strval, VK_DECIMAL);
792 EVCASE(strval, VK_DIVIDE);
793 EVCASE(strval, VK_F1);
794 EVCASE(strval, VK_F2);
795 EVCASE(strval, VK_F3);
796 EVCASE(strval, VK_F4);
797 EVCASE(strval, VK_F5);
798 EVCASE(strval, VK_F6);
799 EVCASE(strval, VK_F7);
800 EVCASE(strval, VK_F8);
801 EVCASE(strval, VK_F9);
802 EVCASE(strval, VK_F10);
803 EVCASE(strval, VK_F11);
804 EVCASE(strval, VK_F12);
805 EVCASE(strval, VK_F13);
806 EVCASE(strval, VK_F14);
807 EVCASE(strval, VK_F15);
808 EVCASE(strval, VK_F16);
809 EVCASE(strval, VK_F17);
810 EVCASE(strval, VK_F18);
811 EVCASE(strval, VK_F19);
812 EVCASE(strval, VK_F20);
813 EVCASE(strval, VK_F21);
814 EVCASE(strval, VK_F22);
815 EVCASE(strval, VK_F23);
816 EVCASE(strval, VK_F24);
817 EVCASE(strval, VK_NUMLOCK);
818 EVCASE(strval, VK_SCROLL);
819 EVCASE(strval, VK_LSHIFT);
820 EVCASE(strval, VK_RSHIFT);
821 EVCASE(strval, VK_LCONTROL);
822 EVCASE(strval, VK_RCONTROL);
823 EVCASE(strval, VK_LMENU);
824 EVCASE(strval, VK_RMENU);
825 EVCASE(strval, VK_BROWSER_BACK);
826 EVCASE(strval, VK_BROWSER_FORWARD);
827 EVCASE(strval, VK_BROWSER_REFRESH);
828 EVCASE(strval, VK_BROWSER_STOP);
829 EVCASE(strval, VK_BROWSER_SEARCH);
830 EVCASE(strval, VK_BROWSER_FAVORITES);
831 EVCASE(strval, VK_BROWSER_HOME);
832 EVCASE(strval, VK_VOLUME_MUTE);
833 EVCASE(strval, VK_VOLUME_DOWN);
834 EVCASE(strval, VK_VOLUME_UP);
835 EVCASE(strval, VK_MEDIA_NEXT_TRACK);
836 EVCASE(strval, VK_MEDIA_PREV_TRACK);
837 EVCASE(strval, VK_MEDIA_STOP);
838 EVCASE(strval, VK_MEDIA_PLAY_PAUSE);
839 EVCASE(strval, VK_LAUNCH_MAIL);
840 EVCASE(strval, VK_MEDIA_SELECT);
841 EVCASE(strval, VK_LAUNCH_MEDIA_SELECT);
842 EVCASE(strval, VK_LAUNCH_APP1);
843 EVCASE(strval, VK_LAUNCH_APP2);
844 EVCASE(strval, VK_OEM_1);
845 EVCASE(strval, VK_OEM_PLUS);
846 EVCASE(strval, VK_OEM_COMMA);
847 EVCASE(strval, VK_OEM_MINUS);
848 EVCASE(strval, VK_OEM_PERIOD);
849 EVCASE(strval, VK_OEM_2);
850 EVCASE(strval, VK_OEM_3);
851 EVCASE(strval, VK_ABNT_C1);
852 EVCASE(strval, VK_ABNT_C2);
853 EVCASE(strval, VK_OEM_4);
854 EVCASE(strval, VK_OEM_5);
855 EVCASE(strval, VK_OEM_6);
856 EVCASE(strval, VK_OEM_7);
857 EVCASE(strval, VK_OEM_8);
858 EVCASE(strval, VK_OEM_AX);
859 EVCASE(strval, VK_OEM_102);
860 EVCASE(strval, VK_PROCESSKEY);
861 EVCASE(strval, VK_PACKET);
862 EVCASE(strval, VK_OEM_RESET);
863 EVCASE(strval, VK_OEM_JUMP);
864 EVCASE(strval, VK_OEM_PA1);
865 EVCASE(strval, VK_OEM_PA2);
866 EVCASE(strval, VK_OEM_PA3);
867 EVCASE(strval, VK_OEM_WSCTRL);
868 EVCASE(strval, VK_OEM_CUSEL);
869 EVCASE(strval, VK_OEM_ATTN);
870 EVCASE(strval, VK_OEM_FINISH);
871 EVCASE(strval, VK_OEM_COPY);
872 EVCASE(strval, VK_OEM_AUTO);
873 EVCASE(strval, VK_OEM_ENLW);
874 EVCASE(strval, VK_OEM_BACKTAB);
875 EVCASE(strval, VK_ATTN);
876 EVCASE(strval, VK_CRSEL);
877 EVCASE(strval, VK_EXSEL);
878 EVCASE(strval, VK_EREOF);
879 EVCASE(strval, VK_PLAY);
880 EVCASE(strval, VK_ZOOM);
881 EVCASE(strval, VK_NONAME);
882 EVCASE(strval, VK_PA1);
883 EVCASE(strval, VK_OEM_CLEAR);
884 EVCASE(strval, VK_NONE);
885 EVCASE(strval, VK_DBE_ALPHANUMERIC);
886 EVCASE(strval, VK_DBE_KATAKANA);
887 EVCASE(strval, VK_DBE_HIRAGANA);
888 EVCASE(strval, VK_DBE_SBCSCHAR);
889 EVCASE(strval, VK_DBE_DBCSCHAR);
890 EVCASE(strval, VK_DBE_ROMAN);
891 EVCASE(strval, VK_DBE_NOROMAN);
892 EVCASE(strval, VK_DBE_ENTERWORDREGISTERMODE);
893 EVCASE(strval, VK_DBE_ENTERIMECONFIGMODE);
894 EVCASE(strval, VK_DBE_FLUSHSTRING);
895 EVCASE(strval, VK_DBE_CODEINPUT);
896 EVCASE(strval, VK_DBE_NOCODEINPUT);
898 WLog_WARN(TAG,
"[%s:%s at %" PRIuz
"] invalid array entry, unknown value '%s'",
899 KEYBOARD_CONFIG_FILE_NAME, section, pos, strval);
903static void loadKeyboardTypeArray(WINPR_JSON* json,
const char* section, DWORD* array,
size_t count)
905 WINPR_ASSERT(section);
909 WLog_WARN(TAG,
"[%s:%s] invalid section entry, NULL or not a JSON array",
910 KEYBOARD_CONFIG_FILE_NAME, section);
914 WINPR_ASSERT(array || (count == 0));
919 const DWORD val = VKStrToInteger(vk, x, section);
924static void loadKeyboardType(WINPR_JSON* json,
enum WINPR_KBD_TYPE type)
934 "[%s] configuration file, no entry for keyboard type '%s' or element not a JSON Object",
935 KEYBOARD_CONFIG_FILE_NAME, kbdTypeStr(type));
939 ScancodeToVKMap_t* cur = &VKmap[type - 1];
942 loadKeyboardTypeArray(multivk,
"multivk", cur->multivk, ARRAYSIZE(cur->multivk));
945 loadKeyboardTypeArray(kbdext,
"kbdext", cur->kbdext, ARRAYSIZE(cur->kbdext));
948 loadKeyboardTypeArray(normal,
"normal", cur->normal, ARRAYSIZE(cur->normal));
952static BOOL CALLBACK loadFromSettings(WINPR_ATTR_UNUSED
PINIT_ONCE InitOnce,
953 WINPR_ATTR_UNUSED PVOID Parameter,
954 WINPR_ATTR_UNUSED PVOID* Context)
956 WINPR_STATIC_ASSERT(ARRAYSIZE(VKmap) >= WINPR_KBD_TYPE_KOREAN);
958 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_IBM_PC_XT - 1];
960 WINPR_STATIC_ASSERT(
sizeof(KBD4X_1) ==
sizeof(cur->multivk));
961 WINPR_STATIC_ASSERT(
sizeof(KBD4X) ==
sizeof(cur->kbdext));
962 WINPR_STATIC_ASSERT(
sizeof(KBD4T) ==
sizeof(cur->normal));
963 WINPR_STATIC_ASSERT(
sizeof(ScancodeToVKMap_t) ==
sizeof(VKmap[0]));
965 memcpy(cur->multivk, KBD4X_1,
sizeof(KBD4X_1));
966 memcpy(cur->kbdext, KBD4X,
sizeof(KBD4X));
967 memcpy(cur->normal, KBD4T,
sizeof(KBD4T));
969 memcpy(&VKmap[WINPR_KBD_TYPE_OLIVETTI_ICO - 1], cur,
sizeof(ScancodeToVKMap_t));
970 memcpy(&VKmap[WINPR_KBD_TYPE_IBM_PC_AT - 1], cur,
sizeof(ScancodeToVKMap_t));
971 memcpy(&VKmap[WINPR_KBD_TYPE_IBM_ENHANCED - 1], cur,
sizeof(ScancodeToVKMap_t));
974 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_NOKIA_1050 - 1];
975 for (
size_t x = 0; x < ARRAYSIZE(cur->multivk); x++)
976 cur->multivk[x] = VK_NONE;
977 for (
size_t x = 0; x < ARRAYSIZE(cur->kbdext); x++)
978 cur->kbdext[x] = VK_NONE;
979 for (
size_t x = 0; x < ARRAYSIZE(cur->normal); x++)
980 cur->normal[x] = VK_NONE;
982 memcpy(&VKmap[WINPR_KBD_TYPE_NOKIA_9140 - 1], cur,
sizeof(ScancodeToVKMap_t));
985 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_JAPANESE - 1];
987 WINPR_STATIC_ASSERT(
sizeof(KBD7X_1) ==
sizeof(cur->multivk));
988 WINPR_STATIC_ASSERT(
sizeof(KBD7X) ==
sizeof(cur->kbdext));
989 WINPR_STATIC_ASSERT(
sizeof(KBD7T) ==
sizeof(cur->normal));
991 memcpy(cur->multivk, KBD7X_1,
sizeof(KBD7X_1));
992 memcpy(cur->kbdext, KBD7X,
sizeof(KBD7X));
993 memcpy(cur->normal, KBD7T,
sizeof(KBD7T));
996 ScancodeToVKMap_t* cur = &VKmap[WINPR_KBD_TYPE_KOREAN - 1];
998 WINPR_STATIC_ASSERT(
sizeof(KBD8X_1) ==
sizeof(cur->multivk));
999 WINPR_STATIC_ASSERT(
sizeof(KBD8X) ==
sizeof(cur->kbdext));
1000 WINPR_STATIC_ASSERT(
sizeof(KBD8T) ==
sizeof(cur->normal));
1002 memcpy(cur->multivk, KBD8X_1,
sizeof(KBD8X_1));
1003 memcpy(cur->kbdext, KBD8X,
sizeof(KBD8X));
1004 memcpy(cur->normal, KBD8T,
sizeof(KBD8T));
1007 char* filename = GetCombinedPath(WINPR_RESOURCE_ROOT, KEYBOARD_CONFIG_FILE_NAME);
1008 if (!filename || !winpr_PathFileExists(filename))
1010 WLog_DBG(TAG,
"[%s] configuration file does not exist at %s, skipping...",
1011 KEYBOARD_CONFIG_FILE_NAME, filename);
1020 "[%s] invalid JSON configuration at top level, element NULL or not a JSON Object",
1021 KEYBOARD_CONFIG_FILE_NAME);
1025 loadKeyboardType(json, WINPR_KBD_TYPE_IBM_PC_XT);
1026 loadKeyboardType(json, WINPR_KBD_TYPE_OLIVETTI_ICO);
1027 loadKeyboardType(json, WINPR_KBD_TYPE_IBM_PC_AT);
1028 loadKeyboardType(json, WINPR_KBD_TYPE_IBM_ENHANCED);
1029 loadKeyboardType(json, WINPR_KBD_TYPE_NOKIA_1050);
1030 loadKeyboardType(json, WINPR_KBD_TYPE_NOKIA_9140);
1031 loadKeyboardType(json, WINPR_KBD_TYPE_JAPANESE);
1032 loadKeyboardType(json, WINPR_KBD_TYPE_KOREAN);
1040 return InitOnceExecuteOnce(&VKmapInitialized, loadFromSettings,
nullptr,
nullptr);
1044static DWORD GetVirtualScanCodesFromVirtualKeyCodeMap(DWORD vkcode,
const ScancodeToVKMap_t* map,
1045 DWORD* pdwScanCodeBuffer,
1046 size_t ScanCodeBufferSize)
1049 DWORD codeIndex = vkcode & 0xFF;
1050 if (codeIndex == VK_NONE)
1053 if (vkcode & KBDMULTIVK)
1054 return get_scancodes(codeIndex, map->multivk, ARRAYSIZE(map->multivk), KBDMULTIVK,
1055 pdwScanCodeBuffer, ScanCodeBufferSize);
1056 if (vkcode & KBDEXT)
1057 return get_scancodes(codeIndex, map->kbdext, ARRAYSIZE(map->kbdext), KBDEXT,
1058 pdwScanCodeBuffer, ScanCodeBufferSize);
1060 return get_scancodes(codeIndex, map->normal, ARRAYSIZE(map->normal), 0, pdwScanCodeBuffer,
1061 ScanCodeBufferSize);
1064DWORD GetVirtualScanCodesFromVirtualKeyCode(DWORD vkcode, DWORD dwKeyboardType,
1065 DWORD* pdwScanCodeBuffer,
size_t ScanCodeBufferSize)
1070 switch (dwKeyboardType)
1072 case WINPR_KBD_TYPE_IBM_PC_XT:
1073 case WINPR_KBD_TYPE_OLIVETTI_ICO:
1074 case WINPR_KBD_TYPE_IBM_PC_AT:
1075 case WINPR_KBD_TYPE_IBM_ENHANCED:
1076 case WINPR_KBD_TYPE_JAPANESE:
1077 case WINPR_KBD_TYPE_KOREAN:
1078 case WINPR_KBD_TYPE_NOKIA_1050:
1079 case WINPR_KBD_TYPE_NOKIA_9140:
1080 return GetVirtualScanCodesFromVirtualKeyCodeMap(vkcode, &VKmap[dwKeyboardType - 1],
1081 pdwScanCodeBuffer, ScanCodeBufferSize);
1083 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.