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