1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <hid/hid.h>
6 #include <hid/usages.h>
7 #include <unittest/unittest.h>
8
9 #include "keyboard-vt100.h"
10 #include "keyboard.h"
11
12 namespace {
13
14 // State reported to keypress_handler().
15 uint8_t g_keycode;
16 int g_modifiers;
17 bool g_got_keypress = false;
18
keypress_handler(uint8_t keycode,int modifiers)19 void keypress_handler(uint8_t keycode, int modifiers) {
20 g_keycode = keycode;
21 g_modifiers = modifiers;
22 g_got_keypress = true;
23 }
24
expect_keypress(uint8_t expected_keycode,int expected_modifiers,uint8_t expected_char)25 void expect_keypress(uint8_t expected_keycode, int expected_modifiers,
26 uint8_t expected_char) {
27
28 EXPECT_EQ(g_got_keypress, true, "");
29 g_got_keypress = false;
30
31 EXPECT_EQ(g_keycode, expected_keycode, "");
32 EXPECT_EQ(g_modifiers, expected_modifiers, "");
33
34 char output[4] = {};
35 uint32_t length = hid_key_to_vt100_code(
36 g_keycode, g_modifiers, qwerty_map, output, sizeof(output));
37 if (expected_char == 0) {
38 EXPECT_EQ(length, 0, "");
39 } else {
40 EXPECT_EQ(length, 1, "");
41 EXPECT_EQ(output[0], expected_char, "");
42 }
43 }
44
45 class KeyboardInputHelper {
46 public:
KeyboardInputHelper()47 KeyboardInputHelper() {
48 EXPECT_EQ(vc_input_create(&vi_, keypress_handler, -1), ZX_OK, "");
49 }
50
~KeyboardInputHelper()51 ~KeyboardInputHelper() {
52 }
53
WriteReportBuf()54 void WriteReportBuf() {
55 vc_input_process(vi_, report_buf_);
56 }
57
58 // Byte 0 contains one bit per modifier key.
set_modifiers_byte(uint8_t value)59 void set_modifiers_byte(uint8_t value) { report_buf_[0] = value; }
60 // Bytes 2+ contain USB HID key codes.
set_first_keycode(uint8_t value)61 void set_first_keycode(uint8_t value) { report_buf_[2] = value; }
62
63 private:
64 // USB HID key state buffer.
65 uint8_t report_buf_[8] = {};
66
67 vc_input_t* vi_;
68 };
69
test_keyboard_input_thread()70 bool test_keyboard_input_thread() {
71 BEGIN_TEST;
72
73 KeyboardInputHelper helper;
74
75 // Test pressing keys without any modifiers.
76 helper.set_first_keycode(HID_USAGE_KEY_M);
77 helper.WriteReportBuf();
78 expect_keypress(HID_USAGE_KEY_M, 0, 'm');
79
80 helper.set_first_keycode(HID_USAGE_KEY_6);
81 helper.WriteReportBuf();
82 expect_keypress(HID_USAGE_KEY_6, 0, '6');
83
84 // Press a modifier (but no other keys).
85 helper.set_first_keycode(0); // Unset the earlier key
86 helper.set_modifiers_byte(2); // Left Shift key
87 helper.WriteReportBuf();
88 expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT, '\0');
89
90 // Test keys with modifiers pressed.
91 // Test Shift-N.
92 helper.set_first_keycode(HID_USAGE_KEY_N);
93 helper.WriteReportBuf();
94 expect_keypress(HID_USAGE_KEY_N, MOD_LSHIFT, 'N');
95
96 // Test Shift-8.
97 helper.set_first_keycode(HID_USAGE_KEY_8);
98 helper.WriteReportBuf();
99 expect_keypress(HID_USAGE_KEY_8, MOD_LSHIFT, '*');
100
101 // Test Ctrl modifier. First send a separate report_buf event to
102 // report unsetting the Shift key state, to account for a quirk of the
103 // current implementation.
104 helper.set_modifiers_byte(0);
105 helper.WriteReportBuf();
106 helper.set_modifiers_byte(1); // Left Ctrl key
107 helper.WriteReportBuf();
108 expect_keypress(HID_USAGE_KEY_LEFT_CTRL, MOD_LCTRL, '\0');
109
110 // Test Ctrl-J.
111 helper.set_first_keycode(HID_USAGE_KEY_J);
112 helper.WriteReportBuf();
113 expect_keypress(HID_USAGE_KEY_J, MOD_LCTRL, 10);
114
115 // Test Ctrl-1. The Ctrl modifier should be ignored in this case so
116 // that we just get '1'.
117 helper.set_first_keycode(HID_USAGE_KEY_1);
118 helper.WriteReportBuf();
119 expect_keypress(HID_USAGE_KEY_1, MOD_LCTRL, '1');
120
121 // Try Shift and Ctrl together.
122 helper.set_first_keycode(0);
123 helper.set_modifiers_byte(1 | 2); // Left Shift and Left Ctrl keys
124 helper.WriteReportBuf();
125 expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT | MOD_LCTRL, '\0');
126
127 // Test Shift-Ctrl-J. This should be equivalent to Ctrl-J.
128 helper.set_first_keycode(HID_USAGE_KEY_J);
129 helper.WriteReportBuf();
130 expect_keypress(HID_USAGE_KEY_J, MOD_LSHIFT | MOD_LCTRL, 10);
131
132 // Test Shift-Ctrl-1. This should be equivalent to Shift-1.
133 helper.set_first_keycode(HID_USAGE_KEY_1);
134 helper.WriteReportBuf();
135 expect_keypress(HID_USAGE_KEY_1, MOD_LSHIFT | MOD_LCTRL, '!');
136
137 END_TEST;
138 }
139
test_caps_lock()140 bool test_caps_lock() {
141 BEGIN_TEST;
142
143 KeyboardInputHelper helper;
144
145 helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK);
146 helper.WriteReportBuf();
147 expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_CAPSLOCK, '\0');
148
149 // Test that letters are capitalized.
150 helper.set_first_keycode(HID_USAGE_KEY_M);
151 helper.WriteReportBuf();
152 expect_keypress(HID_USAGE_KEY_M, MOD_CAPSLOCK, 'M');
153
154 // Non-letter characters should not be affected. This isn't Shift Lock.
155 helper.set_first_keycode(HID_USAGE_KEY_1);
156 helper.WriteReportBuf();
157 expect_keypress(HID_USAGE_KEY_1, MOD_CAPSLOCK, '1');
158
159 // Test unsetting Caps Lock.
160 helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK);
161 helper.WriteReportBuf();
162 expect_keypress(HID_USAGE_KEY_CAPSLOCK, 0, '\0');
163
164 helper.set_first_keycode(HID_USAGE_KEY_M);
165 helper.WriteReportBuf();
166 expect_keypress(HID_USAGE_KEY_M, 0, 'm');
167
168 END_TEST;
169 }
170
test_caps_lock_with_shift()171 bool test_caps_lock_with_shift() {
172 BEGIN_TEST;
173
174 KeyboardInputHelper helper;
175
176 helper.set_modifiers_byte(2); // Left Shift key
177 helper.WriteReportBuf();
178 expect_keypress(HID_USAGE_KEY_LEFT_SHIFT, MOD_LSHIFT, '\0');
179 helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK);
180 helper.WriteReportBuf();
181 expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_LSHIFT | MOD_CAPSLOCK, '\0');
182
183 // Shift should undo the effect of Caps Lock for letters.
184 helper.set_first_keycode(HID_USAGE_KEY_M);
185 helper.WriteReportBuf();
186 expect_keypress(HID_USAGE_KEY_M, MOD_LSHIFT | MOD_CAPSLOCK, 'm');
187
188 helper.set_first_keycode(HID_USAGE_KEY_1);
189 helper.WriteReportBuf();
190 expect_keypress(HID_USAGE_KEY_1, MOD_LSHIFT | MOD_CAPSLOCK, '!');
191
192 // Test unsetting Caps Lock.
193 helper.set_first_keycode(HID_USAGE_KEY_CAPSLOCK);
194 helper.WriteReportBuf();
195 expect_keypress(HID_USAGE_KEY_CAPSLOCK, MOD_LSHIFT, '\0');
196
197 helper.set_first_keycode(HID_USAGE_KEY_M);
198 helper.WriteReportBuf();
199 expect_keypress(HID_USAGE_KEY_M, MOD_LSHIFT, 'M');
200
201 END_TEST;
202 }
203
204 BEGIN_TEST_CASE(gfxconsole_keyboard_tests)
205 RUN_TEST(test_keyboard_input_thread)
206 RUN_TEST(test_caps_lock)
207 RUN_TEST(test_caps_lock_with_shift)
208 END_TEST_CASE(gfxconsole_keyboard_tests)
209
210 }
211