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