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