blob: 23864caefb97f7f82db4b4e713a7724b438eb73f [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
David Sodmanbf3f2842014-11-12 08:26:58 -08007#include <ctype.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07008#include <fcntl.h>
9#include <libtsm.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
Dominik Behr93899452014-08-18 22:16:21 -070015#include <sys/select.h>
16#include <errno.h>
17#include <libudev.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070018#include "input.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070019#include "dbus_interface.h"
20#include "dbus.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080021#include "keysym.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022#include "util.h"
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070023
David Sodmanbf3f2842014-11-12 08:26:58 -080024#define MAX_TERMINALS (5)
25
Dominik Behr93899452014-08-18 22:16:21 -070026struct input_dev {
27 int fd;
28 char *path;
29};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070030
David Sodmanbf3f2842014-11-12 08:26:58 -080031struct keyboard_state {
32 int shift_state;
33 int control_state;
34 int alt_state;
35};
36
Dominik Behr93899452014-08-18 22:16:21 -070037struct {
38 struct udev *udev;
39 struct udev_monitor *udev_monitor;
40 int udev_fd;
41 unsigned int ndevs;
42 struct input_dev *devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080043 struct keyboard_state kbd_state;
David Sodmanbbcb0522014-09-19 10:34:07 -070044 dbus_t *dbus;
David Sodmanbf3f2842014-11-12 08:26:58 -080045 uint32_t current_terminal;
46 terminal_t *terminals[MAX_TERMINALS];
Dominik Behr93899452014-08-18 22:16:21 -070047} input = {
48 .udev = NULL,
49 .udev_monitor = NULL,
50 .udev_fd = -1,
51 .ndevs = 0,
52 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080053 .dbus = NULL,
54 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070055};
56
David Sodmanbf3f2842014-11-12 08:26:58 -080057static int input_special_key(struct input_key_event *ev)
58{
59 unsigned int i;
60
61 uint32_t ignore_keys[] = {
62 BTN_TOUCH, // touchpad events
63 BTN_TOOL_FINGER,
64 BTN_TOOL_DOUBLETAP,
65 BTN_TOOL_TRIPLETAP,
66 BTN_TOOL_QUADTAP,
67 BTN_TOOL_QUINTTAP,
68 BTN_LEFT, // mouse buttons
69 BTN_RIGHT,
70 BTN_MIDDLE,
71 BTN_SIDE,
72 BTN_EXTRA,
73 BTN_FORWARD,
74 BTN_BACK,
75 BTN_TASK
76 };
77
78 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
79 if (ev->code == ignore_keys[i])
80 return 1;
81
82 switch (ev->code) {
83 case KEY_LEFTSHIFT:
84 case KEY_RIGHTSHIFT:
85 input.kbd_state.shift_state = ! !ev->value;
86 return 1;
87 case KEY_LEFTCTRL:
88 case KEY_RIGHTCTRL:
89 input.kbd_state.control_state = ! !ev->value;
90 return 1;
91 case KEY_LEFTALT:
92 case KEY_RIGHTALT:
93 input.kbd_state.alt_state = ! !ev->value;
94 return 1;
95 }
96
97 if (input.kbd_state.shift_state && ev->value) {
98 switch (ev->code) {
99 case KEY_PAGEUP:
100 term_page_up(input.terminals[input.current_terminal]);
101 return 1;
102 case KEY_PAGEDOWN:
103 term_page_down(input.terminals[input.current_terminal]);
104 return 1;
105 case KEY_UP:
106 term_line_up(input.terminals[input.current_terminal]);
107 return 1;
108 case KEY_DOWN:
109 term_line_down(input.terminals[input.current_terminal]);
110 return 1;
111 }
112 }
113
114 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
115 switch (ev->code) {
116 case KEY_F1:
117 input_ungrab();
118 input.terminals[input.current_terminal]->active = false;
119 (void)dbus_method_call0(input.dbus,
120 kLibCrosServiceName,
121 kLibCrosServicePath,
122 kLibCrosServiceInterface,
123 kTakeDisplayOwnership);
124 break;
125 case KEY_F2:
126 case KEY_F3:
127 case KEY_F4:
128 case KEY_F5:
129 case KEY_F6:
130 case KEY_F7:
131 case KEY_F8:
132 case KEY_F9:
133 case KEY_F10:
134 (void)dbus_method_call0(input.dbus,
135 kLibCrosServiceName,
136 kLibCrosServicePath,
137 kLibCrosServiceInterface,
138 kReleaseDisplayOwnership);
139 break;
140 }
141
142 if ((ev->code >= KEY_F2) && (ev->code <= KEY_F4)) {
143 terminal_t* terminal =
144 input.terminals[input.current_terminal];
145 if (term_is_active(terminal))
146 terminal->active = false;
147 input.current_terminal = ev->code - KEY_F2;
148 terminal = input.terminals[input.current_terminal];
149 if (terminal == NULL) {
150 input.terminals[input.current_terminal] =
151 term_init();
152 terminal =
153 input.terminals[input.current_terminal];
154 if (!term_is_valid(terminal)) {
155 LOG(ERROR, "Term init failed");
156 return 1;
157 }
158 }
159 input.terminals[input.current_terminal]->active = true;
160 input_grab();
161 video_setmode(terminal->video);
162 term_redraw(terminal);
163 }
164
165 return 1;
166
167 }
168
169 return 0;
170}
171
172static void input_get_keysym_and_unicode(struct input_key_event *event,
173 uint32_t *keysym, uint32_t *unicode)
174{
175 struct {
176 uint32_t code;
177 uint32_t keysym;
178 } non_ascii_keys[] = {
179 { KEY_ESC, KEYSYM_ESC},
180 { KEY_HOME, KEYSYM_HOME},
181 { KEY_LEFT, KEYSYM_LEFT},
182 { KEY_UP, KEYSYM_UP},
183 { KEY_RIGHT, KEYSYM_RIGHT},
184 { KEY_DOWN, KEYSYM_DOWN},
185 { KEY_PAGEUP, KEYSYM_PAGEUP},
186 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
187 { KEY_END, KEYSYM_END},
188 { KEY_INSERT, KEYSYM_INSERT},
189 { KEY_DELETE, KEYSYM_DELETE},
190 };
191
192 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
193 if (non_ascii_keys[i].code == event->code) {
194 *keysym = non_ascii_keys[i].keysym;
195 *unicode = -1;
196 return;
197 }
198 }
199
200 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
201 *keysym = '?';
202 } else {
203 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
204 if ((input.kbd_state.control_state) && isascii(*keysym))
205 *keysym = tolower(*keysym) - 'a' + 1;
206 }
207
208 *unicode = *keysym;
209}
210
Dominik Behr93899452014-08-18 22:16:21 -0700211static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700212{
Dominik Behr93899452014-08-18 22:16:21 -0700213 int ret = 0, fd = -1;
214 /* for some reason every device has a null enumerations and notifications
215 of every device come with NULL string first */
216 if (!devname) {
217 ret = -EINVAL;
218 goto errorret;
219 }
220 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700221 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700222 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700223
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700224 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
225
226 if (!ret) {
227 ioctl(fd, EVIOCGRAB, (void *) 0);
228 } else {
David Sodmanbbcb0522014-09-19 10:34:07 -0700229 LOG(ERROR, "Evdev device %s grabbed by another process",
Dominik Behr93899452014-08-18 22:16:21 -0700230 devname);
231 ret = -EBUSY;
232 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700233 }
234
Dominik Behr93899452014-08-18 22:16:21 -0700235 struct input_dev *newdevs =
236 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
237 if (!newdevs) {
238 ret = -ENOMEM;
239 goto closefd;
240 }
241 input.devs = newdevs;
242 input.devs[input.ndevs].fd = fd;
243 input.devs[input.ndevs].path = strdup(devname);
244 if (!input.devs[input.ndevs].path) {
245 ret = -ENOMEM;
246 goto closefd;
247 }
248 input.ndevs++;
249
250 return fd;
251
252closefd:
253 close(fd);
254errorret:
255 return ret;
256}
257
258static void input_remove(const char *devname)
259{
260 if (!devname) {
261 return;
262 }
263 unsigned int u;
264 for (u = 0; u < input.ndevs; u++) {
265 if (!strcmp(devname, input.devs[u].path)) {
266 free(input.devs[u].path);
267 close(input.devs[u].fd);
268 input.ndevs--;
269 if (u != input.ndevs) {
270 input.devs[u] = input.devs[input.ndevs];
271 }
272 return;
273 }
274 }
275}
276
Dominik Behr93899452014-08-18 22:16:21 -0700277
278int input_init()
279{
280 input.udev = udev_new();
281 if (!input.udev)
282 return -ENOENT;
283 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
284 if (!input.udev_monitor) {
285 udev_unref(input.udev);
286 return -ENOENT;
287 }
288 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
289 NULL);
290 udev_monitor_enable_receiving(input.udev_monitor);
291 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
292
293 struct udev_enumerate *udev_enum;
294 struct udev_list_entry *devices, *deventry;
295 udev_enum = udev_enumerate_new(input.udev);
296 udev_enumerate_add_match_subsystem(udev_enum, "input");
297 udev_enumerate_scan_devices(udev_enum);
298 devices = udev_enumerate_get_list_entry(udev_enum);
299 udev_list_entry_foreach(deventry, devices) {
300 const char *syspath;
301 struct udev_device *dev;
302 syspath = udev_list_entry_get_name(deventry);
303 dev = udev_device_new_from_syspath(input.udev, syspath);
304 input_add(udev_device_get_devnode(dev));
305 udev_device_unref(dev);
306 }
307 udev_enumerate_unref(udev_enum);
308
309 if (!isatty(fileno(stdout)))
310 setbuf(stdout, NULL);
311
David Sodmanbbcb0522014-09-19 10:34:07 -0700312 if (input.ndevs == 0) {
313 LOG(ERROR, "No valid inputs for terminal");
314 exit(EXIT_SUCCESS);
315 }
316
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700317 return 0;
318}
319
320void input_close()
321{
Dominik Behr93899452014-08-18 22:16:21 -0700322 unsigned int u;
323 for (u = 0; u < input.ndevs; u++) {
324 free(input.devs[u].path);
325 close(input.devs[u].fd);
326 }
327 free(input.devs);
328 input.devs = NULL;
329 input.ndevs = 0;
330
331 udev_monitor_unref(input.udev_monitor);
332 input.udev_monitor = NULL;
333 udev_unref(input.udev);
334 input.udev = NULL;
335 input.udev_fd = -1;
336
David Sodmanbbcb0522014-09-19 10:34:07 -0700337 dbus_destroy(input.dbus);
338
339}
340
341void input_set_dbus(dbus_t* dbus)
342{
343 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700344}
345
Dominik Behr93899452014-08-18 22:16:21 -0700346int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700347{
Dominik Behr93899452014-08-18 22:16:21 -0700348 unsigned int u;
349 int max = -1;
350 for (u = 0; u < input.ndevs; u++) {
351 FD_SET(input.devs[u].fd, read_set);
352 FD_SET(input.devs[u].fd, exception_set);
353 if (input.devs[u].fd > max)
354 max = input.devs[u].fd;
355 }
356
357 FD_SET(input.udev_fd, read_set);
358 FD_SET(input.udev_fd, exception_set);
359 if (input.udev_fd > max)
360 max = input.udev_fd;
361 return max;
362}
363
364static void report_user_activity(void)
365{
David Sodmanbbcb0522014-09-19 10:34:07 -0700366 int activity_type = USER_ACTIVITY_OTHER;
Dominik Behr93899452014-08-18 22:16:21 -0700367
David Sodman003faed2014-11-03 09:02:10 -0800368 dbus_method_call1(input.dbus, kPowerManagerServiceName,
David Sodmanbbcb0522014-09-19 10:34:07 -0700369 kPowerManagerServicePath,
370 kPowerManagerInterface,
371 kHandleUserActivityMethod,
372 &activity_type);
Dominik Behr93899452014-08-18 22:16:21 -0700373
David Sodmanbbcb0522014-09-19 10:34:07 -0700374 (void)dbus_message_new_method_call(kPowerManagerServiceName,
David Sodmanbf3f2842014-11-12 08:26:58 -0800375 kPowerManagerServicePath,
376 kPowerManagerInterface,
377 kHandleUserActivityMethod);
David Sodmanbbcb0522014-09-19 10:34:07 -0700378
Dominik Behr93899452014-08-18 22:16:21 -0700379}
380
381struct input_key_event *input_get_event(fd_set * read_set,
382 fd_set * exception_set)
383{
384 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700385 struct input_event ev;
386 int ret;
387
Dominik Behr93899452014-08-18 22:16:21 -0700388 if (FD_ISSET(input.udev_fd, exception_set)) {
389 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700390 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700391 }
392
Dominik Behr93899452014-08-18 22:16:21 -0700393 if (FD_ISSET(input.udev_fd, read_set)
394 && !FD_ISSET(input.udev_fd, exception_set)) {
395 /* we got an udev notification */
396 struct udev_device *dev =
397 udev_monitor_receive_device(input.udev_monitor);
398 if (dev) {
399 if (!strcmp("add", udev_device_get_action(dev))) {
400 input_add(udev_device_get_devnode(dev));
401 } else
402 if (!strcmp("remove", udev_device_get_action(dev)))
403 {
404 input_remove(udev_device_get_devnode(dev));
405 }
406 udev_device_unref(dev);
407 }
408 }
409
410 for (u = 0; u < input.ndevs; u++) {
411 if (FD_ISSET(input.devs[u].fd, read_set)
412 && !FD_ISSET(input.devs[u].fd, exception_set)) {
413 ret =
414 read(input.devs[u].fd, &ev, sizeof (struct input_event));
415 if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700416 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700417 (int) sizeof (struct input_event), ret);
418 return NULL;
419 }
420
421 if (ev.type == EV_KEY) {
422 struct input_key_event *event =
423 malloc(sizeof (*event));
424 event->code = ev.code;
425 event->value = ev.value;
426 report_user_activity();
427 return event;
428 }
429 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700430 }
431
432 return NULL;
433}
434
David Sodmanbf3f2842014-11-12 08:26:58 -0800435int input_run(bool standalone)
436{
437 fd_set read_set, exception_set;
438 terminal_t* terminal;
439
440 if (standalone) {
441 (void)dbus_method_call0(input.dbus,
442 kLibCrosServiceName,
443 kLibCrosServicePath,
444 kLibCrosServiceInterface,
445 kReleaseDisplayOwnership);
446
447 input.terminals[input.current_terminal] = term_init();
448 terminal = input.terminals[input.current_terminal];
449 if (term_is_valid(terminal)) {
450 input_grab();
451 }
452 }
453
454 while (1) {
455 terminal = input.terminals[input.current_terminal];
456
457 FD_ZERO(&read_set);
458 FD_ZERO(&exception_set);
459 term_add_fd(terminal, &read_set, &exception_set);
460
461 int maxfd = input_setfds(&read_set, &exception_set);
462
463 maxfd = MAX(maxfd, term_fd(terminal)) + 1;
464
465 select(maxfd, &read_set, NULL, &exception_set, NULL);
466
467 if (term_exception(terminal, &exception_set))
468 return -1;
469
470 struct input_key_event *event;
471 event = input_get_event(&read_set, &exception_set);
472 if (event) {
473 if (!input_special_key(event) && event->value) {
474 uint32_t keysym, unicode;
475 if (term_is_active(terminal)) {
476 input_get_keysym_and_unicode(
477 event, &keysym, &unicode);
478 term_key_event(terminal,
479 keysym, unicode);
480 }
481 }
482
483 input_put_event(event);
484 }
485
486
487 term_dispatch_io(terminal, &read_set);
488
489 if (term_is_valid(terminal)) {
490 if (term_is_child_done(terminal)) {
491 term_close(terminal);
492 input.terminals[input.current_terminal] = term_init();
493 terminal = input.terminals[input.current_terminal];
494 if (!term_is_valid(terminal)) {
495 return -1;
496 }
497 }
498 }
499 }
500
501 return 0;
502}
503
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700504void input_put_event(struct input_key_event *event)
505{
506 free(event);
507}
David Sodmanbbcb0522014-09-19 10:34:07 -0700508
509void input_grab()
510{
511 unsigned int i;
512 for (i = 0; i < input.ndevs; i++) {
513 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void *) 1);
514 }
515}
516
517void input_ungrab()
518{
519 unsigned int i;
520 for (i = 0; i < input.ndevs; i++) {
521 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void*) 0);
522 }
523}