blob: 5f37ddf2e35ea8f6061c935c802b8de62ebf00a0 [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>
David Sodman8ef20062015-01-06 09:23:40 -08008#include <errno.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07009#include <fcntl.h>
David Sodman8ef20062015-01-06 09:23:40 -080010#include <libudev.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070011#include <stdint.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
Dominik Behr93899452014-08-18 22:16:21 -070015#include <sys/select.h>
David Sodman8ef20062015-01-06 09:23:40 -080016#include <unistd.h>
17
David Sodmanbbcb0522014-09-19 10:34:07 -070018#include "dbus.h"
Stéphane Marchesin6cbb7332016-01-07 21:18:43 -080019#include "dbus_interface.h"
Stéphane Marchesin62561a12015-12-11 17:32:37 -080020#include "input.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080021#include "keysym.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022#include "util.h"
David Sodman8ef20062015-01-06 09:23:40 -080023
Dominik Behr93899452014-08-18 22:16:21 -070024struct input_dev {
25 int fd;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 char* path;
Dominik Behr93899452014-08-18 22:16:21 -070027};
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
Dylan Reid342aed02015-06-18 12:15:52 -070036/*
37 * structure to keep input state:
38 * udev - for udev events.
39 * udev_monitor - used to listen for udev events.
40 * udev_fd - to poll for udev messages.
41 * ndevs - number of input devices.
42 * devs - input devices to listen to.
43 * kbd_state - tracks modifier keys that are pressed.
Dylan Reid342aed02015-06-18 12:15:52 -070044 * current_terminal - the currently selected terminal.
Dylan Reid342aed02015-06-18 12:15:52 -070045 */
Dominik Behr93899452014-08-18 22:16:21 -070046struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080047 struct udev* udev;
48 struct udev_monitor* udev_monitor;
Dominik Behr93899452014-08-18 22:16:21 -070049 int udev_fd;
50 unsigned int ndevs;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080051 struct input_dev* devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080052 struct keyboard_state kbd_state;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080053 uint32_t current_terminal;
Dominik Behr93899452014-08-18 22:16:21 -070054} input = {
55 .udev = NULL,
56 .udev_monitor = NULL,
57 .udev_fd = -1,
58 .ndevs = 0,
59 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080060 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070061};
62
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080063static int input_special_key(struct input_key_event* ev)
David Sodmanbf3f2842014-11-12 08:26:58 -080064{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080065 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080066
67 uint32_t ignore_keys[] = {
68 BTN_TOUCH, // touchpad events
69 BTN_TOOL_FINGER,
70 BTN_TOOL_DOUBLETAP,
71 BTN_TOOL_TRIPLETAP,
72 BTN_TOOL_QUADTAP,
73 BTN_TOOL_QUINTTAP,
74 BTN_LEFT, // mouse buttons
75 BTN_RIGHT,
76 BTN_MIDDLE,
77 BTN_SIDE,
78 BTN_EXTRA,
79 BTN_FORWARD,
80 BTN_BACK,
81 BTN_TASK
82 };
83
Stéphane Marchesin08c08e72016-01-07 16:44:08 -080084 terminal = term_get_terminal(input.current_terminal);
David Sodmanafba0d92015-01-27 19:07:46 -080085
Stéphane Marchesinac14d292015-12-14 15:27:18 -080086 for (unsigned int i = 0; i < ARRAY_SIZE(ignore_keys); i++)
David Sodmanbf3f2842014-11-12 08:26:58 -080087 if (ev->code == ignore_keys[i])
88 return 1;
89
90 switch (ev->code) {
91 case KEY_LEFTSHIFT:
92 case KEY_RIGHTSHIFT:
93 input.kbd_state.shift_state = ! !ev->value;
94 return 1;
95 case KEY_LEFTCTRL:
96 case KEY_RIGHTCTRL:
97 input.kbd_state.control_state = ! !ev->value;
98 return 1;
99 case KEY_LEFTALT:
100 case KEY_RIGHTALT:
101 input.kbd_state.alt_state = ! !ev->value;
102 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800103 case KEY_LEFTMETA: // search key
104 input.kbd_state.search_state = ! !ev->value;
105 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800106 }
107
David Sodmanafba0d92015-01-27 19:07:46 -0800108 if (term_is_active(terminal)) {
109 if (input.kbd_state.shift_state && ev->value) {
110 switch (ev->code) {
111 case KEY_PAGEUP:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800112 term_page_up(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800113 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800114 case KEY_PAGEDOWN:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800115 term_page_down(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800116 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800117 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700118 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800119 term_page_up(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700120 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800121 term_line_up(terminal);
David Sodmanafba0d92015-01-27 19:07:46 -0800122 return 1;
123 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700124 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800125 term_page_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700126 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800127 term_line_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700128 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800129 }
130 }
131
132 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
133 input.kbd_state.control_state) &&
134 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
135 switch (ev->code) {
136 case KEY_F1:
137 case KEY_F2:
138 case KEY_F3:
139 case KEY_F4:
140 case KEY_F5:
141 break;
142 case KEY_F6:
143 case KEY_F7:
Dominik Behr797a3832016-01-11 15:53:11 -0800144 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
145 (ev->code - KEY_F6));
David Sodmanafba0d92015-01-27 19:07:46 -0800146 break;
147 case KEY_F8:
148 case KEY_F9:
149 case KEY_F10:
150 break;
151 }
152 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800153 }
154 }
155
David Sodmanbf3f2842014-11-12 08:26:58 -0800156 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700157 /*
158 * Special case for key sequence that is used by external program. Just
159 * explicitly ignore here and do nothing.
160 */
161 if (input.kbd_state.shift_state)
162 return 1;
163
David Sodmanb0697c22014-12-12 10:29:25 -0800164 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800165 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700166 term_deactivate(terminal);
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800167 if (term_get_terminal(SPLASH_TERMINAL) != NULL) {
168 term_activate(term_get_terminal(SPLASH_TERMINAL));
David Sodmanf0a925a2015-05-04 11:19:19 -0700169 } else {
Dominik Behr797a3832016-01-11 15:53:11 -0800170 dbus_take_display_ownership();
David Sodmanf0a925a2015-05-04 11:19:19 -0700171 }
David Sodman8ef20062015-01-06 09:23:40 -0800172 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700173 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
Dominik Behr797a3832016-01-11 15:53:11 -0800174 dbus_release_display_ownership();
David Sodmanbf3f2842014-11-12 08:26:58 -0800175 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700176 term_deactivate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800177 input.current_terminal = ev->code - KEY_F2;
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800178 terminal = term_get_terminal(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800179 if (terminal == NULL) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800180 term_set_terminal(input.current_terminal,
181 term_init(true, NULL));
David Sodmanbf3f2842014-11-12 08:26:58 -0800182 terminal =
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800183 term_get_terminal(input.current_terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800184 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800185 if (!term_is_valid(terminal)) {
186 LOG(ERROR, "Term init failed");
187 return 1;
188 }
189 }
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800190 term_activate(term_get_terminal(input.current_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800191 }
192
193 return 1;
194
195 }
196
197 return 0;
198}
199
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800200static void input_get_keysym_and_unicode(struct input_key_event* event,
201 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800202{
203 struct {
204 uint32_t code;
205 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700206 } search_keys[] = {
207 { KEY_F1, KEYSYM_F1},
208 { KEY_F2, KEYSYM_F2},
209 { KEY_F3, KEYSYM_F3},
210 { KEY_F4, KEYSYM_F4},
211 { KEY_F5, KEYSYM_F5},
212 { KEY_F6, KEYSYM_F6},
213 { KEY_F7, KEYSYM_F7},
214 { KEY_F8, KEYSYM_F8},
215 { KEY_F9, KEYSYM_F8},
216 { KEY_F10, KEYSYM_F10},
217 { KEY_UP, KEYSYM_PAGEUP},
218 { KEY_DOWN, KEYSYM_PAGEDOWN},
219 { KEY_LEFT, KEYSYM_HOME},
220 { KEY_RIGHT, KEYSYM_END},
221 };
222
223 struct {
224 uint32_t code;
225 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800226 } non_ascii_keys[] = {
227 { KEY_ESC, KEYSYM_ESC},
228 { KEY_HOME, KEYSYM_HOME},
229 { KEY_LEFT, KEYSYM_LEFT},
230 { KEY_UP, KEYSYM_UP},
231 { KEY_RIGHT, KEYSYM_RIGHT},
232 { KEY_DOWN, KEYSYM_DOWN},
233 { KEY_PAGEUP, KEYSYM_PAGEUP},
234 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
235 { KEY_END, KEYSYM_END},
236 { KEY_INSERT, KEYSYM_INSERT},
237 { KEY_DELETE, KEYSYM_DELETE},
238 };
239
Dominik Behr58bb8e12015-09-22 14:30:41 -0700240 if (input.kbd_state.search_state) {
241 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
242 if (search_keys[i].code == event->code) {
243 *keysym = search_keys[i].keysym;
244 *unicode = -1;
245 return;
246 }
247 }
248 }
249
David Sodmanbf3f2842014-11-12 08:26:58 -0800250 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
251 if (non_ascii_keys[i].code == event->code) {
252 *keysym = non_ascii_keys[i].keysym;
253 *unicode = -1;
254 return;
255 }
256 }
257
258 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
259 *keysym = '?';
260 } else {
261 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
262 if ((input.kbd_state.control_state) && isascii(*keysym))
263 *keysym = tolower(*keysym) - 'a' + 1;
264 }
265
266 *unicode = *keysym;
267}
268
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800269static int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700270{
Dominik Behr93899452014-08-18 22:16:21 -0700271 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800272
Dominik Behr93899452014-08-18 22:16:21 -0700273 /* for some reason every device has a null enumerations and notifications
274 of every device come with NULL string first */
275 if (!devname) {
276 ret = -EINVAL;
277 goto errorret;
278 }
Haixia Shid288e032015-09-14 18:33:11 -0700279 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800280 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700281 if (strcmp(devname, input.devs[i].path) == 0) {
Stéphane Marchesinc02260b2016-01-07 22:46:45 -0800282 LOG(INFO, "Skipping duplicate input device %s", devname);
Haixia Shid288e032015-09-14 18:33:11 -0700283 ret = -EINVAL;
284 goto errorret;
285 }
286 }
Dominik Behr93899452014-08-18 22:16:21 -0700287 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700288 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700289 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700290
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800291 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700292 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800293 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700294 if (ret)
295 LOG(ERROR,
296 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
297 } else {
298 LOG(ERROR, "Evdev device %s grabbed by another process",
299 devname);
300 ret = -EBUSY;
301 goto closefd;
302 }
303
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800304 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700305 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
306 if (!newdevs) {
307 ret = -ENOMEM;
308 goto closefd;
309 }
310 input.devs = newdevs;
311 input.devs[input.ndevs].fd = fd;
312 input.devs[input.ndevs].path = strdup(devname);
313 if (!input.devs[input.ndevs].path) {
314 ret = -ENOMEM;
315 goto closefd;
316 }
317 input.ndevs++;
318
319 return fd;
320
321closefd:
322 close(fd);
323errorret:
324 return ret;
325}
326
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800327static void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700328{
Dominik Behr93899452014-08-18 22:16:21 -0700329 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800330
331 if (!devname)
332 return;
333
Dominik Behr93899452014-08-18 22:16:21 -0700334 for (u = 0; u < input.ndevs; u++) {
335 if (!strcmp(devname, input.devs[u].path)) {
336 free(input.devs[u].path);
337 close(input.devs[u].fd);
338 input.ndevs--;
339 if (u != input.ndevs) {
340 input.devs[u] = input.devs[input.ndevs];
341 }
342 return;
343 }
344 }
345}
346
Dominik Behr93899452014-08-18 22:16:21 -0700347
348int input_init()
349{
350 input.udev = udev_new();
351 if (!input.udev)
352 return -ENOENT;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800353
Dominik Behr93899452014-08-18 22:16:21 -0700354 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
355 if (!input.udev_monitor) {
356 udev_unref(input.udev);
357 return -ENOENT;
358 }
359 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
360 NULL);
361 udev_monitor_enable_receiving(input.udev_monitor);
362 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
363
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800364 struct udev_enumerate* udev_enum;
365 struct udev_list_entry* devices, *deventry;
Dominik Behr93899452014-08-18 22:16:21 -0700366 udev_enum = udev_enumerate_new(input.udev);
367 udev_enumerate_add_match_subsystem(udev_enum, "input");
368 udev_enumerate_scan_devices(udev_enum);
369 devices = udev_enumerate_get_list_entry(udev_enum);
370 udev_list_entry_foreach(deventry, devices) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800371 const char* syspath;
372 struct udev_device* dev;
Dominik Behr93899452014-08-18 22:16:21 -0700373 syspath = udev_list_entry_get_name(deventry);
374 dev = udev_device_new_from_syspath(input.udev, syspath);
375 input_add(udev_device_get_devnode(dev));
376 udev_device_unref(dev);
377 }
378 udev_enumerate_unref(udev_enum);
379
380 if (!isatty(fileno(stdout)))
381 setbuf(stdout, NULL);
382
David Sodmanbbcb0522014-09-19 10:34:07 -0700383 if (input.ndevs == 0) {
384 LOG(ERROR, "No valid inputs for terminal");
385 exit(EXIT_SUCCESS);
386 }
387
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700388 return 0;
389}
390
391void input_close()
392{
Dominik Behr93899452014-08-18 22:16:21 -0700393 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800394
Dominik Behr93899452014-08-18 22:16:21 -0700395 for (u = 0; u < input.ndevs; u++) {
396 free(input.devs[u].path);
397 close(input.devs[u].fd);
398 }
399 free(input.devs);
400 input.devs = NULL;
401 input.ndevs = 0;
402
403 udev_monitor_unref(input.udev_monitor);
404 input.udev_monitor = NULL;
405 udev_unref(input.udev);
406 input.udev = NULL;
407 input.udev_fd = -1;
408
Dominik Behr797a3832016-01-11 15:53:11 -0800409 dbus_destroy();
David Sodmanbbcb0522014-09-19 10:34:07 -0700410
411}
412
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800413int input_add_fds(fd_set* read_set, fd_set* exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700414{
Dominik Behr93899452014-08-18 22:16:21 -0700415 unsigned int u;
416 int max = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800417
Dominik Behr93899452014-08-18 22:16:21 -0700418 for (u = 0; u < input.ndevs; u++) {
419 FD_SET(input.devs[u].fd, read_set);
420 FD_SET(input.devs[u].fd, exception_set);
421 if (input.devs[u].fd > max)
422 max = input.devs[u].fd;
423 }
424
425 FD_SET(input.udev_fd, read_set);
426 FD_SET(input.udev_fd, exception_set);
427 if (input.udev_fd > max)
428 max = input.udev_fd;
429 return max;
430}
431
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800432struct input_key_event* input_get_event(fd_set* read_set,
433 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700434{
435 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700436 struct input_event ev;
437 int ret;
438
Dominik Behr93899452014-08-18 22:16:21 -0700439 if (FD_ISSET(input.udev_fd, exception_set)) {
440 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700441 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700442 }
443
Dominik Behr93899452014-08-18 22:16:21 -0700444 if (FD_ISSET(input.udev_fd, read_set)
445 && !FD_ISSET(input.udev_fd, exception_set)) {
446 /* we got an udev notification */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800447 struct udev_device* dev =
Dominik Behr93899452014-08-18 22:16:21 -0700448 udev_monitor_receive_device(input.udev_monitor);
449 if (dev) {
450 if (!strcmp("add", udev_device_get_action(dev))) {
451 input_add(udev_device_get_devnode(dev));
452 } else
453 if (!strcmp("remove", udev_device_get_action(dev)))
454 {
455 input_remove(udev_device_get_devnode(dev));
456 }
457 udev_device_unref(dev);
458 }
459 }
460
461 for (u = 0; u < input.ndevs; u++) {
462 if (FD_ISSET(input.devs[u].fd, read_set)
463 && !FD_ISSET(input.devs[u].fd, exception_set)) {
464 ret =
465 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400466 if (ret < 0) {
467 if (errno == EINTR || errno == EAGAIN)
468 continue;
469 if (errno != ENODEV) {
470 LOG(ERROR, "read: %s: %s", input.devs[u].path,
471 strerror(errno));
472 }
473 input_remove(input.devs[u].path);
474 return NULL;
475 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700476 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700477 (int) sizeof (struct input_event), ret);
478 return NULL;
479 }
480
481 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800482 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700483 malloc(sizeof (*event));
484 event->code = ev.code;
485 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700486 return event;
487 }
488 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700489 }
490
491 return NULL;
492}
493
David Sodmanf0a925a2015-05-04 11:19:19 -0700494int input_process(terminal_t* splash_term, uint32_t usec)
495{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800496 terminal_t* terminal;
497 terminal_t* new_terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700498 fd_set read_set, exception_set;
499 int maxfd;
500 int sstat;
501 struct timeval tm;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800502 struct timeval* ptm;
David Sodmanf0a925a2015-05-04 11:19:19 -0700503
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800504 terminal = term_get_terminal(input.current_terminal);
David Sodmanf0a925a2015-05-04 11:19:19 -0700505
506 FD_ZERO(&read_set);
507 FD_ZERO(&exception_set);
508
Dominik Behr797a3832016-01-11 15:53:11 -0800509 maxfd = dbus_add_fds(&read_set, &exception_set) + 1;
David Sodmanf0a925a2015-05-04 11:19:19 -0700510
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800511 maxfd = MAX(maxfd, input_add_fds(&read_set, &exception_set)) + 1;
David Sodmanf0a925a2015-05-04 11:19:19 -0700512
513 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800514 if (term_is_valid(term_get_terminal(i))) {
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800515 terminal_t* current_term = term_get_terminal(i);
516 maxfd = MAX(maxfd, term_add_fds(current_term, &read_set, &exception_set)) + 1;
517 term_dispatch_io(current_term, &read_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700518 }
519 }
520
521 if (usec) {
522 ptm = &tm;
523 tm.tv_sec = 0;
524 tm.tv_usec = usec;
525 } else
526 ptm = NULL;
527
528 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
529 if (sstat == 0)
530 return 0;
531
Dominik Behr797a3832016-01-11 15:53:11 -0800532 dbus_dispatch_io();
David Sodmanf0a925a2015-05-04 11:19:19 -0700533
534 if (term_exception(terminal, &exception_set))
535 return -1;
536
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800537 struct input_key_event* event;
David Sodmanf0a925a2015-05-04 11:19:19 -0700538 event = input_get_event(&read_set, &exception_set);
539 if (event) {
540 if (!input_special_key(event) && event->value) {
541 uint32_t keysym, unicode;
542 // current_terminal can possibly change during
543 // execution of input_special_key
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800544 terminal = term_get_terminal(input.current_terminal);
David Sodmanf0a925a2015-05-04 11:19:19 -0700545 if (term_is_active(terminal)) {
546 // Only report user activity when the terminal is active
Dominik Behr797a3832016-01-11 15:53:11 -0800547 dbus_report_user_activity(USER_ACTIVITY_OTHER);
David Sodmanf0a925a2015-05-04 11:19:19 -0700548 input_get_keysym_and_unicode(
549 event, &keysym, &unicode);
550 term_key_event(terminal,
551 keysym, unicode);
552 }
553 }
554 input_put_event(event);
555 }
556
557 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800558 if (term_is_valid(term_get_terminal(i))) {
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800559 terminal_t* current_term = term_get_terminal(i);
560 maxfd = MAX(maxfd, term_add_fds(current_term, &read_set, &exception_set)) + 1;
561 term_dispatch_io(current_term, &read_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700562 }
563 }
564
565 if (term_is_valid(terminal)) {
566 if (term_is_child_done(terminal)) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800567 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700568 /*
569 * Note: reference is not lost because it is still referenced
570 * by the splash_t structure which will ultimately destroy
571 * it, once it's safe to do so
572 */
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800573 term_set_terminal(SPLASH_TERMINAL, NULL);
David Sodmanf0a925a2015-05-04 11:19:19 -0700574 return -1;
575 }
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800576 term_set_terminal(input.current_terminal,
577 term_init(true, term_getvideo(terminal)));
578 new_terminal = term_get_terminal(input.current_terminal);
David Sodmanf0a925a2015-05-04 11:19:19 -0700579 if (!term_is_valid(new_terminal)) {
580 return -1;
581 }
582 term_activate(new_terminal);
583 term_close(terminal);
584 }
585 }
586
587 return 0;
588}
589
David Sodmanbf3f2842014-11-12 08:26:58 -0800590int input_run(bool standalone)
591{
David Sodmanbf3f2842014-11-12 08:26:58 -0800592 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700593 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800594
595 if (standalone) {
Dominik Behr797a3832016-01-11 15:53:11 -0800596 dbus_take_display_ownership();
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800597 term_set_terminal(input.current_terminal, term_init(true, NULL));
598 terminal = term_get_terminal(input.current_terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800599 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800600 }
601
602 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700603 status = input_process(NULL, 0);
604 if (status != 0) {
605 LOG(ERROR, "input process returned %d", status);
606 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800607 }
608 }
609
610 return 0;
611}
612
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800613void input_put_event(struct input_key_event* event)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700614{
615 free(event);
616}
David Sodmanbbcb0522014-09-19 10:34:07 -0700617
Stéphane Marchesine38b8e72016-01-07 19:20:28 -0800618terminal_t* input_get_current_term()
619{
620 return term_get_terminal(input.current_terminal);
621}
622
David Sodman8ef20062015-01-06 09:23:40 -0800623void input_set_current(terminal_t* terminal)
624{
David Sodmanf0a925a2015-05-04 11:19:19 -0700625 if (!terminal) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800626 term_set_terminal(input.current_terminal, NULL);
David Sodmanf0a925a2015-05-04 11:19:19 -0700627 input.current_terminal = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800628 return;
David Sodmanf0a925a2015-05-04 11:19:19 -0700629 }
David Sodman8ef20062015-01-06 09:23:40 -0800630
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800631 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800632 if (terminal == term_get_terminal(i)) {
David Sodman8ef20062015-01-06 09:23:40 -0800633 input.current_terminal = i;
634 return;
635 }
636 }
637}