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