blob: 696a83d6653d3ec64f2687419ae609da44bac366 [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{
David Sodman19e4f9d2015-03-10 11:11:09 -070058 dbus_bool_t allow_off = false;
David Sodmane0cc8312014-11-18 11:16:36 -080059 dbus_method_call1(input.dbus, kPowerManagerServiceName,
60 kPowerManagerServicePath,
61 kPowerManagerInterface,
62 kHandleUserActivityMethod,
David Sodman19e4f9d2015-03-10 11:11:09 -070063 DBUS_TYPE_INT32, &activity_type);
David Sodmane0cc8312014-11-18 11:16:36 -080064
65 switch (activity_type) {
66 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
67 (void)dbus_method_call0(input.dbus,
68 kPowerManagerServiceName,
69 kPowerManagerServicePath,
70 kPowerManagerInterface,
71 kIncreaseScreenBrightnessMethod);
72 break;
73 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
David Sodman19e4f9d2015-03-10 11:11:09 -070074 /*
75 * Shouldn't allow the screen to go
76 * completely off while frecon is active
77 * so passing false to allow_off
78 */
79 (void)dbus_method_call1(input.dbus,
David Sodmane0cc8312014-11-18 11:16:36 -080080 kPowerManagerServiceName,
81 kPowerManagerServicePath,
82 kPowerManagerInterface,
David Sodman19e4f9d2015-03-10 11:11:09 -070083 kDecreaseScreenBrightnessMethod,
84 DBUS_TYPE_BOOLEAN, &allow_off);
David Sodmane0cc8312014-11-18 11:16:36 -080085 break;
86 }
87}
88
David Sodmanbf3f2842014-11-12 08:26:58 -080089static int input_special_key(struct input_key_event *ev)
90{
91 unsigned int i;
David Sodmanb0697c22014-12-12 10:29:25 -080092 terminal_t *terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080093
94 uint32_t ignore_keys[] = {
95 BTN_TOUCH, // touchpad events
96 BTN_TOOL_FINGER,
97 BTN_TOOL_DOUBLETAP,
98 BTN_TOOL_TRIPLETAP,
99 BTN_TOOL_QUADTAP,
100 BTN_TOOL_QUINTTAP,
101 BTN_LEFT, // mouse buttons
102 BTN_RIGHT,
103 BTN_MIDDLE,
104 BTN_SIDE,
105 BTN_EXTRA,
106 BTN_FORWARD,
107 BTN_BACK,
108 BTN_TASK
109 };
110
David Sodmanafba0d92015-01-27 19:07:46 -0800111 terminal = input.terminals[input.current_terminal];
112
David Sodmanbf3f2842014-11-12 08:26:58 -0800113 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
114 if (ev->code == ignore_keys[i])
115 return 1;
116
117 switch (ev->code) {
118 case KEY_LEFTSHIFT:
119 case KEY_RIGHTSHIFT:
120 input.kbd_state.shift_state = ! !ev->value;
121 return 1;
122 case KEY_LEFTCTRL:
123 case KEY_RIGHTCTRL:
124 input.kbd_state.control_state = ! !ev->value;
125 return 1;
126 case KEY_LEFTALT:
127 case KEY_RIGHTALT:
128 input.kbd_state.alt_state = ! !ev->value;
129 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800130 case KEY_LEFTMETA: // search key
131 input.kbd_state.search_state = ! !ev->value;
132 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800133 }
134
David Sodmanafba0d92015-01-27 19:07:46 -0800135 if (term_is_active(terminal)) {
136 if (input.kbd_state.shift_state && ev->value) {
137 switch (ev->code) {
138 case KEY_PAGEUP:
David Sodmane0cc8312014-11-18 11:16:36 -0800139 term_page_up(input.terminals[input.current_terminal]);
140 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800141 case KEY_PAGEDOWN:
David Sodmane0cc8312014-11-18 11:16:36 -0800142 term_page_down(input.terminals[input.current_terminal]);
143 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800144 case KEY_UP:
145 term_line_up(input.terminals[input.current_terminal]);
146 return 1;
147 case KEY_DOWN:
148 term_line_down(input.terminals[input.current_terminal]);
149 return 1;
150 }
151 }
152
153 if (input.kbd_state.search_state && ev->value) {
154 switch (ev->code) {
155 case KEY_UP:
156 term_page_up(input.terminals[input.current_terminal]);
157 return 1;
158 case KEY_DOWN:
159 term_page_down(input.terminals[input.current_terminal]);
160 return 1;
161 }
162 }
163
164 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
165 input.kbd_state.control_state) &&
166 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
167 switch (ev->code) {
168 case KEY_F1:
169 case KEY_F2:
170 case KEY_F3:
171 case KEY_F4:
172 case KEY_F5:
173 break;
174 case KEY_F6:
175 case KEY_F7:
176 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
177 (ev->code - KEY_F6));
178 break;
179 case KEY_F8:
180 case KEY_F9:
181 case KEY_F10:
182 break;
183 }
184 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800185 }
186 }
187
David Sodmanbf3f2842014-11-12 08:26:58 -0800188 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodmanb0697c22014-12-12 10:29:25 -0800189 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800190 if (term_is_active(terminal)) {
David Sodmanbf3f2842014-11-12 08:26:58 -0800191 input_ungrab();
David Sodmanb0697c22014-12-12 10:29:25 -0800192 terminal->active = false;
David Sodman35d6bd82014-11-24 08:23:00 -0800193 video_release(input.terminals[input.current_terminal]->video);
David Sodmanbf3f2842014-11-12 08:26:58 -0800194 (void)dbus_method_call0(input.dbus,
195 kLibCrosServiceName,
196 kLibCrosServicePath,
197 kLibCrosServiceInterface,
198 kTakeDisplayOwnership);
David Sodmanb0697c22014-12-12 10:29:25 -0800199 }
200 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_TERMINALS)) {
201 (void)dbus_method_call0(input.dbus,
202 kLibCrosServiceName,
203 kLibCrosServicePath,
204 kLibCrosServiceInterface,
205 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800206 if (term_is_active(terminal))
207 terminal->active = false;
208 input.current_terminal = ev->code - KEY_F2;
209 terminal = input.terminals[input.current_terminal];
210 if (terminal == NULL) {
211 input.terminals[input.current_terminal] =
Dominik Behr580462b2014-11-20 13:50:05 -0800212 term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800213 terminal =
214 input.terminals[input.current_terminal];
215 if (!term_is_valid(terminal)) {
216 LOG(ERROR, "Term init failed");
217 return 1;
218 }
219 }
220 input.terminals[input.current_terminal]->active = true;
221 input_grab();
222 video_setmode(terminal->video);
223 term_redraw(terminal);
224 }
225
226 return 1;
227
228 }
229
230 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;
Dominik Behr93899452014-08-18 22:16:21 -0700470 return event;
471 }
472 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700473 }
474
475 return NULL;
476}
477
David Sodmanbf3f2842014-11-12 08:26:58 -0800478int input_run(bool standalone)
479{
480 fd_set read_set, exception_set;
481 terminal_t* terminal;
482
483 if (standalone) {
484 (void)dbus_method_call0(input.dbus,
485 kLibCrosServiceName,
486 kLibCrosServicePath,
487 kLibCrosServiceInterface,
488 kReleaseDisplayOwnership);
489
Dominik Behr580462b2014-11-20 13:50:05 -0800490 input.terminals[input.current_terminal] = term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800491 terminal = input.terminals[input.current_terminal];
492 if (term_is_valid(terminal)) {
493 input_grab();
494 }
495 }
496
497 while (1) {
498 terminal = input.terminals[input.current_terminal];
499
500 FD_ZERO(&read_set);
501 FD_ZERO(&exception_set);
502 term_add_fd(terminal, &read_set, &exception_set);
503
504 int maxfd = input_setfds(&read_set, &exception_set);
505
506 maxfd = MAX(maxfd, term_fd(terminal)) + 1;
507
508 select(maxfd, &read_set, NULL, &exception_set, NULL);
509
510 if (term_exception(terminal, &exception_set))
511 return -1;
512
David Sodmanafba0d92015-01-27 19:07:46 -0800513 struct input_key_event *event;
514 event = input_get_event(&read_set, &exception_set);
515 if (event) {
516 if (!input_special_key(event) && event->value) {
517 uint32_t keysym, unicode;
518 // current_terminal can possibly change during
519 // execution of input_special_key
520 terminal = input.terminals[input.current_terminal];
521 if (term_is_active(terminal)) {
522 // Only report user activity when the terminal is active
523 report_user_activity(USER_ACTIVITY_OTHER);
524 input_get_keysym_and_unicode(
525 event, &keysym, &unicode);
526 term_key_event(terminal,
527 keysym, unicode);
David Sodmanbf3f2842014-11-12 08:26:58 -0800528 }
529 }
David Sodmanafba0d92015-01-27 19:07:46 -0800530 input_put_event(event);
David Sodmanbf3f2842014-11-12 08:26:58 -0800531 }
532
David Sodmanbf3f2842014-11-12 08:26:58 -0800533 term_dispatch_io(terminal, &read_set);
534
535 if (term_is_valid(terminal)) {
536 if (term_is_child_done(terminal)) {
David Sodman5e5c37e2014-12-19 14:14:46 -0800537 if (terminal->video) {
538 // necessary in case chrome is playing full screen
539 // video or graphics
540 //TODO: This is still a race with Chrome. This
541 //needs to be fixed with bug 444209
542 video_setmode(terminal->video);
543 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800544 term_close(terminal);
Dominik Behr580462b2014-11-20 13:50:05 -0800545 input.terminals[input.current_terminal] = term_init(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800546 terminal = input.terminals[input.current_terminal];
547 if (!term_is_valid(terminal)) {
548 return -1;
549 }
550 }
551 }
552 }
553
554 return 0;
555}
556
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700557void input_put_event(struct input_key_event *event)
558{
559 free(event);
560}
David Sodmanbbcb0522014-09-19 10:34:07 -0700561
562void input_grab()
563{
564 unsigned int i;
565 for (i = 0; i < input.ndevs; i++) {
566 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void *) 1);
567 }
568}
569
570void input_ungrab()
571{
572 unsigned int i;
573 for (i = 0; i < input.ndevs; i++) {
574 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void*) 0);
575 }
576}