FreeRDP
Loading...
Searching...
No Matches
TestLocaleKeyboard.c
1#include <stdio.h>
2#include <winpr/crypto.h>
3#include <freerdp/config.h>
4#include <freerdp/locale/keyboard.h>
5
6static BOOL test_scancode_name(void)
7{
8 const DWORD scancodes[] = { RDP_SCANCODE_ESCAPE,
9 RDP_SCANCODE_KEY_1,
10 RDP_SCANCODE_KEY_2,
11 RDP_SCANCODE_KEY_3,
12 RDP_SCANCODE_KEY_4,
13 RDP_SCANCODE_KEY_5,
14 RDP_SCANCODE_KEY_6,
15 RDP_SCANCODE_KEY_7,
16 RDP_SCANCODE_KEY_8,
17 RDP_SCANCODE_KEY_9,
18 RDP_SCANCODE_KEY_0,
19 RDP_SCANCODE_OEM_MINUS,
20 RDP_SCANCODE_OEM_PLUS,
21 RDP_SCANCODE_BACKSPACE,
22 RDP_SCANCODE_TAB,
23 RDP_SCANCODE_KEY_Q,
24 RDP_SCANCODE_KEY_W,
25 RDP_SCANCODE_KEY_E,
26 RDP_SCANCODE_KEY_R,
27 RDP_SCANCODE_KEY_T,
28 RDP_SCANCODE_KEY_Y,
29 RDP_SCANCODE_KEY_U,
30 RDP_SCANCODE_KEY_I,
31 RDP_SCANCODE_KEY_O,
32 RDP_SCANCODE_KEY_P,
33 RDP_SCANCODE_OEM_4,
34 RDP_SCANCODE_OEM_6,
35 RDP_SCANCODE_RETURN,
36 RDP_SCANCODE_LCONTROL,
37 RDP_SCANCODE_KEY_A,
38 RDP_SCANCODE_KEY_S,
39 RDP_SCANCODE_KEY_D,
40 RDP_SCANCODE_KEY_F,
41 RDP_SCANCODE_KEY_G,
42 RDP_SCANCODE_KEY_H,
43 RDP_SCANCODE_KEY_J,
44 RDP_SCANCODE_KEY_K,
45 RDP_SCANCODE_KEY_L,
46 RDP_SCANCODE_OEM_1,
47 RDP_SCANCODE_OEM_7,
48 RDP_SCANCODE_OEM_3,
49 RDP_SCANCODE_LSHIFT,
50 RDP_SCANCODE_OEM_5,
51 RDP_SCANCODE_KEY_Z,
52 RDP_SCANCODE_KEY_X,
53 RDP_SCANCODE_KEY_C,
54 RDP_SCANCODE_KEY_V,
55 RDP_SCANCODE_KEY_B,
56 RDP_SCANCODE_KEY_N,
57 RDP_SCANCODE_KEY_M,
58 RDP_SCANCODE_OEM_COMMA,
59 RDP_SCANCODE_OEM_PERIOD,
60 RDP_SCANCODE_OEM_2,
61 RDP_SCANCODE_RSHIFT,
62 RDP_SCANCODE_MULTIPLY,
63 RDP_SCANCODE_LMENU,
64 RDP_SCANCODE_SPACE,
65 RDP_SCANCODE_CAPSLOCK,
66 RDP_SCANCODE_F1,
67 RDP_SCANCODE_F2,
68 RDP_SCANCODE_F3,
69 RDP_SCANCODE_F4,
70 RDP_SCANCODE_F5,
71 RDP_SCANCODE_F6,
72 RDP_SCANCODE_F7,
73 RDP_SCANCODE_F8,
74 RDP_SCANCODE_F9,
75 RDP_SCANCODE_F10,
76 RDP_SCANCODE_NUMLOCK,
77 RDP_SCANCODE_SCROLLLOCK,
78 RDP_SCANCODE_NUMPAD7,
79 RDP_SCANCODE_NUMPAD8,
80 RDP_SCANCODE_NUMPAD9,
81 RDP_SCANCODE_SUBTRACT,
82 RDP_SCANCODE_NUMPAD4,
83 RDP_SCANCODE_NUMPAD5,
84 RDP_SCANCODE_NUMPAD6,
85 RDP_SCANCODE_ADD,
86 RDP_SCANCODE_NUMPAD1,
87 RDP_SCANCODE_NUMPAD2,
88 RDP_SCANCODE_NUMPAD3,
89 RDP_SCANCODE_NUMPAD0,
90 RDP_SCANCODE_DECIMAL,
91 RDP_SCANCODE_SYSREQ,
92 RDP_SCANCODE_OEM_102,
93 RDP_SCANCODE_F11,
94 RDP_SCANCODE_F12,
95 RDP_SCANCODE_SLEEP,
96 RDP_SCANCODE_ZOOM,
97 RDP_SCANCODE_HELP,
98 RDP_SCANCODE_F13,
99 RDP_SCANCODE_F14,
100 RDP_SCANCODE_F15,
101 RDP_SCANCODE_F16,
102 RDP_SCANCODE_F17,
103 RDP_SCANCODE_F18,
104 RDP_SCANCODE_F19,
105 RDP_SCANCODE_F20,
106 RDP_SCANCODE_F21,
107 RDP_SCANCODE_F22,
108 RDP_SCANCODE_F23,
109 RDP_SCANCODE_F24,
110 RDP_SCANCODE_HIRAGANA,
111 RDP_SCANCODE_HANJA_KANJI,
112 RDP_SCANCODE_KANA_HANGUL,
113 RDP_SCANCODE_ABNT_C1,
114 RDP_SCANCODE_F24_JP,
115 RDP_SCANCODE_CONVERT_JP,
116 RDP_SCANCODE_NONCONVERT_JP,
117 RDP_SCANCODE_TAB_JP,
118 RDP_SCANCODE_BACKSLASH_JP,
119 RDP_SCANCODE_ABNT_C2,
120 RDP_SCANCODE_HANJA,
121 RDP_SCANCODE_HANGUL,
122 RDP_SCANCODE_RETURN_KP,
123 RDP_SCANCODE_RCONTROL,
124 RDP_SCANCODE_DIVIDE,
125 RDP_SCANCODE_PRINTSCREEN,
126 RDP_SCANCODE_RMENU,
127 RDP_SCANCODE_PAUSE,
128 RDP_SCANCODE_HOME,
129 RDP_SCANCODE_UP,
130 RDP_SCANCODE_PRIOR,
131 RDP_SCANCODE_LEFT,
132 RDP_SCANCODE_RIGHT,
133 RDP_SCANCODE_END,
134 RDP_SCANCODE_DOWN,
135 RDP_SCANCODE_NEXT,
136 RDP_SCANCODE_INSERT,
137 RDP_SCANCODE_DELETE,
138 RDP_SCANCODE_NULL,
139 RDP_SCANCODE_HELP2,
140 RDP_SCANCODE_LWIN,
141 RDP_SCANCODE_RWIN,
142 RDP_SCANCODE_APPS,
143 RDP_SCANCODE_POWER_JP,
144 RDP_SCANCODE_SLEEP_JP,
145 RDP_SCANCODE_NUMLOCK_EXTENDED,
146 RDP_SCANCODE_RSHIFT_EXTENDED,
147 RDP_SCANCODE_VOLUME_MUTE,
148 RDP_SCANCODE_VOLUME_DOWN,
149 RDP_SCANCODE_VOLUME_UP,
150 RDP_SCANCODE_MEDIA_NEXT_TRACK,
151 RDP_SCANCODE_MEDIA_PREV_TRACK,
152 RDP_SCANCODE_MEDIA_STOP,
153 RDP_SCANCODE_MEDIA_PLAY_PAUSE,
154 RDP_SCANCODE_BROWSER_BACK,
155 RDP_SCANCODE_BROWSER_FORWARD,
156 RDP_SCANCODE_BROWSER_REFRESH,
157 RDP_SCANCODE_BROWSER_STOP,
158 RDP_SCANCODE_BROWSER_SEARCH,
159 RDP_SCANCODE_BROWSER_FAVORITES,
160 RDP_SCANCODE_BROWSER_HOME,
161 RDP_SCANCODE_LAUNCH_MAIL,
162 RDP_SCANCODE_LAUNCH_MEDIA_SELECT,
163 RDP_SCANCODE_LAUNCH_APP1,
164 RDP_SCANCODE_LAUNCH_APP2 };
165 for (size_t x = 0; x < ARRAYSIZE(scancodes); x++)
166 {
167 const DWORD code = scancodes[x];
168 const char* sc = freerdp_keyboard_scancode_name(code);
169 if (!sc)
170 {
171 (void)fprintf(stderr, "Failed to run freerdp_keyboard_scancode_name(%" PRIu32 ")\n",
172 code);
173 return FALSE;
174 }
175 }
176
177 return TRUE;
178}
179
180static BOOL test_layouts(DWORD types)
181{
182 BOOL rc = FALSE;
183 size_t count = 0;
184 RDP_KEYBOARD_LAYOUT* layouts = freerdp_keyboard_get_layouts(types, &count);
185 if (!layouts || (count == 0))
186 {
187 (void)fprintf(stderr,
188 "freerdp_keyboard_get_layouts(type: %" PRIu32 ") -> %" PRIuz
189 " elements, layouts: %p:\n",
190 types, count, layouts);
191 goto fail;
192 }
193
194 for (size_t x = 0; x < count; x++)
195 {
196 const RDP_KEYBOARD_LAYOUT* cur = &layouts[x];
197 if ((cur->code == 0) || (!cur->name) || (strnlen(cur->name, 2) == 0))
198 {
199 (void)fprintf(stderr,
200 "freerdp_keyboard_get_layouts(type: %" PRIu32 ") -> %" PRIuz
201 " elements, failed:\n",
202 types, count);
203 (void)fprintf(stderr, "[%" PRIuz "]: code= %" PRIu32 ", name = %s\n", x, cur->code,
204 cur->name);
205 goto fail;
206 }
207
208 const char* name = freerdp_keyboard_get_layout_name_from_id(cur->code);
209 if (!name)
210 {
211 (void)fprintf(stderr,
212 "freerdp_keyboard_get_layouts(type: %" PRIu32 ") -> %" PRIuz
213 " elements, failed:\n",
214 types, count);
215 (void)fprintf(stderr,
216 "[%" PRIuz "]: freerdp_keyboard_get_layouts(%" PRIu32 ") -> nullptr\n", x,
217 cur->code);
218 goto fail;
219 }
220
221 const DWORD id = freerdp_keyboard_get_layout_id_from_name(cur->name);
222 if (id != cur->code)
223 {
224 (void)fprintf(stderr,
225 "freerdp_keyboard_get_layouts(type: %" PRIu32 ") -> %" PRIuz
226 " elements, failed:\n",
227 types, count);
228 (void)fprintf(stderr,
229 "[%" PRIuz "]: freerdp_keyboard_get_layout_id_from_name(%s) -> %" PRIu32
230 " != %" PRIu32 "\n",
231 x, cur->name, id, cur->code);
232 goto fail;
233 }
234 }
235
236 rc = TRUE;
237fail:
238 freerdp_keyboard_layouts_free(layouts, count);
239 return rc;
240}
241
242/* Keyboard identifiers from https://learn.microsoft.com/globalization/windows-keyboard-layouts */
243static BOOL test_layout_ids(void)
244{
245 const struct
246 {
247 const char* name;
248 DWORD code;
249 } layouts[] = { { "Persian", 0x00000429 }, { "Central Kurdish", 0x00000492 },
250 { "Latvian", 0x00000426 }, { "Latvian (Standard)", 0x00020426 },
251 { "Greek (220)", 0x00010408 }, { "Uyghur", 0x00010480 } };
252
253 for (size_t x = 0; x < ARRAYSIZE(layouts); x++)
254 {
255 const DWORD id = freerdp_keyboard_get_layout_id_from_name(layouts[x].name);
256 if (id != layouts[x].code)
257 {
258 (void)fprintf(stderr,
259 "freerdp_keyboard_get_layout_id_from_name(%s) -> 0x%08" PRIx32
260 " != 0x%08" PRIx32 "\n",
261 layouts[x].name, id, layouts[x].code);
262 return FALSE;
263 }
264 }
265 return TRUE;
266}
267
268static DWORD get_random(DWORD offset)
269{
270 DWORD x = 0;
271 if (winpr_RAND(&x, sizeof(x)) < 0)
272 {
273 (void)fprintf(stderr, "winpr_RAND failed, retry...\n");
274 // NOLINTNEXTLINE(concurrency-mt-unsafe)
275 exit(-1);
276 }
277 x = x % UINT32_MAX - offset;
278 x += offset;
279 return x;
280}
281
282#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
283static BOOL test_scancode_cnv(void)
284{
285 for (DWORD x = 0; x < UINT8_MAX; x++)
286 {
287 const DWORD sc = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(x);
288 const BOOL ex = RDP_SCANCODE_EXTENDED(sc);
289 const DWORD kk = freerdp_keyboard_get_x11_keycode_from_rdp_scancode(sc, ex);
290 if (sc != kk)
291 {
292 (void)fprintf(stderr,
293 "[%" PRIu32 "]: keycode->scancode->keycode failed: %" PRIu32
294 " -> %" PRIu32 " -> %" PRIu32 "\n",
295 x, sc, ex, kk);
296 return FALSE;
297 }
298 }
299
300 for (DWORD x = 0; x < 23; x++)
301 {
302 DWORD x = get_random(UINT8_MAX);
303
304 const DWORD sc = freerdp_keyboard_get_rdp_scancode_from_x11_keycode(x);
305 const DWORD kk = freerdp_keyboard_get_x11_keycode_from_rdp_scancode(sc, FALSE);
306 const DWORD kkex = freerdp_keyboard_get_x11_keycode_from_rdp_scancode(sc, TRUE);
307 if ((sc != 0) || (kk != 0) || (kkex != 0))
308 {
309 (void)fprintf(stderr,
310 "[%" PRIu32 "]: invalid scancode %" PRIu32 ", keycode %" PRIu32
311 " or keycode extended %" PRIu32 " has a value != 0\n",
312 x, sc, kk, kkex);
313 return FALSE;
314 }
315 }
316 return TRUE;
317}
318#endif
319
320static BOOL test_codepages(void)
321{
322
323 for (DWORD column = 0; column < 4; column++)
324 {
325 size_t count = 0;
326 RDP_CODEPAGE* cp = freerdp_keyboard_get_matching_codepages(column, nullptr, &count);
327 if (!cp || (count == 0))
328 {
329 (void)fprintf(stderr,
330 "freerdp_keyboard_get_matching_codepages(%" PRIu32 ", nullptr) failed!\n",
331 column);
332 return FALSE;
333 }
334 freerdp_codepages_free(cp);
335 }
336
337 for (DWORD x = 0; x < 23; x++)
338 {
339 DWORD column = get_random(4);
340 size_t count = 0;
341 RDP_CODEPAGE* cp = freerdp_keyboard_get_matching_codepages(column, nullptr, &count);
342 freerdp_codepages_free(cp);
343 if (cp || (count != 0))
344 {
345 (void)fprintf(stderr,
346 "freerdp_keyboard_get_matching_codepages(%" PRIu32
347 ", nullptr) returned not nullptr!\n",
348 column);
349 return FALSE;
350 }
351 }
352
353 // TODO: Test with filters set
354 // TODO: Test with invalid filters set
355
356 return TRUE;
357}
358
359static BOOL test_init(void)
360{
361#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
362 const DWORD kbd = freerdp_keyboard_init(0);
363 if (kbd == 0)
364 {
365 (void)fprintf(stderr, "freerdp_keyboard_init(0) returned invalid layout 0\n");
366 return FALSE;
367 }
368
369 const DWORD kbdex = freerdp_keyboard_init_ex(0, nullptr);
370 if (kbd == 0)
371 {
372 (void)fprintf(stderr, "freerdp_keyboard_init_ex(0, nullptr) returned invalid layout 0\n");
373 return FALSE;
374 }
375
376 if (kbd != kbdex)
377 {
378 (void)fprintf(
379 stderr,
380 "freerdp_keyboard_init(0) != freerdp_keyboard_init_ex(0, nullptr): returned %" PRIu32
381 " vs %" PRIu32 "\n",
382 kbd, kbdex);
383 return FALSE;
384 }
385
386 // TODO: Test with valid remap list
387 // TODO: Test with invalid remap list
388 // TODO: Test with defaults != 0
389#endif
390 return TRUE;
391}
392
393int TestLocaleKeyboard(int argc, char* argv[])
394{
395 WINPR_UNUSED(argc);
396 WINPR_UNUSED(argv);
397
398 if (!test_scancode_name())
399 return -1;
400
401 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD))
402 return -1;
403 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_VARIANT))
404 return -1;
405 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_IME))
406 return -1;
407 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD | RDP_KEYBOARD_LAYOUT_TYPE_VARIANT))
408 return -1;
409 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD | RDP_KEYBOARD_LAYOUT_TYPE_IME))
410 return -1;
411 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_VARIANT | RDP_KEYBOARD_LAYOUT_TYPE_IME))
412 return -1;
413 if (!test_layouts(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD | RDP_KEYBOARD_LAYOUT_TYPE_VARIANT |
414 RDP_KEYBOARD_LAYOUT_TYPE_IME))
415 return -1;
416 if (!test_layout_ids())
417 return -1;
418 if (test_layouts(UINT32_MAX &
419 ~(RDP_KEYBOARD_LAYOUT_TYPE_STANDARD | RDP_KEYBOARD_LAYOUT_TYPE_VARIANT |
420 RDP_KEYBOARD_LAYOUT_TYPE_IME)))
421 return -1;
422#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
423 if (!test_scancode_cnv())
424 return -1;
425#endif
426 if (!test_codepages())
427 return -1;
428 if (!test_init())
429 return -1;
430
431 return 0;
432}