From b0cfc1a12bd2bb18c1e2961372545a31fc723116 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Mon, 15 Apr 2024 17:14:31 +0100 Subject: [PATCH] Add initial scancode module --- common/Makefile.am | 2 + common/scancode.c | 421 ++++++++++++++++++++++++++++++++ common/scancode.h | 87 +++++++ tests/common/Makefile.am | 3 +- tests/common/test_common.h | 1 + tests/common/test_common_main.c | 1 + tests/common/test_scancode.c | 128 ++++++++++ 7 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 common/scancode.c create mode 100644 common/scancode.h create mode 100644 tests/common/test_scancode.c diff --git a/common/Makefile.am b/common/Makefile.am index 141addc8..fd30ae00 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -59,6 +59,8 @@ libcommon_la_SOURCES = \ parse.c \ parse.h \ rail.h \ + scancode.c \ + scancode.h \ ssl_calls.c \ ssl_calls.h \ string_calls.c \ diff --git a/common/scancode.c b/common/scancode.c new file mode 100644 index 00000000..c7225ba6 --- /dev/null +++ b/common/scancode.c @@ -0,0 +1,421 @@ +/** + * Copyright (C) 2022 Matt Burt, all xrdp contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * @file common/scancode.c + * @brief Scancode handling + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif +#include +#include + +#include "scancode.h" + +struct scancode_to_keycode +{ + unsigned short scancode; // 0x1xx implies an extended key + unsigned char keycode; +}; + +#define ELEMENTS(x) (sizeof(x) / sizeof(x[0])) + +// Sources:- +// file:/usr/share/X11/xkb/keycodes/evdev +// https://wiki.osdev.org/PS/2_Keyboard +// https://www.kbdlayout.info/ +static const struct scancode_to_keycode + evdev_scancode_to_keycode_map[] = +{ + // Virtual XKB + // Key (US) Symbol + // -------- ------ + { 0x001, 9 }, // VK_ESCAPE ESC + { 0x002, 10 }, // VK_1 AE01 + { 0x003, 11 }, // VK_2 AE02 + { 0x004, 12 }, // VK_3 AE03 + { 0x005, 13 }, // VK_4 AE04 + { 0x006, 14 }, // VK_5 AE05 + { 0x007, 15 }, // VK_6 AE06 + { 0x008, 16 }, // VK_7 AE07 + { 0x009, 17 }, // VK_8 AE08 + { 0x00a, 18 }, // VK_9 AE09 + { 0x00b, 19 }, // VK_0 AE10 + { 0x00c, 20 }, // VK_OEM_MINUS AE11 + { 0x00d, 21 }, // VK_OEM_PLUS AE12 + { 0x00e, 22 }, // VK_BACK BKSP + { 0x00f, 23 }, // VK_TAB TAB + { 0x010, 24 }, // VK_Q AD01 + { 0x011, 25 }, // VK_W AD02 + { 0x012, 26 }, // VK_E AD03 + { 0x013, 27 }, // VK_R AD04 + { 0x014, 28 }, // VK_T AD05 + { 0x015, 29 }, // VK_Y AD06 + { 0x016, 30 }, // VK_U AD07 + { 0x017, 31 }, // VK_I AD08 + { 0x018, 32 }, // VK_O AD09 + { 0x019, 33 }, // VK_P AD10 + { 0x01a, 34 }, // VK_OEM_4 AD11 + { 0x01b, 35 }, // VK_OEM_6 AD12 + { 0x01c, 36 }, // VK_RETURN RTRN + { 0x01d, 37 }, // VK_LCONTROL LCTL + { 0x01e, 38 }, // VK_A AC01 + { 0x01f, 39 }, // VK_S AC02 + { 0x020, 40 }, // VK_D AC03 + { 0x021, 41 }, // VK_F AC04 + { 0x022, 42 }, // VK_G AC05 + { 0x023, 43 }, // VK_H AC06 + { 0x024, 44 }, // VK_J AC07 + { 0x025, 45 }, // VK_K AC08 + { 0x026, 46 }, // VK_L AC09 + { 0x027, 47 }, // VK_OEM_1 AC10 + { 0x028, 48 }, // VK_OEM_7 AC11 + { 0x029, 49 }, // VK_OEM_3 TLDE + { 0x02a, 50 }, // VK_LSHIFT LFSH + { 0x02b, 51 }, // VK_OEM_5 BKSL + { 0x02c, 52 }, // VK_Z AB01 + { 0x02d, 53 }, // VK_X AB02 + { 0x02e, 54 }, // VK_C AB03 + { 0x02f, 55 }, // VK_V AB04 + { 0x030, 56 }, // VK_B AB05 + { 0x031, 57 }, // VK_N AB06 + { 0x032, 58 }, // VK_M AB07 + { 0x033, 59 }, // VK_OEM_COMMA AB08 + { 0x034, 60 }, // VK_OEM_PERIOD AB09 + { 0x035, 61 }, // VK_OEM_2 AB10 + { 0x036, 62 }, // VK_RSHIFT RTSH + { 0x037, 63 }, // VK_MULTIPLY KPMU + { 0x038, 64 }, // VK_LMENU LALT + { 0x039, 65 }, // VK_SPACE SPCE + { 0x03a, 66 }, // VK_CAPITAL CAPS + { 0x03b, 67 }, // VK_F1 FK01 + { 0x03c, 68 }, // VK_F2 FK02 + { 0x03d, 69 }, // VK_F3 FK03 + { 0x03e, 70 }, // VK_F4 FK04 + { 0x03f, 71 }, // VK_F5 FK05 + { 0x040, 72 }, // VK_F6 FK06 + { 0x041, 73 }, // VK_F7 FK07 + { 0x042, 74 }, // VK_F8 FK08 + { 0x043, 75 }, // VK_F9 FK09 + { 0x044, 76 }, // VK_F10 FK10 + { 0x045, 77 }, // VK_NUMLOCK NMLK + { 0x046, 78 }, // VK_SCROLL SCLK + { 0x047, 79 }, // VK_HOME KP7 + { 0x048, 80 }, // VK_UP KP8 + { 0x049, 81 }, // VK_PRIOR KP9 + { 0x04a, 82 }, // VK_SUBTRACT KPSU + { 0x04b, 83 }, // VK_LEFT KP4 + { 0x04c, 84 }, // VK_CLEAR KP5 + { 0x04d, 85 }, // VK_RIGHT KP6 + { 0x04e, 86 }, // VK_ADD KPAD + { 0x04f, 87 }, // VK_END KP1 + { 0x050, 88 }, // VK_DOWN KP2 + { 0x051, 89 }, // VK_NEXT KP3 + { 0x052, 90 }, // VK_INSERT KP0 + { 0x053, 91 }, // VK_DELETE KPDL + { 0x056, 94 }, // VK_OEM_102 LSGT + { 0x057, 95 }, // VK_F11 FK11 + { 0x058, 96 }, // VK_F12 FK12 + { 0x070, 101 }, // - HKTG + { 0x073, 97 }, // VK_ABNT_C1 AB11 + { 0x079, 100 }, // - HENK + { 0x07b, 102 }, // VK_OEM_PA1 MUHE + { 0x07d, 132 }, // - AE13 + { 0x110, 173 }, // VK_MEDIA_PREV_TRACK I173 (KEY_PREVIOUSSONG) + { 0x119, 171 }, // VK_MEDIA_NEXT_TRACK I171 (KEY_NEXTSONG) + { 0x11c, 104 }, // VK_RETURN KPEN + { 0x11d, 105 }, // VK_RCONTROL RCTL + { 0x120, 121 }, // VK_VOLUME_MUTE MUTE + { 0x121, 148 }, // VK_LAUNCH_APP2 I148 (KEY_CALC) + { 0x122, 172 }, // VK_PLAY_PAUSE I172 (KEY_PLAYPAUSE) + { 0x124, 174 }, // VK_MEDIA_STOP I174 (KEY_STOPCD) + { 0x12e, 122 }, // VK_VOLUME_DOWN VOL- + { 0x130, 123 }, // VK_VOLUME_UP VOL+ + { 0x132, 180 }, // VK_BROWSER_HOME I180 (KEY_HOMEPAGE) + { 0x135, 106 }, // VK_DIVIDE KPDV + { 0x137, 107 }, // VK_SNAPSHOT PRSC + { 0x138, 108 }, // VK_RMENU RALT + { 0x147, 110 }, // VK_HOME HOME + { 0x148, 111 }, // VK_UP UP + { 0x149, 112 }, // VK_PRIOR PGUP (KEY_COMPUTER) + { 0x14b, 113 }, // VK_LEFT LEFT + { 0x14d, 114 }, // VK_RIGHT RGHT + { 0x14f, 115 }, // VK_END END + { 0x150, 116 }, // VK_DOWN DOWN + { 0x151, 117 }, // VK_NEXT PGDN + { 0x152, 118 }, // VK_INSERT INS + { 0x153, 119 }, // VK_DELETE DELE + { 0x15b, 133 }, // VK_LWIN LWIN + { 0x15c, 134 }, // VK_RWIN RWIN + { 0x15d, 135 }, // VK_APPS COMP + { 0x165, 225 }, // VK_BROWSER_SEARCH I225 (KEY_SEARCH) + { 0x166, 164 }, // VK_BROWSER_FAVORITES I164 (KEY_BOOKMARKS) + { 0x16b, 165 }, // VK_LAUNCH_APP1 I165 (KEY_COMPUTER) + { 0x16c, 163 } // VK_LAUNCH_MAIL I163 (KEY_MAIL) +}; + +// Sources:- +// file:/usr/share/X11/xkb/keycodes/xfree86 +// https://wiki.osdev.org/PS/2_Keyboard +// https://www.kbdlayout.info/ +static const struct scancode_to_keycode + base_scancode_to_keycode_map[] = +{ + // Virtual XKB + // Key (US) Symbol + // -------- ------ + { 0x001, 9 }, // VK_ESCAPE ESC + { 0x002, 10 }, // VK_1 AE01 + { 0x003, 11 }, // VK_2 AE02 + { 0x004, 12 }, // VK_3 AE03 + { 0x005, 13 }, // VK_4 AE04 + { 0x006, 14 }, // VK_5 AE05 + { 0x007, 15 }, // VK_6 AE06 + { 0x008, 16 }, // VK_7 AE07 + { 0x009, 17 }, // VK_8 AE08 + { 0x00a, 18 }, // VK_9 AE09 + { 0x00b, 19 }, // VK_0 AE10 + { 0x00c, 20 }, // VK_OEM_MINUS AE11 + { 0x00d, 21 }, // VK_OEM_PLUS AE12 + { 0x00e, 22 }, // VK_BACK BKSP + { 0x00f, 23 }, // VK_TAB TAB + { 0x010, 24 }, // VK_Q AD01 + { 0x011, 25 }, // VK_W AD02 + { 0x012, 26 }, // VK_E AD03 + { 0x013, 27 }, // VK_R AD04 + { 0x014, 28 }, // VK_T AD05 + { 0x015, 29 }, // VK_Y AD06 + { 0x016, 30 }, // VK_U AD07 + { 0x017, 31 }, // VK_I AD08 + { 0x018, 32 }, // VK_O AD09 + { 0x019, 33 }, // VK_P AD10 + { 0x01a, 34 }, // VK_OEM_4 AD11 + { 0x01b, 35 }, // VK_OEM_6 AD12 + { 0x01c, 36 }, // VK_RETURN RTRN + { 0x01d, 37 }, // VK_LCONTROL LCTL + { 0x01e, 38 }, // VK_A AC01 + { 0x01f, 39 }, // VK_S AC02 + { 0x020, 40 }, // VK_D AC03 + { 0x021, 41 }, // VK_F AC04 + { 0x022, 42 }, // VK_G AC05 + { 0x023, 43 }, // VK_H AC06 + { 0x024, 44 }, // VK_J AC07 + { 0x025, 45 }, // VK_K AC08 + { 0x026, 46 }, // VK_L AC09 + { 0x027, 47 }, // VK_OEM_1 AC10 + { 0x028, 48 }, // VK_OEM_7 AC11 + { 0x029, 49 }, // VK_OEM_3 TLDE + { 0x02a, 50 }, // VK_LSHIFT LFSH + { 0x02b, 51 }, // VK_OEM_5 BKSL + { 0x02c, 52 }, // VK_Z AB01 + { 0x02d, 53 }, // VK_X AB02 + { 0x02e, 54 }, // VK_C AB03 + { 0x02f, 55 }, // VK_V AB04 + { 0x030, 56 }, // VK_B AB05 + { 0x031, 57 }, // VK_N AB06 + { 0x032, 58 }, // VK_M AB07 + { 0x033, 59 }, // VK_OEM_COMMA AB08 + { 0x034, 60 }, // VK_OEM_PERIOD AB09 + { 0x035, 61 }, // VK_OEM_2 AB10 + { 0x036, 62 }, // VK_RSHIFT RTSH + { 0x037, 63 }, // VK_MULTIPLY KPMU + { 0x038, 64 }, // VK_LMENU LALT + { 0x039, 65 }, // VK_SPACE SPCE + { 0x03a, 66 }, // VK_CAPITAL CAPS + { 0x03b, 67 }, // VK_F1 FK01 + { 0x03c, 68 }, // VK_F2 FK02 + { 0x03d, 69 }, // VK_F3 FK03 + { 0x03e, 70 }, // VK_F4 FK04 + { 0x03f, 71 }, // VK_F5 FK05 + { 0x040, 72 }, // VK_F6 FK06 + { 0x041, 73 }, // VK_F7 FK07 + { 0x042, 74 }, // VK_F8 FK08 + { 0x043, 75 }, // VK_F9 FK09 + { 0x044, 76 }, // VK_F10 FK10 + { 0x045, 77 }, // VK_NUMLOCK NMLK + { 0x046, 78 }, // VK_SCROLL SCLK + { 0x047, 79 }, // VK_HOME KP7 + { 0x048, 80 }, // VK_UP KP8 + { 0x049, 81 }, // VK_PRIOR KP9 + { 0x04a, 82 }, // VK_SUBTRACT KPSU + { 0x04b, 83 }, // VK_LEFT KP4 + { 0x04c, 84 }, // VK_CLEAR KP5 + { 0x04d, 85 }, // VK_RIGHT KP6 + { 0x04e, 86 }, // VK_ADD KPAD + { 0x04f, 87 }, // VK_END KP1 + { 0x050, 88 }, // VK_DOWN KP2 + { 0x051, 89 }, // VK_NEXT KP3 + { 0x052, 90 }, // VK_INSERT KP0 + { 0x053, 91 }, // VK_DELETE KPDL + { 0x056, 94 }, // VK_OEM_102 LSGT + { 0x057, 95 }, // VK_F11 FK11 + { 0x058, 96 }, // VK_F12 FK12 + { 0x070, 208 }, // - HKTG + { 0x073, 211 }, // VK_ABNT_C1 AB11 + { 0x079, 129 }, // - XFER + { 0x07b, 131 }, // VK_OEM_PA1 NFER + { 0x07d, 133 }, // - AE13 + { 0x11c, 108 }, // VK_RETURN KPEN + { 0x11d, 109 }, // VK_RCONTROL RCTL + { 0x120, 141 }, // VK_VOLUME_MUTE MUTE + { 0x12e, 142 }, // VK_VOLUME_DOWN VOL- + { 0x130, 143 }, // VK_VOLUME_UP VOL+ + { 0x135, 112 }, // VK_DIVIDE KPDV + { 0x137, 121 }, // VK_SNAPSHOT PRSC + { 0x138, 113 }, // VK_RMENU RALT + { 0x147, 97 }, // VK_HOME HOME + { 0x148, 98 }, // VK_UP UP + { 0x149, 99 }, // VK_PRIOR PGUP (KEY_COMPUTER) + { 0x14b, 100 }, // VK_LEFT LEFT + { 0x14d, 102 }, // VK_RIGHT RGHT + { 0x14f, 103 }, // VK_END END + { 0x150, 104 }, // VK_DOWN DOWN + { 0x151, 105 }, // VK_NEXT PGDN + { 0x152, 106 }, // VK_INSERT INS + { 0x153, 107 }, // VK_DELETE DELE + { 0x15b, 115 }, // VK_LWIN LWIN + { 0x15c, 116 }, // VK_RWIN RWIN + { 0x15d, 117 } // VK_APPS COMP +}; + +struct map_settings +{ + const struct scancode_to_keycode *map; + const char *name; + unsigned int size; +}; + +enum settings_index +{ + SI_EVDEV = 0, + SI_BASE +}; + +const struct map_settings global_settings[] = +{ + { + // SI_EVDEV + .map = evdev_scancode_to_keycode_map, + .name = "evdev", + .size = ELEMENTS(evdev_scancode_to_keycode_map), + }, + { + // SI_BASE + .map = base_scancode_to_keycode_map, + .name = "base", + .size = ELEMENTS(base_scancode_to_keycode_map) + } +}; + +// Default mapping set is "evdev" +const struct map_settings *settings = &global_settings[SI_EVDEV]; + +/*****************************************************************************/ +unsigned short +scancode_to_keycode(unsigned short scancode) +{ + unsigned int min = 0; + unsigned int max = settings->size; + unsigned short rv = 0; + + // Check scancode is in range of map + if (scancode >= settings->map[min].scancode && + scancode <= settings->map[max - 1].scancode) + { + // Use a binary chop to locate the correct index + // in logarithmic time. + while (1) + { + unsigned int index = (min + max) / 2; + if (scancode == settings->map[index].scancode) + { + rv = settings->map[index].keycode; + break; + } + // Adjust min or max, checking for end + // of iteration + if (scancode < settings->map[index].scancode) + { + max = index; + } + else if (min == index) + { + // We've already checked this value + break; + } + else + { + min = index; + } + } + } + + return rv; +} + +/*****************************************************************************/ +unsigned short +scancode_get_next(unsigned int *iter) +{ + unsigned short rv = 0; + if (*iter < settings->size) + { + rv = settings->map[*iter].scancode; + ++(*iter); + } + + return rv; +} + +/*****************************************************************************/ +int +scancode_set_keycode_set(const char *kk_set) +{ + int rv = 0; + + if (kk_set == NULL) + { + rv = 1; + } + else if (strncmp(kk_set, "evdev", 5) == 0) + { + settings = &global_settings[SI_EVDEV]; + } + else if (strncmp(kk_set, "base", 4) == 0) + { + settings = &global_settings[SI_BASE]; + } + else if (strncmp(kk_set, "xfree86", 7) == 0) + { + settings = &global_settings[SI_BASE]; + } + else + { + rv = 1; + } + + return rv; +} + +/*****************************************************************************/ +const char * +scancode_get_keycode_set(void) +{ + return settings->name; +} diff --git a/common/scancode.h b/common/scancode.h new file mode 100644 index 00000000..6c76f086 --- /dev/null +++ b/common/scancode.h @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2024 Matt Burt, all xrdp contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file common/scancode.h + * @brief Scancode handling + * + * Convert between RDP scancodes and X11 keycodes. + * + * RDP scancodes are largely the same as Windows scancodes. These are + * indirectly documented in the Microsoft "Keyboard Scan Code Specification", + * Rev 1.3a (March 16th 2000) and are otherwise known as "Scan code set + * 1" scancodes. This document no longer appears to be available directly from + * the Microsoft website. + * + * X11 keycodes are the X11 equivalent of RDP scancodes. In general, these + * are specific to an X server. In practice however, these are nowadays + * handled by the XKB extension and only two sets are in common use:- + * - evdev : Linux, FreeBSD and possibly others + * - base : Everything else. + * + * This module presents a single source of truth for conversions between + * RDP scancodes and X11 keycodes. + */ + +#if !defined(SCANCODE_H) +#define SCANCODE_H + +/** + * Looks up an RDP scancode + * + * @param scancode Scancode. Extended scancodes have bit 9 set + * (i.e. are in 0x100 - 0x1ff) + * @return keycode, or 0 for no keycode + */ +unsigned short +scancode_to_keycode(unsigned short scancode); + +/** + * Gets the next valid scancode from the list of valid scancodes + * @param iter Value (initialised to zero), used to iterate + * over available scancodes. + * @return Next valid scancode, or zero. + * + * The iterator is updated on a successful call. Use like this:- + * + * iter = 0; + * while ((scancode = scancode_get_next(&iter)) != 0) + * { + * . . . + * } + */ +unsigned short +scancode_get_next(unsigned int *iter); + +/** + * Sets the keycode set used for the scancode translation + * + * @param kk_set "evdev", "base", or something more + * complex (e.g. "evdev+aliases(qwerty)") + * @result 0 for success + */ +int +scancode_set_keycode_set(const char *kk_set); + +/** + * Gets the keycode set used for the scancode translation + * + * @result "evdev", or "base" + */ +const char * +scancode_get_keycode_set(void); + +#endif /* SCANCODE_H */ diff --git a/tests/common/Makefile.am b/tests/common/Makefile.am index c85a5f38..07259d62 100644 --- a/tests/common/Makefile.am +++ b/tests/common/Makefile.am @@ -23,7 +23,8 @@ test_common_SOURCES = \ test_os_calls_signals.c \ test_ssl_calls.c \ test_base64.c \ - test_guid.c + test_guid.c \ + test_scancode.c test_common_CFLAGS = \ @CHECK_CFLAGS@ \ diff --git a/tests/common/test_common.h b/tests/common/test_common.h index 3caeaff7..c496b425 100644 --- a/tests/common/test_common.h +++ b/tests/common/test_common.h @@ -16,6 +16,7 @@ Suite *make_suite_test_os_calls(void); Suite *make_suite_test_ssl_calls(void); Suite *make_suite_test_base64(void); Suite *make_suite_test_guid(void); +Suite *make_suite_test_scancode(void); TCase *make_tcase_test_os_calls_signals(void); diff --git a/tests/common/test_common_main.c b/tests/common/test_common_main.c index 63f641c9..6bdda940 100644 --- a/tests/common/test_common_main.c +++ b/tests/common/test_common_main.c @@ -55,6 +55,7 @@ int main (void) srunner_add_suite(sr, make_suite_test_ssl_calls()); srunner_add_suite(sr, make_suite_test_base64()); srunner_add_suite(sr, make_suite_test_guid()); + srunner_add_suite(sr, make_suite_test_scancode()); srunner_set_tap(sr, "-"); /* diff --git a/tests/common/test_scancode.c b/tests/common/test_scancode.c new file mode 100644 index 00000000..4e328353 --- /dev/null +++ b/tests/common/test_scancode.c @@ -0,0 +1,128 @@ + +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +#include "scancode.h" + +#include "test_common.h" + +// Checks all returned evdev scancodes are mapped to a keycode +START_TEST(test_scancode__keycode_sets) +{ + ck_assert_int_eq(scancode_set_keycode_set(NULL), 1); + ck_assert_int_eq(scancode_set_keycode_set(""), 1); + ck_assert_int_eq(scancode_set_keycode_set("evdev"), 0); + ck_assert_int_eq(scancode_set_keycode_set("evdev+aliases(qwerty)"), 0); + ck_assert_int_eq(scancode_set_keycode_set("base"), 0); + ck_assert_int_eq(scancode_set_keycode_set("xfree86"), 0); + ck_assert_int_eq(scancode_set_keycode_set("xfree86+aliases(qwerty)"), 0); +} +END_TEST + +// Checks all returned evdev scancodes are mapped to a keycode +START_TEST(test_scancode__evdev_all_values_returned) +{ + unsigned int iter; + unsigned int scancode; + + ck_assert_int_eq(scancode_set_keycode_set("evdev"), 0); + + iter = 0; + while ((scancode = scancode_get_next(&iter)) != 0) + { + unsigned short keycode = scancode_to_keycode(scancode); + ck_assert_int_ne(keycode, 0); + } +} +END_TEST + +// Checks all invalid evdev scancodes return 0 +START_TEST(test_scancode__evdev_bad_values_mapped_to_0) +{ + // Store valid scancodes which are between 0 and 0x1ff + int valid[512] = {0}; + unsigned int iter; + unsigned int scancode; + + ck_assert_int_eq(scancode_set_keycode_set("evdev"), 0); + + iter = 0; + while ((scancode = scancode_get_next(&iter)) != 0) + { + valid[scancode] = 1; + } + + for (scancode = 0 ; scancode < 512; ++scancode) + { + if (!valid[scancode]) + { + ck_assert_int_eq(scancode_to_keycode(scancode), 0); + } + } +} +END_TEST + +// Checks all returned base scancodes are mapped to a keycode +START_TEST(test_scancode__base_all_values_returned) +{ + unsigned int iter; + unsigned int scancode; + + ck_assert_int_eq(scancode_set_keycode_set("base"), 0); + + iter = 0; + while ((scancode = scancode_get_next(&iter)) != 0) + { + unsigned short keycode = scancode_to_keycode(scancode); + ck_assert_int_ne(keycode, 0); + } +} +END_TEST + +// Checks all invalid base scancodes return 0 +START_TEST(test_scancode__base_bad_values_mapped_to_0) +{ + // Store valid scancodes which are between 0 and 0x1ff + int valid[512] = {0}; + unsigned int iter; + unsigned int scancode; + + ck_assert_int_eq(scancode_set_keycode_set("base"), 0); + + iter = 0; + while ((scancode = scancode_get_next(&iter)) != 0) + { + valid[scancode] = 1; + } + + for (scancode = 0 ; scancode < 512; ++scancode) + { + if (!valid[scancode]) + { + ck_assert_int_eq(scancode_to_keycode(scancode), 0); + } + } +} +END_TEST + +/******************************************************************************/ + +Suite * +make_suite_test_scancode(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("Scancode"); + + tc = tcase_create("scancode"); + suite_add_tcase(s, tc); + tcase_add_test(tc, test_scancode__keycode_sets); + tcase_add_test(tc, test_scancode__evdev_all_values_returned); + tcase_add_test(tc, test_scancode__evdev_bad_values_mapped_to_0); + tcase_add_test(tc, test_scancode__base_all_values_returned); + tcase_add_test(tc, test_scancode__base_bad_values_mapped_to_0); + + return s; +}