blob: f161687db28828edf74383d66e55ce5ae975d952 [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 Behr5d3a8a72014-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;
85
86 uint32_t ignore_keys[] = {
87 BTN_TOUCH, // touchpad events
88 BTN_TOOL_FINGER,
89 BTN_TOOL_DOUBLETAP,
90 BTN_TOOL_TRIPLETAP,
91 BTN_TOOL_QUADTAP,
92 BTN_TOOL_QUINTTAP,
93 BTN_LEFT, // mouse buttons
94 BTN_RIGHT,
95 BTN_MIDDLE,
96 BTN_SIDE,
97 BTN_EXTRA,
98 BTN_FORWARD,
99 BTN_BACK,
100 BTN_TASK
101 };
102
103 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
104 if (ev->code == ignore_keys[i])
105 return 1;
106
107 switch (ev->code) {
108 case KEY_LEFTSHIFT:
109 case KEY_RIGHTSHIFT:
110 input.kbd_state.shift_state = ! !ev->value;
111 return 1;
112 case KEY_LEFTCTRL:
113 case KEY_RIGHTCTRL:
114 input.kbd_state.control_state = ! !ev->value;
115 return 1;
116 case KEY_LEFTALT:
117 case KEY_RIGHTALT:
118 input.kbd_state.alt_state = ! !ev->value;
119 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800120 case KEY_LEFTMETA: // search key
121 input.kbd_state.search_state = ! !ev->value;
122 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800123 }
124
125 if (input.kbd_state.shift_state && ev->value) {
126 switch (ev->code) {
127 case KEY_PAGEUP:
128 term_page_up(input.terminals[input.current_terminal]);
129 return 1;
130 case KEY_PAGEDOWN:
131 term_page_down(input.terminals[input.current_terminal]);
132 return 1;
133 case KEY_UP:
134 term_line_up(input.terminals[input.current_terminal]);
135 return 1;
136 case KEY_DOWN:
137 term_line_down(input.terminals[input.current_terminal]);
138 return 1;
139 }
140 }
141
David Sodmane0cc8312014-11-18 11:16:36 -0800142 if (input.kbd_state.search_state && ev->value) {
143 switch (ev->code) {
144 case KEY_UP:
145 term_page_up(input.terminals[input.current_terminal]);
146 return 1;
147 case KEY_DOWN:
148 term_page_down(input.terminals[input.current_terminal]);
149 return 1;
150 }
151 }
152
David Sodmanbf3f2842014-11-12 08:26:58 -0800153 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
154 switch (ev->code) {
155 case KEY_F1:
156 input_ungrab();
157 input.terminals[input.current_terminal]->active = false;
158 (void)dbus_method_call0(input.dbus,
159 kLibCrosServiceName,
160 kLibCrosServicePath,
161 kLibCrosServiceInterface,
162 kTakeDisplayOwnership);
163 break;
164 case KEY_F2:
165 case KEY_F3:
166 case KEY_F4:
167 case KEY_F5:
168 case KEY_F6:
169 case KEY_F7:
170 case KEY_F8:
171 case KEY_F9:
172 case KEY_F10:
173 (void)dbus_method_call0(input.dbus,
174 kLibCrosServiceName,
175 kLibCrosServicePath,
176 kLibCrosServiceInterface,
177 kReleaseDisplayOwnership);
178 break;
179 }
180
181 if ((ev->code >= KEY_F2) && (ev->code <= KEY_F4)) {
182 terminal_t* terminal =
183 input.terminals[input.current_terminal];
184 if (term_is_active(terminal))
185 terminal->active = false;
186 input.current_terminal = ev->code - KEY_F2;
187 terminal = input.terminals[input.current_terminal];
188 if (terminal == NULL) {
189 input.terminals[input.current_terminal] =
Dominik Behr5d3a8a72014-11-20 13:50:05 -0800190 term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800191 terminal =
192 input.terminals[input.current_terminal];
193 if (!term_is_valid(terminal)) {
194 LOG(ERROR, "Term init failed");
195 return 1;
196 }
197 }
198 input.terminals[input.current_terminal]->active = true;
199 input_grab();
200 video_setmode(terminal->video);
201 term_redraw(terminal);
202 }
203
204 return 1;
205
206 }
207
David Sodmane0cc8312014-11-18 11:16:36 -0800208 if ((!input.kbd_state.search_state) && ev->value &&
209 (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
210 switch (ev->code) {
211 case KEY_F1:
212 case KEY_F2:
213 case KEY_F3:
214 case KEY_F4:
215 case KEY_F5:
216 break;
217 case KEY_F6:
218 case KEY_F7:
219 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
220 (ev->code - KEY_F6));
221 break;
222 case KEY_F8:
223 case KEY_F9:
224 case KEY_F10:
225 break;
226 }
227 return 1;
228 }
229
David Sodmanbf3f2842014-11-12 08:26:58 -0800230 return 0;
231}
232
233static void input_get_keysym_and_unicode(struct input_key_event *event,
234 uint32_t *keysym, uint32_t *unicode)
235{
236 struct {
237 uint32_t code;
238 uint32_t keysym;
239 } non_ascii_keys[] = {
240 { KEY_ESC, KEYSYM_ESC},
241 { KEY_HOME, KEYSYM_HOME},
242 { KEY_LEFT, KEYSYM_LEFT},
243 { KEY_UP, KEYSYM_UP},
244 { KEY_RIGHT, KEYSYM_RIGHT},
245 { KEY_DOWN, KEYSYM_DOWN},
246 { KEY_PAGEUP, KEYSYM_PAGEUP},
247 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
248 { KEY_END, KEYSYM_END},
249 { KEY_INSERT, KEYSYM_INSERT},
250 { KEY_DELETE, KEYSYM_DELETE},
251 };
252
253 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
254 if (non_ascii_keys[i].code == event->code) {
255 *keysym = non_ascii_keys[i].keysym;
256 *unicode = -1;
257 return;
258 }
259 }
260
261 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
262 *keysym = '?';
263 } else {
264 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
265 if ((input.kbd_state.control_state) && isascii(*keysym))
266 *keysym = tolower(*keysym) - 'a' + 1;
267 }
268
269 *unicode = *keysym;
270}
271
Dominik Behr93899452014-08-18 22:16:21 -0700272static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700273{
Dominik Behr93899452014-08-18 22:16:21 -0700274 int ret = 0, fd = -1;
275 /* for some reason every device has a null enumerations and notifications
276 of every device come with NULL string first */
277 if (!devname) {
278 ret = -EINVAL;
279 goto errorret;
280 }
281 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700282 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700283 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700284
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700285 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
286
287 if (!ret) {
288 ioctl(fd, EVIOCGRAB, (void *) 0);
289 } else {
David Sodmanbbcb0522014-09-19 10:34:07 -0700290 LOG(ERROR, "Evdev device %s grabbed by another process",
Dominik Behr93899452014-08-18 22:16:21 -0700291 devname);
292 ret = -EBUSY;
293 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700294 }
295
Dominik Behr93899452014-08-18 22:16:21 -0700296 struct input_dev *newdevs =
297 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
298 if (!newdevs) {
299 ret = -ENOMEM;
300 goto closefd;
301 }
302 input.devs = newdevs;
303 input.devs[input.ndevs].fd = fd;
304 input.devs[input.ndevs].path = strdup(devname);
305 if (!input.devs[input.ndevs].path) {
306 ret = -ENOMEM;
307 goto closefd;
308 }
309 input.ndevs++;
310
311 return fd;
312
313closefd:
314 close(fd);
315errorret:
316 return ret;
317}
318
319static void input_remove(const char *devname)
320{
321 if (!devname) {
322 return;
323 }
324 unsigned int u;
325 for (u = 0; u < input.ndevs; u++) {
326 if (!strcmp(devname, input.devs[u].path)) {
327 free(input.devs[u].path);
328 close(input.devs[u].fd);
329 input.ndevs--;
330 if (u != input.ndevs) {
331 input.devs[u] = input.devs[input.ndevs];
332 }
333 return;
334 }
335 }
336}
337
Dominik Behr93899452014-08-18 22:16:21 -0700338
339int input_init()
340{
341 input.udev = udev_new();
342 if (!input.udev)
343 return -ENOENT;
344 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
345 if (!input.udev_monitor) {
346 udev_unref(input.udev);
347 return -ENOENT;
348 }
349 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
350 NULL);
351 udev_monitor_enable_receiving(input.udev_monitor);
352 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
353
354 struct udev_enumerate *udev_enum;
355 struct udev_list_entry *devices, *deventry;
356 udev_enum = udev_enumerate_new(input.udev);
357 udev_enumerate_add_match_subsystem(udev_enum, "input");
358 udev_enumerate_scan_devices(udev_enum);
359 devices = udev_enumerate_get_list_entry(udev_enum);
360 udev_list_entry_foreach(deventry, devices) {
361 const char *syspath;
362 struct udev_device *dev;
363 syspath = udev_list_entry_get_name(deventry);
364 dev = udev_device_new_from_syspath(input.udev, syspath);
365 input_add(udev_device_get_devnode(dev));
366 udev_device_unref(dev);
367 }
368 udev_enumerate_unref(udev_enum);
369
370 if (!isatty(fileno(stdout)))
371 setbuf(stdout, NULL);
372
David Sodmanbbcb0522014-09-19 10:34:07 -0700373 if (input.ndevs == 0) {
374 LOG(ERROR, "No valid inputs for terminal");
375 exit(EXIT_SUCCESS);
376 }
377
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700378 return 0;
379}
380
381void input_close()
382{
Dominik Behr93899452014-08-18 22:16:21 -0700383 unsigned int u;
384 for (u = 0; u < input.ndevs; u++) {
385 free(input.devs[u].path);
386 close(input.devs[u].fd);
387 }
388 free(input.devs);
389 input.devs = NULL;
390 input.ndevs = 0;
391
392 udev_monitor_unref(input.udev_monitor);
393 input.udev_monitor = NULL;
394 udev_unref(input.udev);
395 input.udev = NULL;
396 input.udev_fd = -1;
397
David Sodmanbbcb0522014-09-19 10:34:07 -0700398 dbus_destroy(input.dbus);
399
400}
401
402void input_set_dbus(dbus_t* dbus)
403{
404 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700405}
406
Dominik Behr93899452014-08-18 22:16:21 -0700407int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700408{
Dominik Behr93899452014-08-18 22:16:21 -0700409 unsigned int u;
410 int max = -1;
411 for (u = 0; u < input.ndevs; u++) {
412 FD_SET(input.devs[u].fd, read_set);
413 FD_SET(input.devs[u].fd, exception_set);
414 if (input.devs[u].fd > max)
415 max = input.devs[u].fd;
416 }
417
418 FD_SET(input.udev_fd, read_set);
419 FD_SET(input.udev_fd, exception_set);
420 if (input.udev_fd > max)
421 max = input.udev_fd;
422 return max;
423}
424
Dominik Behr93899452014-08-18 22:16:21 -0700425struct input_key_event *input_get_event(fd_set * read_set,
426 fd_set * exception_set)
427{
428 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700429 struct input_event ev;
430 int ret;
431
Dominik Behr93899452014-08-18 22:16:21 -0700432 if (FD_ISSET(input.udev_fd, exception_set)) {
433 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700434 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700435 }
436
Dominik Behr93899452014-08-18 22:16:21 -0700437 if (FD_ISSET(input.udev_fd, read_set)
438 && !FD_ISSET(input.udev_fd, exception_set)) {
439 /* we got an udev notification */
440 struct udev_device *dev =
441 udev_monitor_receive_device(input.udev_monitor);
442 if (dev) {
443 if (!strcmp("add", udev_device_get_action(dev))) {
444 input_add(udev_device_get_devnode(dev));
445 } else
446 if (!strcmp("remove", udev_device_get_action(dev)))
447 {
448 input_remove(udev_device_get_devnode(dev));
449 }
450 udev_device_unref(dev);
451 }
452 }
453
454 for (u = 0; u < input.ndevs; u++) {
455 if (FD_ISSET(input.devs[u].fd, read_set)
456 && !FD_ISSET(input.devs[u].fd, exception_set)) {
457 ret =
458 read(input.devs[u].fd, &ev, sizeof (struct input_event));
459 if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700460 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700461 (int) sizeof (struct input_event), ret);
462 return NULL;
463 }
464
465 if (ev.type == EV_KEY) {
466 struct input_key_event *event =
467 malloc(sizeof (*event));
468 event->code = ev.code;
469 event->value = ev.value;
David Sodmane0cc8312014-11-18 11:16:36 -0800470 report_user_activity(USER_ACTIVITY_OTHER);
Dominik Behr93899452014-08-18 22:16:21 -0700471 return event;
472 }
473 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700474 }
475
476 return NULL;
477}
478
David Sodmanbf3f2842014-11-12 08:26:58 -0800479int input_run(bool standalone)
480{
481 fd_set read_set, exception_set;
482 terminal_t* terminal;
483
484 if (standalone) {
485 (void)dbus_method_call0(input.dbus,
486 kLibCrosServiceName,
487 kLibCrosServicePath,
488 kLibCrosServiceInterface,
489 kReleaseDisplayOwnership);
490
Dominik Behr5d3a8a72014-11-20 13:50:05 -0800491 input.terminals[input.current_terminal] = term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800492 terminal = input.terminals[input.current_terminal];
493 if (term_is_valid(terminal)) {
494 input_grab();
495 }
496 }
497
498 while (1) {
499 terminal = input.terminals[input.current_terminal];
500
501 FD_ZERO(&read_set);
502 FD_ZERO(&exception_set);
503 term_add_fd(terminal, &read_set, &exception_set);
504
505 int maxfd = input_setfds(&read_set, &exception_set);
506
507 maxfd = MAX(maxfd, term_fd(terminal)) + 1;
508
509 select(maxfd, &read_set, NULL, &exception_set, NULL);
510
511 if (term_exception(terminal, &exception_set))
512 return -1;
513
514 struct input_key_event *event;
515 event = input_get_event(&read_set, &exception_set);
516 if (event) {
517 if (!input_special_key(event) && event->value) {
518 uint32_t keysym, unicode;
519 if (term_is_active(terminal)) {
520 input_get_keysym_and_unicode(
521 event, &keysym, &unicode);
522 term_key_event(terminal,
523 keysym, unicode);
524 }
525 }
526
527 input_put_event(event);
528 }
529
530
531 term_dispatch_io(terminal, &read_set);
532
533 if (term_is_valid(terminal)) {
534 if (term_is_child_done(terminal)) {
535 term_close(terminal);
Dominik Behr5d3a8a72014-11-20 13:50:05 -0800536 input.terminals[input.current_terminal] = term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800537 terminal = input.terminals[input.current_terminal];
538 if (!term_is_valid(terminal)) {
539 return -1;
540 }
541 }
542 }
543 }
544
545 return 0;
546}
547
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700548void input_put_event(struct input_key_event *event)
549{
550 free(event);
551}
David Sodmanbbcb0522014-09-19 10:34:07 -0700552
553void input_grab()
554{
555 unsigned int i;
556 for (i = 0; i < input.ndevs; i++) {
557 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void *) 1);
558 }
559}
560
561void input_ungrab()
562{
563 unsigned int i;
564 for (i = 0; i < input.ndevs; i++) {
565 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void*) 0);
566 }
567}