blob: f72d59e923c01ae6e8ee4c5d34da7a70297f07b7 [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;
David Sodmane0cc8312014-11-18 11:16:36 -080035 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080036};
37
Dominik Behr93899452014-08-18 22:16:21 -070038struct {
39 struct udev *udev;
40 struct udev_monitor *udev_monitor;
41 int udev_fd;
42 unsigned int ndevs;
43 struct input_dev *devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080044 struct keyboard_state kbd_state;
David Sodmanbbcb0522014-09-19 10:34:07 -070045 dbus_t *dbus;
David Sodmanbf3f2842014-11-12 08:26:58 -080046 uint32_t current_terminal;
47 terminal_t *terminals[MAX_TERMINALS];
Dominik Behr93899452014-08-18 22:16:21 -070048} input = {
49 .udev = NULL,
50 .udev_monitor = NULL,
51 .udev_fd = -1,
52 .ndevs = 0,
53 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080054 .dbus = NULL,
55 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070056};
57
David Sodmane0cc8312014-11-18 11:16:36 -080058static void report_user_activity(int activity_type)
59{
60 dbus_method_call1(input.dbus, kPowerManagerServiceName,
61 kPowerManagerServicePath,
62 kPowerManagerInterface,
63 kHandleUserActivityMethod,
64 &activity_type);
65
66 switch (activity_type) {
67 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
68 (void)dbus_method_call0(input.dbus,
69 kPowerManagerServiceName,
70 kPowerManagerServicePath,
71 kPowerManagerInterface,
72 kIncreaseScreenBrightnessMethod);
73 break;
74 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
75 (void)dbus_method_call0(input.dbus,
76 kPowerManagerServiceName,
77 kPowerManagerServicePath,
78 kPowerManagerInterface,
79 kDecreaseScreenBrightnessMethod);
80 break;
81 }
82}
83
David Sodmanbf3f2842014-11-12 08:26:58 -080084static int input_special_key(struct input_key_event *ev)
85{
86 unsigned int i;
87
88 uint32_t ignore_keys[] = {
89 BTN_TOUCH, // touchpad events
90 BTN_TOOL_FINGER,
91 BTN_TOOL_DOUBLETAP,
92 BTN_TOOL_TRIPLETAP,
93 BTN_TOOL_QUADTAP,
94 BTN_TOOL_QUINTTAP,
95 BTN_LEFT, // mouse buttons
96 BTN_RIGHT,
97 BTN_MIDDLE,
98 BTN_SIDE,
99 BTN_EXTRA,
100 BTN_FORWARD,
101 BTN_BACK,
102 BTN_TASK
103 };
104
105 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
106 if (ev->code == ignore_keys[i])
107 return 1;
108
109 switch (ev->code) {
110 case KEY_LEFTSHIFT:
111 case KEY_RIGHTSHIFT:
112 input.kbd_state.shift_state = ! !ev->value;
113 return 1;
114 case KEY_LEFTCTRL:
115 case KEY_RIGHTCTRL:
116 input.kbd_state.control_state = ! !ev->value;
117 return 1;
118 case KEY_LEFTALT:
119 case KEY_RIGHTALT:
120 input.kbd_state.alt_state = ! !ev->value;
121 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800122 case KEY_LEFTMETA: // search key
123 input.kbd_state.search_state = ! !ev->value;
124 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800125 }
126
127 if (input.kbd_state.shift_state && ev->value) {
128 switch (ev->code) {
129 case KEY_PAGEUP:
130 term_page_up(input.terminals[input.current_terminal]);
131 return 1;
132 case KEY_PAGEDOWN:
133 term_page_down(input.terminals[input.current_terminal]);
134 return 1;
135 case KEY_UP:
136 term_line_up(input.terminals[input.current_terminal]);
137 return 1;
138 case KEY_DOWN:
139 term_line_down(input.terminals[input.current_terminal]);
140 return 1;
141 }
142 }
143
David Sodmane0cc8312014-11-18 11:16:36 -0800144 if (input.kbd_state.search_state && ev->value) {
145 switch (ev->code) {
146 case KEY_UP:
147 term_page_up(input.terminals[input.current_terminal]);
148 return 1;
149 case KEY_DOWN:
150 term_page_down(input.terminals[input.current_terminal]);
151 return 1;
152 }
153 }
154
David Sodmanbf3f2842014-11-12 08:26:58 -0800155 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
156 switch (ev->code) {
157 case KEY_F1:
158 input_ungrab();
159 input.terminals[input.current_terminal]->active = false;
160 (void)dbus_method_call0(input.dbus,
161 kLibCrosServiceName,
162 kLibCrosServicePath,
163 kLibCrosServiceInterface,
164 kTakeDisplayOwnership);
165 break;
166 case KEY_F2:
167 case KEY_F3:
168 case KEY_F4:
169 case KEY_F5:
170 case KEY_F6:
171 case KEY_F7:
172 case KEY_F8:
173 case KEY_F9:
174 case KEY_F10:
175 (void)dbus_method_call0(input.dbus,
176 kLibCrosServiceName,
177 kLibCrosServicePath,
178 kLibCrosServiceInterface,
179 kReleaseDisplayOwnership);
180 break;
181 }
182
183 if ((ev->code >= KEY_F2) && (ev->code <= KEY_F4)) {
184 terminal_t* terminal =
185 input.terminals[input.current_terminal];
186 if (term_is_active(terminal))
187 terminal->active = false;
188 input.current_terminal = ev->code - KEY_F2;
189 terminal = input.terminals[input.current_terminal];
190 if (terminal == NULL) {
191 input.terminals[input.current_terminal] =
192 term_init();
193 terminal =
194 input.terminals[input.current_terminal];
195 if (!term_is_valid(terminal)) {
196 LOG(ERROR, "Term init failed");
197 return 1;
198 }
199 }
200 input.terminals[input.current_terminal]->active = true;
201 input_grab();
202 video_setmode(terminal->video);
203 term_redraw(terminal);
204 }
205
206 return 1;
207
208 }
209
David Sodmane0cc8312014-11-18 11:16:36 -0800210 if ((!input.kbd_state.search_state) && ev->value &&
211 (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
212 switch (ev->code) {
213 case KEY_F1:
214 case KEY_F2:
215 case KEY_F3:
216 case KEY_F4:
217 case KEY_F5:
218 break;
219 case KEY_F6:
220 case KEY_F7:
221 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
222 (ev->code - KEY_F6));
223 break;
224 case KEY_F8:
225 case KEY_F9:
226 case KEY_F10:
227 break;
228 }
229 return 1;
230 }
231
David Sodmanbf3f2842014-11-12 08:26:58 -0800232 return 0;
233}
234
235static void input_get_keysym_and_unicode(struct input_key_event *event,
236 uint32_t *keysym, uint32_t *unicode)
237{
238 struct {
239 uint32_t code;
240 uint32_t keysym;
241 } non_ascii_keys[] = {
242 { KEY_ESC, KEYSYM_ESC},
243 { KEY_HOME, KEYSYM_HOME},
244 { KEY_LEFT, KEYSYM_LEFT},
245 { KEY_UP, KEYSYM_UP},
246 { KEY_RIGHT, KEYSYM_RIGHT},
247 { KEY_DOWN, KEYSYM_DOWN},
248 { KEY_PAGEUP, KEYSYM_PAGEUP},
249 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
250 { KEY_END, KEYSYM_END},
251 { KEY_INSERT, KEYSYM_INSERT},
252 { KEY_DELETE, KEYSYM_DELETE},
253 };
254
255 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
256 if (non_ascii_keys[i].code == event->code) {
257 *keysym = non_ascii_keys[i].keysym;
258 *unicode = -1;
259 return;
260 }
261 }
262
263 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
264 *keysym = '?';
265 } else {
266 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
267 if ((input.kbd_state.control_state) && isascii(*keysym))
268 *keysym = tolower(*keysym) - 'a' + 1;
269 }
270
271 *unicode = *keysym;
272}
273
Dominik Behr93899452014-08-18 22:16:21 -0700274static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700275{
Dominik Behr93899452014-08-18 22:16:21 -0700276 int ret = 0, fd = -1;
277 /* for some reason every device has a null enumerations and notifications
278 of every device come with NULL string first */
279 if (!devname) {
280 ret = -EINVAL;
281 goto errorret;
282 }
283 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700284 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700285 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700286
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700287 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
288
289 if (!ret) {
290 ioctl(fd, EVIOCGRAB, (void *) 0);
291 } else {
David Sodmanbbcb0522014-09-19 10:34:07 -0700292 LOG(ERROR, "Evdev device %s grabbed by another process",
Dominik Behr93899452014-08-18 22:16:21 -0700293 devname);
294 ret = -EBUSY;
295 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700296 }
297
Dominik Behr93899452014-08-18 22:16:21 -0700298 struct input_dev *newdevs =
299 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
300 if (!newdevs) {
301 ret = -ENOMEM;
302 goto closefd;
303 }
304 input.devs = newdevs;
305 input.devs[input.ndevs].fd = fd;
306 input.devs[input.ndevs].path = strdup(devname);
307 if (!input.devs[input.ndevs].path) {
308 ret = -ENOMEM;
309 goto closefd;
310 }
311 input.ndevs++;
312
313 return fd;
314
315closefd:
316 close(fd);
317errorret:
318 return ret;
319}
320
321static void input_remove(const char *devname)
322{
323 if (!devname) {
324 return;
325 }
326 unsigned int u;
327 for (u = 0; u < input.ndevs; u++) {
328 if (!strcmp(devname, input.devs[u].path)) {
329 free(input.devs[u].path);
330 close(input.devs[u].fd);
331 input.ndevs--;
332 if (u != input.ndevs) {
333 input.devs[u] = input.devs[input.ndevs];
334 }
335 return;
336 }
337 }
338}
339
Dominik Behr93899452014-08-18 22:16:21 -0700340
341int input_init()
342{
343 input.udev = udev_new();
344 if (!input.udev)
345 return -ENOENT;
346 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
347 if (!input.udev_monitor) {
348 udev_unref(input.udev);
349 return -ENOENT;
350 }
351 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
352 NULL);
353 udev_monitor_enable_receiving(input.udev_monitor);
354 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
355
356 struct udev_enumerate *udev_enum;
357 struct udev_list_entry *devices, *deventry;
358 udev_enum = udev_enumerate_new(input.udev);
359 udev_enumerate_add_match_subsystem(udev_enum, "input");
360 udev_enumerate_scan_devices(udev_enum);
361 devices = udev_enumerate_get_list_entry(udev_enum);
362 udev_list_entry_foreach(deventry, devices) {
363 const char *syspath;
364 struct udev_device *dev;
365 syspath = udev_list_entry_get_name(deventry);
366 dev = udev_device_new_from_syspath(input.udev, syspath);
367 input_add(udev_device_get_devnode(dev));
368 udev_device_unref(dev);
369 }
370 udev_enumerate_unref(udev_enum);
371
372 if (!isatty(fileno(stdout)))
373 setbuf(stdout, NULL);
374
David Sodmanbbcb0522014-09-19 10:34:07 -0700375 if (input.ndevs == 0) {
376 LOG(ERROR, "No valid inputs for terminal");
377 exit(EXIT_SUCCESS);
378 }
379
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700380 return 0;
381}
382
383void input_close()
384{
Dominik Behr93899452014-08-18 22:16:21 -0700385 unsigned int u;
386 for (u = 0; u < input.ndevs; u++) {
387 free(input.devs[u].path);
388 close(input.devs[u].fd);
389 }
390 free(input.devs);
391 input.devs = NULL;
392 input.ndevs = 0;
393
394 udev_monitor_unref(input.udev_monitor);
395 input.udev_monitor = NULL;
396 udev_unref(input.udev);
397 input.udev = NULL;
398 input.udev_fd = -1;
399
David Sodmanbbcb0522014-09-19 10:34:07 -0700400 dbus_destroy(input.dbus);
401
402}
403
404void input_set_dbus(dbus_t* dbus)
405{
406 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700407}
408
Dominik Behr93899452014-08-18 22:16:21 -0700409int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700410{
Dominik Behr93899452014-08-18 22:16:21 -0700411 unsigned int u;
412 int max = -1;
413 for (u = 0; u < input.ndevs; u++) {
414 FD_SET(input.devs[u].fd, read_set);
415 FD_SET(input.devs[u].fd, exception_set);
416 if (input.devs[u].fd > max)
417 max = input.devs[u].fd;
418 }
419
420 FD_SET(input.udev_fd, read_set);
421 FD_SET(input.udev_fd, exception_set);
422 if (input.udev_fd > max)
423 max = input.udev_fd;
424 return max;
425}
426
Dominik Behr93899452014-08-18 22:16:21 -0700427struct input_key_event *input_get_event(fd_set * read_set,
428 fd_set * exception_set)
429{
430 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700431 struct input_event ev;
432 int ret;
433
Dominik Behr93899452014-08-18 22:16:21 -0700434 if (FD_ISSET(input.udev_fd, exception_set)) {
435 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700436 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700437 }
438
Dominik Behr93899452014-08-18 22:16:21 -0700439 if (FD_ISSET(input.udev_fd, read_set)
440 && !FD_ISSET(input.udev_fd, exception_set)) {
441 /* we got an udev notification */
442 struct udev_device *dev =
443 udev_monitor_receive_device(input.udev_monitor);
444 if (dev) {
445 if (!strcmp("add", udev_device_get_action(dev))) {
446 input_add(udev_device_get_devnode(dev));
447 } else
448 if (!strcmp("remove", udev_device_get_action(dev)))
449 {
450 input_remove(udev_device_get_devnode(dev));
451 }
452 udev_device_unref(dev);
453 }
454 }
455
456 for (u = 0; u < input.ndevs; u++) {
457 if (FD_ISSET(input.devs[u].fd, read_set)
458 && !FD_ISSET(input.devs[u].fd, exception_set)) {
459 ret =
460 read(input.devs[u].fd, &ev, sizeof (struct input_event));
461 if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700462 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700463 (int) sizeof (struct input_event), ret);
464 return NULL;
465 }
466
467 if (ev.type == EV_KEY) {
468 struct input_key_event *event =
469 malloc(sizeof (*event));
470 event->code = ev.code;
471 event->value = ev.value;
David Sodmane0cc8312014-11-18 11:16:36 -0800472 report_user_activity(USER_ACTIVITY_OTHER);
Dominik Behr93899452014-08-18 22:16:21 -0700473 return event;
474 }
475 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700476 }
477
478 return NULL;
479}
480
David Sodmanbf3f2842014-11-12 08:26:58 -0800481int input_run(bool standalone)
482{
483 fd_set read_set, exception_set;
484 terminal_t* terminal;
485
486 if (standalone) {
487 (void)dbus_method_call0(input.dbus,
488 kLibCrosServiceName,
489 kLibCrosServicePath,
490 kLibCrosServiceInterface,
491 kReleaseDisplayOwnership);
492
493 input.terminals[input.current_terminal] = term_init();
494 terminal = input.terminals[input.current_terminal];
495 if (term_is_valid(terminal)) {
496 input_grab();
497 }
498 }
499
500 while (1) {
501 terminal = input.terminals[input.current_terminal];
502
503 FD_ZERO(&read_set);
504 FD_ZERO(&exception_set);
505 term_add_fd(terminal, &read_set, &exception_set);
506
507 int maxfd = input_setfds(&read_set, &exception_set);
508
509 maxfd = MAX(maxfd, term_fd(terminal)) + 1;
510
511 select(maxfd, &read_set, NULL, &exception_set, NULL);
512
513 if (term_exception(terminal, &exception_set))
514 return -1;
515
516 struct input_key_event *event;
517 event = input_get_event(&read_set, &exception_set);
518 if (event) {
519 if (!input_special_key(event) && event->value) {
520 uint32_t keysym, unicode;
521 if (term_is_active(terminal)) {
522 input_get_keysym_and_unicode(
523 event, &keysym, &unicode);
524 term_key_event(terminal,
525 keysym, unicode);
526 }
527 }
528
529 input_put_event(event);
530 }
531
532
533 term_dispatch_io(terminal, &read_set);
534
535 if (term_is_valid(terminal)) {
536 if (term_is_child_done(terminal)) {
537 term_close(terminal);
538 input.terminals[input.current_terminal] = term_init();
539 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}