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 <fcntl.h>
6 #include <poll.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include <fuchsia/hardware/input/c/fidl.h>
12 #include <hid/hid.h>
13 #include <hid/usages.h>
14 #include <lib/fzl/fdio.h>
15 #include <zircon/syscalls.h>
16
17 #include <port/port.h>
18
19 #include <utility>
20
21 #include "keyboard.h"
22
23 #define LOW_REPEAT_KEY_FREQ 250000000
24 #define HIGH_REPEAT_KEY_FREQ 50000000
25
modifiers_from_keycode(uint8_t keycode)26 static int modifiers_from_keycode(uint8_t keycode) {
27 switch (keycode) {
28 case HID_USAGE_KEY_LEFT_SHIFT:
29 return MOD_LSHIFT;
30 case HID_USAGE_KEY_RIGHT_SHIFT:
31 return MOD_RSHIFT;
32 case HID_USAGE_KEY_LEFT_ALT:
33 return MOD_LALT;
34 case HID_USAGE_KEY_RIGHT_ALT:
35 return MOD_RALT;
36 case HID_USAGE_KEY_LEFT_CTRL:
37 return MOD_LCTRL;
38 case HID_USAGE_KEY_RIGHT_CTRL:
39 return MOD_RCTRL;
40 }
41 return 0;
42 }
43
set_caps_lock_led(int keyboard_fd,bool caps_lock)44 static void set_caps_lock_led(int keyboard_fd, bool caps_lock) {
45 // The following bit to set is specified in "Device Class Definition
46 // for Human Interface Devices (HID)", Version 1.11,
47 // http://www.usb.org/developers/hidpage/HID1_11.pdf. Zircon leaves
48 // USB keyboards in boot mode, so the relevant section is Appendix B,
49 // "Boot Interface Descriptors", "B.1 Protocol 1 (Keyboard)".
50 const uint8_t kUsbCapsLockBit = 1 << 1;
51 const uint8_t report_body[1] = { static_cast<uint8_t>(caps_lock ? kUsbCapsLockBit : 0) };
52
53 // Temporarily wrap keyboard_fd, we will release it after the call so we don't close it.
54 fzl::FdioCaller caller{fbl::unique_fd(keyboard_fd)};
55 zx_status_t call_status;
56 zx_status_t status = fuchsia_hardware_input_DeviceSetReport(
57 caller.borrow_channel(), fuchsia_hardware_input_ReportType_OUTPUT, 0, report_body,
58 sizeof(report_body), &call_status);
59 caller.release().release();
60 if (status != ZX_OK || call_status != ZX_OK) {
61 #if !BUILD_FOR_TEST
62 printf("fuchsia.hardware.input.Device.SetReport() failed (returned %d, %d)\n", status,
63 call_status);
64 #endif
65 }
66 }
67
68 struct vc_input {
69 port_fd_handler_t fh;
70 port_handler_t th;
71 zx_handle_t timer;
72
73 keypress_handler_t handler;
74 int fd;
75
76 uint8_t previous_report_buf[8];
77 uint8_t report_buf[8];
78 hid_keys_t state[2];
79 int cur_idx;
80 int prev_idx;
81 int modifiers;
82 uint64_t repeat_interval;
83 bool repeat_enabled;
84 };
85
86 // returns true if key was pressed and none were released
vc_input_process(vc_input_t * vi,uint8_t report[8])87 bool vc_input_process(vc_input_t* vi, uint8_t report[8]) {
88 bool do_repeat = false;
89
90 // process the key
91 uint8_t keycode;
92 hid_keys_t keys;
93
94 hid_kbd_parse_report(report, &vi->state[vi->cur_idx]);
95
96 hid_kbd_pressed_keys(&vi->state[vi->prev_idx], &vi->state[vi->cur_idx], &keys);
97 hid_for_every_key(&keys, keycode) {
98 vi->modifiers |= modifiers_from_keycode(keycode);
99 if (keycode == HID_USAGE_KEY_CAPSLOCK) {
100 vi->modifiers ^= MOD_CAPSLOCK;
101 set_caps_lock_led(vi->fd, vi->modifiers & MOD_CAPSLOCK);
102 }
103 vi->handler(keycode, vi->modifiers);
104 do_repeat = true;
105 }
106
107 hid_kbd_released_keys(&vi->state[vi->prev_idx], &vi->state[vi->cur_idx], &keys);
108 hid_for_every_key(&keys, keycode) {
109 vi->modifiers &= ~modifiers_from_keycode(keycode);
110 do_repeat = false;
111 }
112
113 // swap key states
114 vi->cur_idx = 1 - vi->cur_idx;
115 vi->prev_idx = 1 - vi->prev_idx;
116
117 return do_repeat;
118 }
119
120 #if !BUILD_FOR_TEST
vc_input_destroy(vc_input_t * vi)121 static void vc_input_destroy(vc_input_t* vi) {
122 port_cancel(&port, &vi->th);
123 if (vi->fd >= 0) {
124 port_fd_handler_done(&vi->fh);
125 close(vi->fd);
126 }
127 zx_handle_close(vi->timer);
128 free(vi);
129 }
130
vc_timer_cb(port_handler_t * ph,zx_signals_t signals,uint32_t evt)131 static zx_status_t vc_timer_cb(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
132 vc_input_t* vi = containerof(ph, vc_input_t, th);
133
134 // if interval is infinite, repeat was canceled
135 if (vi->repeat_interval != ZX_TIME_INFINITE) {
136 vc_input_process(vi, vi->previous_report_buf);
137 vc_input_process(vi, vi->report_buf);
138
139 // increase repeat rate if we're not yet at the fastest rate
140 if ((vi->repeat_interval = vi->repeat_interval * 3 / 4) < HIGH_REPEAT_KEY_FREQ) {
141 vi->repeat_interval = HIGH_REPEAT_KEY_FREQ;
142 }
143
144 zx_timer_set(vi->timer, zx_deadline_after(vi->repeat_interval), 0);
145 }
146
147 // return non-OK to avoid needlessly re-arming the repeating wait
148 return ZX_ERR_NEXT;
149 }
150
vc_input_cb(port_fd_handler_t * fh,unsigned pollevt,uint32_t evt)151 static zx_status_t vc_input_cb(port_fd_handler_t* fh, unsigned pollevt, uint32_t evt) {
152 vc_input_t* vi = containerof(fh, vc_input_t, fh);
153 ssize_t r;
154
155 if (!(pollevt & POLLIN)) {
156 r = ZX_ERR_PEER_CLOSED;
157 } else {
158 memcpy(vi->previous_report_buf, vi->report_buf, sizeof(vi->report_buf));
159 r = read(vi->fd, vi->report_buf, sizeof(vi->report_buf));
160 }
161 if (r <= 0) {
162 vc_input_destroy(vi);
163 return ZX_ERR_STOP;
164 }
165 if ((size_t)(r) != sizeof(vi->report_buf)) {
166 vi->repeat_interval = ZX_TIME_INFINITE;
167 return ZX_OK;
168 }
169
170 if (vc_input_process(vi, vi->report_buf) && vi->repeat_enabled) {
171 vi->repeat_interval = LOW_REPEAT_KEY_FREQ;
172 zx_timer_set(vi->timer, zx_deadline_after(vi->repeat_interval), 0);
173 } else {
174 vi->repeat_interval = ZX_TIME_INFINITE;
175 }
176 return ZX_OK;
177 }
178 #endif
179
vc_input_create(vc_input_t ** out,keypress_handler_t handler,int fd)180 zx_status_t vc_input_create(vc_input_t** out, keypress_handler_t handler, int fd) {
181 vc_input_t* vi = reinterpret_cast<vc_input_t*>(calloc(1, sizeof(vc_input_t)));
182 if (vi == NULL) {
183 return ZX_ERR_NO_MEMORY;
184 }
185
186 vi->fd = fd;
187 vi->handler = handler;
188
189 vi->cur_idx = 0;
190 vi->prev_idx = 1;
191 vi->modifiers = 0;
192 vi->repeat_interval = ZX_TIME_INFINITE;
193 vi->repeat_enabled = true;
194
195 char* flag = getenv("virtcon.keyrepeat");
196 if (flag && (!strcmp(flag, "0") || !strcmp(flag, "false"))) {
197 printf("vc: Key repeat disabled\n");
198 vi->repeat_enabled = false;
199 }
200
201 #if !BUILD_FOR_TEST
202 zx_status_t r;
203 if ((r = zx_timer_create(0, ZX_CLOCK_MONOTONIC, &vi->timer)) < 0) {
204 free(vi);
205 return r;
206 }
207
208 vi->fh.func = vc_input_cb;
209 if ((r = port_fd_handler_init(&vi->fh, fd, POLLIN | POLLHUP | POLLRDHUP)) < 0) {
210 zx_handle_close(vi->timer);
211 free(vi);
212 return r;
213 }
214
215 if ((r = port_wait(&port, &vi->fh.ph)) < 0) {
216 port_fd_handler_done(&vi->fh);
217 zx_handle_close(vi->timer);
218 free(vi);
219 return r;
220 }
221
222 vi->th.handle = vi->timer;
223 vi->th.waitfor = ZX_TIMER_SIGNALED;
224 vi->th.func = vc_timer_cb;
225 port_wait_repeating(&port, &vi->th);
226 #endif
227
228 *out = vi;
229 return ZX_OK;
230 }
231
232 #if !BUILD_FOR_TEST
new_input_device(int fd,keypress_handler_t handler)233 zx_status_t new_input_device(int fd, keypress_handler_t handler) {
234 // test to see if this is a device we can read
235 uint32_t proto = fuchsia_hardware_input_BootProtocol_NONE;
236
237 // Temporarily wrap fd, we will release it after the call so we don't close it.
238 fzl::FdioCaller caller{fbl::unique_fd(fd)};
239 zx_status_t status =
240 fuchsia_hardware_input_DeviceGetBootProtocol(caller.borrow_channel(), &proto);
241 caller.release().release();
242 if ((status != ZX_OK) || (proto != fuchsia_hardware_input_BootProtocol_KBD)) {
243 // skip devices that aren't keyboards
244 close(fd);
245 return ZX_ERR_NOT_SUPPORTED;
246 }
247
248 vc_input_t* vi;
249 if ((status = vc_input_create(&vi, handler, fd)) < 0) {
250 close(fd);
251 }
252 return status;
253 }
254 #endif
255