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