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
16 namespace ui {
17
18 namespace {
19
KeyboardCodeFromButton(unsigned int code)20 ui::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
ModifierFromButton(unsigned int code)159 int 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
IsLockButton(unsigned int code)186 bool IsLockButton(unsigned int code) { return code == KEY_CAPSLOCK; }
187
188 } // namespace
189
KeyEventConverterEvdev(int fd,base::FilePath path,EventModifiersEvdev * modifiers,const EventDispatchCallback & callback)190 KeyEventConverterEvdev::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
~KeyEventConverterEvdev()202 KeyEventConverterEvdev::~KeyEventConverterEvdev() {
203 Stop();
204 close(fd_);
205 }
206
Start()207 void KeyEventConverterEvdev::Start() {
208 base::MessageLoopForUI::current()->WatchFileDescriptor(
209 fd_, true, base::MessagePumpLibevent::WATCH_READ, &controller_, this);
210 }
211
Stop()212 void KeyEventConverterEvdev::Stop() {
213 controller_.StopWatchingFileDescriptor();
214 }
215
OnFileCanReadWithoutBlocking(int fd)216 void 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
OnFileCanWriteWithoutBlocking(int fd)232 void KeyEventConverterEvdev::OnFileCanWriteWithoutBlocking(int fd) {
233 NOTREACHED();
234 }
235
ProcessEvents(const input_event * inputs,int count)236 void 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
ConvertKeyEvent(int key,int value)248 void 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