blob: 3d3fdba18cfa37aaa42c0a214720dc8aa2a48d14 [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>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07009#include <stdint.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
Dominik Behr93899452014-08-18 22:16:21 -070014#include <sys/select.h>
15#include <errno.h>
16#include <libudev.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070017#include "input.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070018#include "dbus_interface.h"
19#include "dbus.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080020#include "keysym.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070021#include "util.h"
Dominik Behr580462b2014-11-20 13:50:05 -080022#include "main.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080023
Dominik Behr93899452014-08-18 22:16:21 -070024struct input_dev {
25 int fd;
26 char *path;
27};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070028
David Sodmanbf3f2842014-11-12 08:26:58 -080029struct keyboard_state {
30 int shift_state;
31 int control_state;
32 int alt_state;
David Sodmane0cc8312014-11-18 11:16:36 -080033 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080034};
35
Dominik Behr93899452014-08-18 22:16:21 -070036struct {
37 struct udev *udev;
38 struct udev_monitor *udev_monitor;
39 int udev_fd;
40 unsigned int ndevs;
41 struct input_dev *devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080042 struct keyboard_state kbd_state;
David Sodmanbbcb0522014-09-19 10:34:07 -070043 dbus_t *dbus;
David Sodmanbf3f2842014-11-12 08:26:58 -080044 uint32_t current_terminal;
45 terminal_t *terminals[MAX_TERMINALS];
Dominik Behr93899452014-08-18 22:16:21 -070046} input = {
47 .udev = NULL,
48 .udev_monitor = NULL,
49 .udev_fd = -1,
50 .ndevs = 0,
51 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080052 .dbus = NULL,
53 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070054};
55
David Sodmane0cc8312014-11-18 11:16:36 -080056static void report_user_activity(int activity_type)
57{
58 dbus_method_call1(input.dbus, kPowerManagerServiceName,
59 kPowerManagerServicePath,
60 kPowerManagerInterface,
61 kHandleUserActivityMethod,
62 &activity_type);
63
64 switch (activity_type) {
65 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
66 (void)dbus_method_call0(input.dbus,
67 kPowerManagerServiceName,
68 kPowerManagerServicePath,
69 kPowerManagerInterface,
70 kIncreaseScreenBrightnessMethod);
71 break;
72 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
73 (void)dbus_method_call0(input.dbus,
74 kPowerManagerServiceName,
75 kPowerManagerServicePath,
76 kPowerManagerInterface,
77 kDecreaseScreenBrightnessMethod);
78 break;
79 }
80}
81
David Sodmanbf3f2842014-11-12 08:26:58 -080082static int input_special_key(struct input_key_event *ev)
83{
84 unsigned int i;
David Sodmanb0697c22014-12-12 10:29:25 -080085 terminal_t *terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080086
87 uint32_t ignore_keys[] = {
88 BTN_TOUCH, // touchpad events
89 BTN_TOOL_FINGER,
90 BTN_TOOL_DOUBLETAP,
91 BTN_TOOL_TRIPLETAP,
92 BTN_TOOL_QUADTAP,
93 BTN_TOOL_QUINTTAP,
94 BTN_LEFT, // mouse buttons
95 BTN_RIGHT,
96 BTN_MIDDLE,
97 BTN_SIDE,
98 BTN_EXTRA,
99 BTN_FORWARD,
100 BTN_BACK,
101 BTN_TASK
102 };
103
David Sodmanafba0d92015-01-27 19:07:46 -0800104 terminal = input.terminals[input.current_terminal];
105
David Sodmanbf3f2842014-11-12 08:26:58 -0800106 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
107 if (ev->code == ignore_keys[i])
108 return 1;
109
110 switch (ev->code) {
111 case KEY_LEFTSHIFT:
112 case KEY_RIGHTSHIFT:
113 input.kbd_state.shift_state = ! !ev->value;
114 return 1;
115 case KEY_LEFTCTRL:
116 case KEY_RIGHTCTRL:
117 input.kbd_state.control_state = ! !ev->value;
118 return 1;
119 case KEY_LEFTALT:
120 case KEY_RIGHTALT:
121 input.kbd_state.alt_state = ! !ev->value;
122 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800123 case KEY_LEFTMETA: // search key
124 input.kbd_state.search_state = ! !ev->value;
125 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800126 }
127
David Sodmanafba0d92015-01-27 19:07:46 -0800128 if (term_is_active(terminal)) {
129 if (input.kbd_state.shift_state && ev->value) {
130 switch (ev->code) {
131 case KEY_PAGEUP:
David Sodmane0cc8312014-11-18 11:16:36 -0800132 term_page_up(input.terminals[input.current_terminal]);
133 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800134 case KEY_PAGEDOWN:
David Sodmane0cc8312014-11-18 11:16:36 -0800135 term_page_down(input.terminals[input.current_terminal]);
136 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800137 case KEY_UP:
138 term_line_up(input.terminals[input.current_terminal]);
139 return 1;
140 case KEY_DOWN:
141 term_line_down(input.terminals[input.current_terminal]);
142 return 1;
143 }
144 }
145
146 if (input.kbd_state.search_state && ev->value) {
147 switch (ev->code) {
148 case KEY_UP:
149 term_page_up(input.terminals[input.current_terminal]);
150 return 1;
151 case KEY_DOWN:
152 term_page_down(input.terminals[input.current_terminal]);
153 return 1;
154 }
155 }
156
157 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
158 input.kbd_state.control_state) &&
159 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
160 switch (ev->code) {
161 case KEY_F1:
162 case KEY_F2:
163 case KEY_F3:
164 case KEY_F4:
165 case KEY_F5:
166 break;
167 case KEY_F6:
168 case KEY_F7:
169 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
170 (ev->code - KEY_F6));
171 break;
172 case KEY_F8:
173 case KEY_F9:
174 case KEY_F10:
175 break;
176 }
177 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800178 }
179 }
180
David Sodmanbf3f2842014-11-12 08:26:58 -0800181 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodmanb0697c22014-12-12 10:29:25 -0800182 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800183 if (term_is_active(terminal)) {
David Sodmanbf3f2842014-11-12 08:26:58 -0800184 input_ungrab();
David Sodmanb0697c22014-12-12 10:29:25 -0800185 terminal->active = false;
David Sodman35d6bd82014-11-24 08:23:00 -0800186 video_release(input.terminals[input.current_terminal]->video);
David Sodmanbf3f2842014-11-12 08:26:58 -0800187 (void)dbus_method_call0(input.dbus,
188 kLibCrosServiceName,
189 kLibCrosServicePath,
190 kLibCrosServiceInterface,
191 kTakeDisplayOwnership);
David Sodmanb0697c22014-12-12 10:29:25 -0800192 }
193 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_TERMINALS)) {
194 (void)dbus_method_call0(input.dbus,
195 kLibCrosServiceName,
196 kLibCrosServicePath,
197 kLibCrosServiceInterface,
198 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800199 if (term_is_active(terminal))
200 terminal->active = false;
201 input.current_terminal = ev->code - KEY_F2;
202 terminal = input.terminals[input.current_terminal];
203 if (terminal == NULL) {
204 input.terminals[input.current_terminal] =
Dominik Behr580462b2014-11-20 13:50:05 -0800205 term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800206 terminal =
207 input.terminals[input.current_terminal];
208 if (!term_is_valid(terminal)) {
209 LOG(ERROR, "Term init failed");
210 return 1;
211 }
212 }
213 input.terminals[input.current_terminal]->active = true;
214 input_grab();
215 video_setmode(terminal->video);
216 term_redraw(terminal);
217 }
218
219 return 1;
220
221 }
222
223 return 0;
224}
225
226static void input_get_keysym_and_unicode(struct input_key_event *event,
227 uint32_t *keysym, uint32_t *unicode)
228{
229 struct {
230 uint32_t code;
231 uint32_t keysym;
232 } non_ascii_keys[] = {
233 { KEY_ESC, KEYSYM_ESC},
234 { KEY_HOME, KEYSYM_HOME},
235 { KEY_LEFT, KEYSYM_LEFT},
236 { KEY_UP, KEYSYM_UP},
237 { KEY_RIGHT, KEYSYM_RIGHT},
238 { KEY_DOWN, KEYSYM_DOWN},
239 { KEY_PAGEUP, KEYSYM_PAGEUP},
240 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
241 { KEY_END, KEYSYM_END},
242 { KEY_INSERT, KEYSYM_INSERT},
243 { KEY_DELETE, KEYSYM_DELETE},
244 };
245
246 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
247 if (non_ascii_keys[i].code == event->code) {
248 *keysym = non_ascii_keys[i].keysym;
249 *unicode = -1;
250 return;
251 }
252 }
253
254 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
255 *keysym = '?';
256 } else {
257 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
258 if ((input.kbd_state.control_state) && isascii(*keysym))
259 *keysym = tolower(*keysym) - 'a' + 1;
260 }
261
262 *unicode = *keysym;
263}
264
Dominik Behr93899452014-08-18 22:16:21 -0700265static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700266{
Dominik Behr93899452014-08-18 22:16:21 -0700267 int ret = 0, fd = -1;
268 /* for some reason every device has a null enumerations and notifications
269 of every device come with NULL string first */
270 if (!devname) {
271 ret = -EINVAL;
272 goto errorret;
273 }
274 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700275 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700276 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700277
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700278 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
279
280 if (!ret) {
281 ioctl(fd, EVIOCGRAB, (void *) 0);
282 } else {
David Sodmanbbcb0522014-09-19 10:34:07 -0700283 LOG(ERROR, "Evdev device %s grabbed by another process",
Dominik Behr93899452014-08-18 22:16:21 -0700284 devname);
285 ret = -EBUSY;
286 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700287 }
288
Dominik Behr93899452014-08-18 22:16:21 -0700289 struct input_dev *newdevs =
290 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
291 if (!newdevs) {
292 ret = -ENOMEM;
293 goto closefd;
294 }
295 input.devs = newdevs;
296 input.devs[input.ndevs].fd = fd;
297 input.devs[input.ndevs].path = strdup(devname);
298 if (!input.devs[input.ndevs].path) {
299 ret = -ENOMEM;
300 goto closefd;
301 }
302 input.ndevs++;
303
304 return fd;
305
306closefd:
307 close(fd);
308errorret:
309 return ret;
310}
311
312static void input_remove(const char *devname)
313{
314 if (!devname) {
315 return;
316 }
317 unsigned int u;
318 for (u = 0; u < input.ndevs; u++) {
319 if (!strcmp(devname, input.devs[u].path)) {
320 free(input.devs[u].path);
321 close(input.devs[u].fd);
322 input.ndevs--;
323 if (u != input.ndevs) {
324 input.devs[u] = input.devs[input.ndevs];
325 }
326 return;
327 }
328 }
329}
330
Dominik Behr93899452014-08-18 22:16:21 -0700331
332int input_init()
333{
334 input.udev = udev_new();
335 if (!input.udev)
336 return -ENOENT;
337 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
338 if (!input.udev_monitor) {
339 udev_unref(input.udev);
340 return -ENOENT;
341 }
342 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
343 NULL);
344 udev_monitor_enable_receiving(input.udev_monitor);
345 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
346
347 struct udev_enumerate *udev_enum;
348 struct udev_list_entry *devices, *deventry;
349 udev_enum = udev_enumerate_new(input.udev);
350 udev_enumerate_add_match_subsystem(udev_enum, "input");
351 udev_enumerate_scan_devices(udev_enum);
352 devices = udev_enumerate_get_list_entry(udev_enum);
353 udev_list_entry_foreach(deventry, devices) {
354 const char *syspath;
355 struct udev_device *dev;
356 syspath = udev_list_entry_get_name(deventry);
357 dev = udev_device_new_from_syspath(input.udev, syspath);
358 input_add(udev_device_get_devnode(dev));
359 udev_device_unref(dev);
360 }
361 udev_enumerate_unref(udev_enum);
362
363 if (!isatty(fileno(stdout)))
364 setbuf(stdout, NULL);
365
David Sodmanbbcb0522014-09-19 10:34:07 -0700366 if (input.ndevs == 0) {
367 LOG(ERROR, "No valid inputs for terminal");
368 exit(EXIT_SUCCESS);
369 }
370
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700371 return 0;
372}
373
374void input_close()
375{
Dominik Behr93899452014-08-18 22:16:21 -0700376 unsigned int u;
377 for (u = 0; u < input.ndevs; u++) {
378 free(input.devs[u].path);
379 close(input.devs[u].fd);
380 }
381 free(input.devs);
382 input.devs = NULL;
383 input.ndevs = 0;
384
385 udev_monitor_unref(input.udev_monitor);
386 input.udev_monitor = NULL;
387 udev_unref(input.udev);
388 input.udev = NULL;
389 input.udev_fd = -1;
390
David Sodmanbbcb0522014-09-19 10:34:07 -0700391 dbus_destroy(input.dbus);
392
393}
394
395void input_set_dbus(dbus_t* dbus)
396{
397 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700398}
399
Dominik Behr93899452014-08-18 22:16:21 -0700400int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700401{
Dominik Behr93899452014-08-18 22:16:21 -0700402 unsigned int u;
403 int max = -1;
404 for (u = 0; u < input.ndevs; u++) {
405 FD_SET(input.devs[u].fd, read_set);
406 FD_SET(input.devs[u].fd, exception_set);
407 if (input.devs[u].fd > max)
408 max = input.devs[u].fd;
409 }
410
411 FD_SET(input.udev_fd, read_set);
412 FD_SET(input.udev_fd, exception_set);
413 if (input.udev_fd > max)
414 max = input.udev_fd;
415 return max;
416}
417
Dominik Behr93899452014-08-18 22:16:21 -0700418struct input_key_event *input_get_event(fd_set * read_set,
419 fd_set * exception_set)
420{
421 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700422 struct input_event ev;
423 int ret;
424
Dominik Behr93899452014-08-18 22:16:21 -0700425 if (FD_ISSET(input.udev_fd, exception_set)) {
426 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700427 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700428 }
429
Dominik Behr93899452014-08-18 22:16:21 -0700430 if (FD_ISSET(input.udev_fd, read_set)
431 && !FD_ISSET(input.udev_fd, exception_set)) {
432 /* we got an udev notification */
433 struct udev_device *dev =
434 udev_monitor_receive_device(input.udev_monitor);
435 if (dev) {
436 if (!strcmp("add", udev_device_get_action(dev))) {
437 input_add(udev_device_get_devnode(dev));
438 } else
439 if (!strcmp("remove", udev_device_get_action(dev)))
440 {
441 input_remove(udev_device_get_devnode(dev));
442 }
443 udev_device_unref(dev);
444 }
445 }
446
447 for (u = 0; u < input.ndevs; u++) {
448 if (FD_ISSET(input.devs[u].fd, read_set)
449 && !FD_ISSET(input.devs[u].fd, exception_set)) {
450 ret =
451 read(input.devs[u].fd, &ev, sizeof (struct input_event));
452 if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700453 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700454 (int) sizeof (struct input_event), ret);
455 return NULL;
456 }
457
458 if (ev.type == EV_KEY) {
459 struct input_key_event *event =
460 malloc(sizeof (*event));
461 event->code = ev.code;
462 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700463 return event;
464 }
465 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700466 }
467
468 return NULL;
469}
470
David Sodmanbf3f2842014-11-12 08:26:58 -0800471int input_run(bool standalone)
472{
473 fd_set read_set, exception_set;
474 terminal_t* terminal;
475
476 if (standalone) {
477 (void)dbus_method_call0(input.dbus,
478 kLibCrosServiceName,
479 kLibCrosServicePath,
480 kLibCrosServiceInterface,
481 kReleaseDisplayOwnership);
482
Dominik Behr580462b2014-11-20 13:50:05 -0800483 input.terminals[input.current_terminal] = term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800484 terminal = input.terminals[input.current_terminal];
485 if (term_is_valid(terminal)) {
486 input_grab();
487 }
488 }
489
490 while (1) {
491 terminal = input.terminals[input.current_terminal];
492
493 FD_ZERO(&read_set);
494 FD_ZERO(&exception_set);
495 term_add_fd(terminal, &read_set, &exception_set);
496
497 int maxfd = input_setfds(&read_set, &exception_set);
498
499 maxfd = MAX(maxfd, term_fd(terminal)) + 1;
500
501 select(maxfd, &read_set, NULL, &exception_set, NULL);
502
503 if (term_exception(terminal, &exception_set))
504 return -1;
505
David Sodmanafba0d92015-01-27 19:07:46 -0800506 struct input_key_event *event;
507 event = input_get_event(&read_set, &exception_set);
508 if (event) {
509 if (!input_special_key(event) && event->value) {
510 uint32_t keysym, unicode;
511 // current_terminal can possibly change during
512 // execution of input_special_key
513 terminal = input.terminals[input.current_terminal];
514 if (term_is_active(terminal)) {
515 // Only report user activity when the terminal is active
516 report_user_activity(USER_ACTIVITY_OTHER);
517 input_get_keysym_and_unicode(
518 event, &keysym, &unicode);
519 term_key_event(terminal,
520 keysym, unicode);
David Sodmanbf3f2842014-11-12 08:26:58 -0800521 }
522 }
David Sodmanafba0d92015-01-27 19:07:46 -0800523 input_put_event(event);
David Sodmanbf3f2842014-11-12 08:26:58 -0800524 }
525
David Sodmanbf3f2842014-11-12 08:26:58 -0800526 term_dispatch_io(terminal, &read_set);
527
528 if (term_is_valid(terminal)) {
529 if (term_is_child_done(terminal)) {
David Sodman5e5c37e2014-12-19 14:14:46 -0800530 if (terminal->video) {
531 // necessary in case chrome is playing full screen
532 // video or graphics
533 //TODO: This is still a race with Chrome. This
534 //needs to be fixed with bug 444209
535 video_setmode(terminal->video);
536 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800537 term_close(terminal);
Dominik Behr580462b2014-11-20 13:50:05 -0800538 input.terminals[input.current_terminal] = term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800539 terminal = input.terminals[input.current_terminal];
540 if (!term_is_valid(terminal)) {
541 return -1;
542 }
543 }
544 }
545 }
546
547 return 0;
548}
549
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700550void input_put_event(struct input_key_event *event)
551{
552 free(event);
553}
David Sodmanbbcb0522014-09-19 10:34:07 -0700554
555void input_grab()
556{
557 unsigned int i;
558 for (i = 0; i < input.ndevs; i++) {
559 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void *) 1);
560 }
561}
562
563void input_ungrab()
564{
565 unsigned int i;
566 for (i = 0; i < input.ndevs; i++) {
567 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void*) 0);
568 }
569}