| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <hid/hid.h> |
| #include <hid/usages.h> |
| #include <unittest/unittest.h> |
| |
| #include "keyboard-vt100.h" |
| #include "keyboard.h" |
| |
| namespace { |
| |
| // State reported to keypress_handler(). |
| uint8_t g_keycode; |
| int g_modifiers; |
| bool g_got_keypress = false; |
| |
| void keypress_handler(uint8_t keycode, int modifiers) { |
| g_keycode = keycode; |
| g_modifiers = modifiers; |
| g_got_keypress = true; |
| } |
| |
| void expect_keypress(uint8_t expected_keycode, int expected_modifiers, |
| uint8_t expected_char) { |
| |
| EXPECT_EQ(g_got_keypress, true, ""); |
| g_got_keypress = false; |
| |
| EXPECT_EQ(g_keycode, expected_keycode, ""); |
| EXPECT_EQ(g_modifiers, expected_modifiers, ""); |
| |
| char output[4] = {}; |
| uint32_t length = hid_key_to_vt100_code( |
| g_keycode, g_modifiers, qwerty_map, output, sizeof(output)); |
| if (expected_char == 0) { |
| EXPECT_EQ(length, 0, ""); |
| } else { |
| EXPECT_EQ(length, 1, ""); |
| EXPECT_EQ(output[0], expected_char, ""); |
| } |
| } |
| |
| class KeyboardInputHelper { |
| public: |
| KeyboardInputHelper() { |
| EXPECT_EQ(vc_input_create(&vi_, keypress_handler, -1), ZX_OK, ""); |
| } |
| |
| ~KeyboardInputHelper() { |
| } |
| |
| void WriteReportBuf() { |
| vc_input_process(vi_, report_buf_); |
| } |
| |
| // Byte 0 contains one bit per modifier key. |
| void set_modifiers_byte(uint8_t value) { report_buf_[0] = value; } |
| // Bytes 2+ contain USB HID key codes. |
| void set_first_keycode(uint8_t value) { report_buf_[2] = value; } |
| |
| private: |
| // USB HID key state buffer. |
| uint8_t report_buf_[8] = {}; |
| |
| vc_input_t* vi_; |
| }; |
| |
| bool test_keyboard_input_thread() { |
| BEGIN_TEST; |
| |
| KeyboardInputHelper helper; |
| |
| // Test pressing keys without any modifiers. |
| helper.set_first_keycode(HID_USAGE_KEY_M); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_M, 0, 'm'); |
| |
| helper.set_first_keycode(HID_USAGE_KEY_6); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_6, 0, '6'); |
| |
| // Press a modifier (but no other keys). |
| helper.set_first_keycode(0); // Unset the earlier key |
| helper.set_modifiers_byte(2); // Left Shift key |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT, '\0'); |
| |
| // Test keys with modifiers pressed. |
| // Test Shift-N. |
| helper.set_first_keycode(HID_USAGE_KEY_N); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_N, MOD_LSHIFT, 'N'); |
| |
| // Test Shift-8. |
| helper.set_first_keycode(HID_USAGE_KEY_8); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_8, MOD_LSHIFT, '*'); |
| |
| // Test Ctrl modifier. First send a separate report_buf event to |
| // report unsetting the Shift key state, to account for a quirk of the |
| // current implementation. |
| helper.set_modifiers_byte(0); |
| helper.WriteReportBuf(); |
| helper.set_modifiers_byte(1); // Left Ctrl key |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_LEFT_CTRL, MOD_LCTRL, '\0'); |
| |
| // Test Ctrl-J. |
| helper.set_first_keycode(HID_USAGE_KEY_J); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_J, MOD_LCTRL, 10); |
| |
| // Test Ctrl-1. The Ctrl modifier should be ignored in this case so |
| // that we just get '1'. |
| helper.set_first_keycode(HID_USAGE_KEY_1); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_1, MOD_LCTRL, '1'); |
| |
| // Try Shift and Ctrl together. |
| helper.set_first_keycode(0); |
| helper.set_modifiers_byte(1 | 2); // Left Shift and Left Ctrl keys |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT | MOD_LCTRL, '\0'); |
| |
| // Test Shift-Ctrl-J. This should be equivalent to Ctrl-J. |
| helper.set_first_keycode(HID_USAGE_KEY_J); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_J, MOD_LSHIFT | MOD_LCTRL, 10); |
| |
| // Test Shift-Ctrl-1. This should be equivalent to Shift-1. |
| helper.set_first_keycode(HID_USAGE_KEY_1); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_1, MOD_LSHIFT | MOD_LCTRL, '!'); |
| |
| END_TEST; |
| } |
| |
| bool test_caps_lock() { |
| BEGIN_TEST; |
| |
| KeyboardInputHelper helper; |
| |
| helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_CAPSLOCK, '\0'); |
| |
| // Test that letters are capitalized. |
| helper.set_first_keycode(HID_USAGE_KEY_M); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_M, MOD_CAPSLOCK, 'M'); |
| |
| // Non-letter characters should not be affected. This isn't Shift Lock. |
| helper.set_first_keycode(HID_USAGE_KEY_1); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_1, MOD_CAPSLOCK, '1'); |
| |
| // Test unsetting Caps Lock. |
| helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_CAPSLOCK, 0, '\0'); |
| |
| helper.set_first_keycode(HID_USAGE_KEY_M); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_M, 0, 'm'); |
| |
| END_TEST; |
| } |
| |
| bool test_caps_lock_with_shift() { |
| BEGIN_TEST; |
| |
| KeyboardInputHelper helper; |
| |
| helper.set_modifiers_byte(2); // Left Shift key |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT, '\0'); |
| helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_LSHIFT | MOD_CAPSLOCK, '\0'); |
| |
| // Shift should undo the effect of Caps Lock for letters. |
| helper.set_first_keycode(HID_USAGE_KEY_M); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_M, MOD_LSHIFT | MOD_CAPSLOCK, 'm'); |
| |
| helper.set_first_keycode(HID_USAGE_KEY_1); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_1, MOD_LSHIFT | MOD_CAPSLOCK, '!'); |
| |
| // Test unsetting Caps Lock. |
| helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_LSHIFT, '\0'); |
| |
| helper.set_first_keycode(HID_USAGE_KEY_M); |
| helper.WriteReportBuf(); |
| expect_keypress(HID_USAGE_KEY_M, MOD_LSHIFT, 'M'); |
| |
| END_TEST; |
| } |
| |
| BEGIN_TEST_CASE(gfxconsole_keyboard_tests) |
| RUN_TEST(test_keyboard_input_thread) |
| RUN_TEST(test_caps_lock) |
| RUN_TEST(test_caps_lock_with_shift) |
| END_TEST_CASE(gfxconsole_keyboard_tests) |
| |
| } |