1// Copyright 2014 The Chromium 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 "ui/events/ozone/evdev/key_event_converter_evdev.h" 6 7#include <errno.h> 8#include <linux/input.h> 9 10#include "base/message_loop/message_loop.h" 11#include "ui/events/event.h" 12#include "ui/events/keycodes/dom4/keycode_converter.h" 13#include "ui/events/keycodes/keyboard_codes.h" 14#include "ui/events/ozone/evdev/event_modifiers_evdev.h" 15 16namespace ui { 17 18namespace { 19 20const int kXkbKeycodeOffset = 8; 21 22ui::KeyboardCode KeyboardCodeFromButton(unsigned int code) { 23 static const ui::KeyboardCode kLinuxBaseKeyMap[] = { 24 ui::VKEY_UNKNOWN, // KEY_RESERVED 25 ui::VKEY_ESCAPE, // KEY_ESC 26 ui::VKEY_1, // KEY_1 27 ui::VKEY_2, // KEY_2 28 ui::VKEY_3, // KEY_3 29 ui::VKEY_4, // KEY_4 30 ui::VKEY_5, // KEY_5 31 ui::VKEY_6, // KEY_6 32 ui::VKEY_7, // KEY_7 33 ui::VKEY_8, // KEY_8 34 ui::VKEY_9, // KEY_9 35 ui::VKEY_0, // KEY_0 36 ui::VKEY_OEM_MINUS, // KEY_MINUS 37 ui::VKEY_OEM_PLUS, // KEY_EQUAL 38 ui::VKEY_BACK, // KEY_BACKSPACE 39 ui::VKEY_TAB, // KEY_TAB 40 ui::VKEY_Q, // KEY_Q 41 ui::VKEY_W, // KEY_W 42 ui::VKEY_E, // KEY_E 43 ui::VKEY_R, // KEY_R 44 ui::VKEY_T, // KEY_T 45 ui::VKEY_Y, // KEY_Y 46 ui::VKEY_U, // KEY_U 47 ui::VKEY_I, // KEY_I 48 ui::VKEY_O, // KEY_O 49 ui::VKEY_P, // KEY_P 50 ui::VKEY_OEM_4, // KEY_LEFTBRACE 51 ui::VKEY_OEM_6, // KEY_RIGHTBRACE 52 ui::VKEY_RETURN, // KEY_ENTER 53 ui::VKEY_CONTROL, // KEY_LEFTCTRL 54 ui::VKEY_A, // KEY_A 55 ui::VKEY_S, // KEY_S 56 ui::VKEY_D, // KEY_D 57 ui::VKEY_F, // KEY_F 58 ui::VKEY_G, // KEY_G 59 ui::VKEY_H, // KEY_H 60 ui::VKEY_J, // KEY_J 61 ui::VKEY_K, // KEY_K 62 ui::VKEY_L, // KEY_L 63 ui::VKEY_OEM_1, // KEY_SEMICOLON 64 ui::VKEY_OEM_7, // KEY_APOSTROPHE 65 ui::VKEY_OEM_3, // KEY_GRAVE 66 ui::VKEY_SHIFT, // KEY_LEFTSHIFT 67 ui::VKEY_OEM_5, // KEY_BACKSLASH 68 ui::VKEY_Z, // KEY_Z 69 ui::VKEY_X, // KEY_X 70 ui::VKEY_C, // KEY_C 71 ui::VKEY_V, // KEY_V 72 ui::VKEY_B, // KEY_B 73 ui::VKEY_N, // KEY_N 74 ui::VKEY_M, // KEY_M 75 ui::VKEY_OEM_COMMA, // KEY_COMMA 76 ui::VKEY_OEM_PERIOD, // KEY_DOT 77 ui::VKEY_OEM_2, // KEY_SLASH 78 ui::VKEY_SHIFT, // KEY_RIGHTSHIFT 79 ui::VKEY_MULTIPLY, // KEY_KPASTERISK 80 ui::VKEY_MENU, // KEY_LEFTALT 81 ui::VKEY_SPACE, // KEY_SPACE 82 ui::VKEY_CAPITAL, // KEY_CAPSLOCK 83 ui::VKEY_F1, // KEY_F1 84 ui::VKEY_F2, // KEY_F2 85 ui::VKEY_F3, // KEY_F3 86 ui::VKEY_F4, // KEY_F4 87 ui::VKEY_F5, // KEY_F5 88 ui::VKEY_F6, // KEY_F6 89 ui::VKEY_F7, // KEY_F7 90 ui::VKEY_F8, // KEY_F8 91 ui::VKEY_F9, // KEY_F9 92 ui::VKEY_F10, // KEY_F10 93 ui::VKEY_NUMLOCK, // KEY_NUMLOCK 94 ui::VKEY_SCROLL, // KEY_SCROLLLOCK 95 ui::VKEY_NUMPAD7, // KEY_KP7 96 ui::VKEY_NUMPAD8, // KEY_KP8 97 ui::VKEY_NUMPAD9, // KEY_KP9 98 ui::VKEY_SUBTRACT, // KEY_KPMINUS 99 ui::VKEY_NUMPAD4, // KEY_KP4 100 ui::VKEY_NUMPAD5, // KEY_KP5 101 ui::VKEY_NUMPAD6, // KEY_KP6 102 ui::VKEY_ADD, // KEY_KPPLUS 103 ui::VKEY_NUMPAD1, // KEY_KP1 104 ui::VKEY_NUMPAD2, // KEY_KP2 105 ui::VKEY_NUMPAD3, // KEY_KP3 106 ui::VKEY_NUMPAD0, // KEY_KP0 107 ui::VKEY_DECIMAL, // KEY_KPDOT 108 ui::VKEY_UNKNOWN, // (unassigned) 109 ui::VKEY_DBE_DBCSCHAR, // KEY_ZENKAKUHANKAKU 110 ui::VKEY_OEM_102, // KEY_102ND 111 ui::VKEY_F11, // KEY_F11 112 ui::VKEY_F12, // KEY_F12 113 ui::VKEY_UNKNOWN, // KEY_RO 114 ui::VKEY_UNKNOWN, // KEY_KATAKANA 115 ui::VKEY_UNKNOWN, // KEY_HIRAGANA 116 ui::VKEY_CONVERT, // KEY_HENKAN 117 ui::VKEY_UNKNOWN, // KEY_KATAKANAHIRAGANA 118 ui::VKEY_NONCONVERT, // KEY_MUHENKAN 119 ui::VKEY_UNKNOWN, // KEY_KPJPCOMMA 120 ui::VKEY_RETURN, // KEY_KPENTER 121 ui::VKEY_CONTROL, // KEY_RIGHTCTRL 122 ui::VKEY_DIVIDE, // KEY_KPSLASH 123 ui::VKEY_PRINT, // KEY_SYSRQ 124 ui::VKEY_MENU, // KEY_RIGHTALT 125 ui::VKEY_RETURN, // KEY_LINEFEED 126 ui::VKEY_HOME, // KEY_HOME 127 ui::VKEY_UP, // KEY_UP 128 ui::VKEY_PRIOR, // KEY_PAGEUP 129 ui::VKEY_LEFT, // KEY_LEFT 130 ui::VKEY_RIGHT, // KEY_RIGHT 131 ui::VKEY_END, // KEY_END 132 ui::VKEY_DOWN, // KEY_DOWN 133 ui::VKEY_NEXT, // KEY_PAGEDOWN 134 ui::VKEY_INSERT, // KEY_INSERT 135 ui::VKEY_DELETE, // KEY_DELETE 136 ui::VKEY_UNKNOWN, // KEY_MACRO 137 ui::VKEY_VOLUME_MUTE, // KEY_MUTE 138 ui::VKEY_VOLUME_DOWN, // KEY_VOLUMEDOWN 139 ui::VKEY_VOLUME_UP, // KEY_VOLUMEUP 140 ui::VKEY_POWER, // KEY_POWER 141 ui::VKEY_OEM_PLUS, // KEY_KPEQUAL 142 ui::VKEY_UNKNOWN, // KEY_KPPLUSMINUS 143 ui::VKEY_PAUSE, // KEY_PAUSE 144 ui::VKEY_MEDIA_LAUNCH_APP1, // KEY_SCALE 145 ui::VKEY_DECIMAL, // KEY_KPCOMMA 146 ui::VKEY_HANGUL, // KEY_HANGEUL 147 ui::VKEY_HANJA, // KEY_HANJA 148 ui::VKEY_UNKNOWN, // KEY_YEN 149 ui::VKEY_LWIN, // KEY_LEFTMETA 150 ui::VKEY_RWIN, // KEY_RIGHTMETA 151 ui::VKEY_APPS, // KEY_COMPOSE 152 }; 153 154 if (code < arraysize(kLinuxBaseKeyMap)) 155 return kLinuxBaseKeyMap[code]; 156 157 LOG(ERROR) << "Unknown key code: " << code; 158 return ui::VKEY_UNKNOWN; 159} 160 161int ModifierFromButton(unsigned int code) { 162 switch (code) { 163 case KEY_CAPSLOCK: 164 return EVDEV_MODIFIER_CAPS_LOCK; 165 case KEY_LEFTSHIFT: 166 case KEY_RIGHTSHIFT: 167 return EVDEV_MODIFIER_SHIFT; 168 case KEY_LEFTCTRL: 169 case KEY_RIGHTCTRL: 170 return EVDEV_MODIFIER_CONTROL; 171 case KEY_LEFTALT: 172 case KEY_RIGHTALT: 173 return EVDEV_MODIFIER_ALT; 174 case BTN_LEFT: 175 return EVDEV_MODIFIER_LEFT_MOUSE_BUTTON; 176 case BTN_MIDDLE: 177 return EVDEV_MODIFIER_MIDDLE_MOUSE_BUTTON; 178 case BTN_RIGHT: 179 return EVDEV_MODIFIER_RIGHT_MOUSE_BUTTON; 180 case KEY_LEFTMETA: 181 case KEY_RIGHTMETA: 182 return EVDEV_MODIFIER_COMMAND; 183 default: 184 return EVDEV_MODIFIER_NONE; 185 } 186} 187 188bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; } 189 190} // namespace 191 192KeyEventConverterEvdev::KeyEventConverterEvdev( 193 int fd, 194 base::FilePath path, 195 EventModifiersEvdev* modifiers, 196 const EventDispatchCallback& callback) 197 : EventConverterEvdev(fd, path), 198 callback_(callback), 199 modifiers_(modifiers) { 200 // TODO(spang): Initialize modifiers using EVIOCGKEY. 201} 202 203KeyEventConverterEvdev::~KeyEventConverterEvdev() { 204 Stop(); 205 close(fd_); 206} 207 208void KeyEventConverterEvdev::OnFileCanReadWithoutBlocking(int fd) { 209 input_event inputs[4]; 210 ssize_t read_size = read(fd, inputs, sizeof(inputs)); 211 if (read_size < 0) { 212 if (errno == EINTR || errno == EAGAIN) 213 return; 214 if (errno != ENODEV) 215 PLOG(ERROR) << "error reading device " << path_.value(); 216 Stop(); 217 return; 218 } 219 220 DCHECK_EQ(read_size % sizeof(*inputs), 0u); 221 ProcessEvents(inputs, read_size / sizeof(*inputs)); 222} 223 224void KeyEventConverterEvdev::ProcessEvents(const input_event* inputs, 225 int count) { 226 for (int i = 0; i < count; ++i) { 227 const input_event& input = inputs[i]; 228 if (input.type == EV_KEY) { 229 ConvertKeyEvent(input.code, input.value); 230 } else if (input.type == EV_SYN) { 231 // TODO(sadrul): Handle this case appropriately. 232 } 233 } 234} 235 236void KeyEventConverterEvdev::ConvertKeyEvent(int key, int value) { 237 int down = (value != 0); 238 int repeat = (value == 2); 239 int modifier = ModifierFromButton(key); 240 ui::KeyboardCode code = KeyboardCodeFromButton(key); 241 242 if (!repeat && (modifier != EVDEV_MODIFIER_NONE)) { 243 if (IsLockButton(key)) { 244 // Locking modifier keys: CapsLock. 245 modifiers_->UpdateModifierLock(modifier, down); 246 } else { 247 // Regular modifier keys: Shift, Ctrl, Alt, etc. 248 modifiers_->UpdateModifier(modifier, down); 249 } 250 } 251 252 int flags = modifiers_->GetModifierFlags(); 253 254 KeyEvent key_event( 255 down ? ET_KEY_PRESSED : ET_KEY_RELEASED, 256 code, 257 KeycodeConverter::NativeKeycodeToCode(key + kXkbKeycodeOffset), 258 flags); 259 callback_.Run(&key_event); 260} 261 262} // namespace ui 263