blob: 573e062c793df918261a3418fbbda4a24830752d [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.
44 * dbus - where to send dbus events.
45 * current_terminal - the currently selected terminal.
Dylan Reid342aed02015-06-18 12:15:52 -070046 */
Dominik Behr93899452014-08-18 22:16:21 -070047struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080048 struct udev* udev;
49 struct udev_monitor* udev_monitor;
Dominik Behr93899452014-08-18 22:16:21 -070050 int udev_fd;
51 unsigned int ndevs;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080052 struct input_dev* devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080053 struct keyboard_state kbd_state;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080054 dbus_t* dbus;
55 uint32_t current_terminal;
Dominik Behr93899452014-08-18 22:16:21 -070056} input = {
57 .udev = NULL,
58 .udev_monitor = NULL,
59 .udev_fd = -1,
60 .ndevs = 0,
61 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080062 .dbus = NULL,
63 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070064};
65
David Sodmane0cc8312014-11-18 11:16:36 -080066static void report_user_activity(int activity_type)
67{
David Sodman19e4f9d2015-03-10 11:11:09 -070068 dbus_bool_t allow_off = false;
David Sodman8ef20062015-01-06 09:23:40 -080069 if (!input.dbus)
70 return;
71
David Sodmane0cc8312014-11-18 11:16:36 -080072 dbus_method_call1(input.dbus, kPowerManagerServiceName,
73 kPowerManagerServicePath,
74 kPowerManagerInterface,
75 kHandleUserActivityMethod,
David Sodman19e4f9d2015-03-10 11:11:09 -070076 DBUS_TYPE_INT32, &activity_type);
David Sodmane0cc8312014-11-18 11:16:36 -080077
78 switch (activity_type) {
79 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
80 (void)dbus_method_call0(input.dbus,
81 kPowerManagerServiceName,
82 kPowerManagerServicePath,
83 kPowerManagerInterface,
84 kIncreaseScreenBrightnessMethod);
85 break;
86 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
David Sodman19e4f9d2015-03-10 11:11:09 -070087 /*
88 * Shouldn't allow the screen to go
89 * completely off while frecon is active
90 * so passing false to allow_off
91 */
92 (void)dbus_method_call1(input.dbus,
David Sodmane0cc8312014-11-18 11:16:36 -080093 kPowerManagerServiceName,
94 kPowerManagerServicePath,
95 kPowerManagerInterface,
David Sodman19e4f9d2015-03-10 11:11:09 -070096 kDecreaseScreenBrightnessMethod,
97 DBUS_TYPE_BOOLEAN, &allow_off);
David Sodmane0cc8312014-11-18 11:16:36 -080098 break;
99 }
100}
101
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800102static int input_special_key(struct input_key_event* ev)
David Sodmanbf3f2842014-11-12 08:26:58 -0800103{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800104 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -0800105
106 uint32_t ignore_keys[] = {
107 BTN_TOUCH, // touchpad events
108 BTN_TOOL_FINGER,
109 BTN_TOOL_DOUBLETAP,
110 BTN_TOOL_TRIPLETAP,
111 BTN_TOOL_QUADTAP,
112 BTN_TOOL_QUINTTAP,
113 BTN_LEFT, // mouse buttons
114 BTN_RIGHT,
115 BTN_MIDDLE,
116 BTN_SIDE,
117 BTN_EXTRA,
118 BTN_FORWARD,
119 BTN_BACK,
120 BTN_TASK
121 };
122
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800123 terminal = term_get_terminal(input.current_terminal);
David Sodmanafba0d92015-01-27 19:07:46 -0800124
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800125 for (unsigned int i = 0; i < ARRAY_SIZE(ignore_keys); i++)
David Sodmanbf3f2842014-11-12 08:26:58 -0800126 if (ev->code == ignore_keys[i])
127 return 1;
128
129 switch (ev->code) {
130 case KEY_LEFTSHIFT:
131 case KEY_RIGHTSHIFT:
132 input.kbd_state.shift_state = ! !ev->value;
133 return 1;
134 case KEY_LEFTCTRL:
135 case KEY_RIGHTCTRL:
136 input.kbd_state.control_state = ! !ev->value;
137 return 1;
138 case KEY_LEFTALT:
139 case KEY_RIGHTALT:
140 input.kbd_state.alt_state = ! !ev->value;
141 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800142 case KEY_LEFTMETA: // search key
143 input.kbd_state.search_state = ! !ev->value;
144 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800145 }
146
David Sodmanafba0d92015-01-27 19:07:46 -0800147 if (term_is_active(terminal)) {
148 if (input.kbd_state.shift_state && ev->value) {
149 switch (ev->code) {
150 case KEY_PAGEUP:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800151 term_page_up(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800152 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800153 case KEY_PAGEDOWN:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800154 term_page_down(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800155 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800156 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700157 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800158 term_page_up(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700159 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800160 term_line_up(terminal);
David Sodmanafba0d92015-01-27 19:07:46 -0800161 return 1;
162 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700163 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800164 term_page_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700165 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800166 term_line_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700167 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800168 }
169 }
170
171 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
172 input.kbd_state.control_state) &&
173 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
174 switch (ev->code) {
175 case KEY_F1:
176 case KEY_F2:
177 case KEY_F3:
178 case KEY_F4:
179 case KEY_F5:
180 break;
181 case KEY_F6:
182 case KEY_F7:
183 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
184 (ev->code - KEY_F6));
185 break;
186 case KEY_F8:
187 case KEY_F9:
188 case KEY_F10:
189 break;
190 }
191 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800192 }
193 }
194
David Sodmanbf3f2842014-11-12 08:26:58 -0800195 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700196 /*
197 * Special case for key sequence that is used by external program. Just
198 * explicitly ignore here and do nothing.
199 */
200 if (input.kbd_state.shift_state)
201 return 1;
202
David Sodmanb0697c22014-12-12 10:29:25 -0800203 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800204 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700205 term_deactivate(terminal);
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800206 if (term_get_terminal(SPLASH_TERMINAL) != NULL) {
207 term_activate(term_get_terminal(SPLASH_TERMINAL));
David Sodmanf0a925a2015-05-04 11:19:19 -0700208 } else {
209 if (input.dbus != NULL)
210 (void)dbus_method_call0(input.dbus,
211 kLibCrosServiceName,
212 kLibCrosServicePath,
213 kLibCrosServiceInterface,
214 kTakeDisplayOwnership);
215 }
David Sodman8ef20062015-01-06 09:23:40 -0800216 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700217 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
David Sodman8ef20062015-01-06 09:23:40 -0800218 if (input.dbus != NULL)
David Sodmanbf3f2842014-11-12 08:26:58 -0800219 (void)dbus_method_call0(input.dbus,
220 kLibCrosServiceName,
221 kLibCrosServicePath,
222 kLibCrosServiceInterface,
David Sodman8ef20062015-01-06 09:23:40 -0800223 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800224 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700225 term_deactivate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800226 input.current_terminal = ev->code - KEY_F2;
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800227 terminal = term_get_terminal(input.current_terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800228 if (terminal == NULL) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800229 term_set_terminal(input.current_terminal,
230 term_init(true, NULL));
David Sodmanbf3f2842014-11-12 08:26:58 -0800231 terminal =
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800232 term_get_terminal(input.current_terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800233 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800234 if (!term_is_valid(terminal)) {
235 LOG(ERROR, "Term init failed");
236 return 1;
237 }
238 }
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800239 term_activate(term_get_terminal(input.current_terminal));
David Sodmanbf3f2842014-11-12 08:26:58 -0800240 }
241
242 return 1;
243
244 }
245
246 return 0;
247}
248
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800249static void input_get_keysym_and_unicode(struct input_key_event* event,
250 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800251{
252 struct {
253 uint32_t code;
254 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700255 } search_keys[] = {
256 { KEY_F1, KEYSYM_F1},
257 { KEY_F2, KEYSYM_F2},
258 { KEY_F3, KEYSYM_F3},
259 { KEY_F4, KEYSYM_F4},
260 { KEY_F5, KEYSYM_F5},
261 { KEY_F6, KEYSYM_F6},
262 { KEY_F7, KEYSYM_F7},
263 { KEY_F8, KEYSYM_F8},
264 { KEY_F9, KEYSYM_F8},
265 { KEY_F10, KEYSYM_F10},
266 { KEY_UP, KEYSYM_PAGEUP},
267 { KEY_DOWN, KEYSYM_PAGEDOWN},
268 { KEY_LEFT, KEYSYM_HOME},
269 { KEY_RIGHT, KEYSYM_END},
270 };
271
272 struct {
273 uint32_t code;
274 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800275 } non_ascii_keys[] = {
276 { KEY_ESC, KEYSYM_ESC},
277 { KEY_HOME, KEYSYM_HOME},
278 { KEY_LEFT, KEYSYM_LEFT},
279 { KEY_UP, KEYSYM_UP},
280 { KEY_RIGHT, KEYSYM_RIGHT},
281 { KEY_DOWN, KEYSYM_DOWN},
282 { KEY_PAGEUP, KEYSYM_PAGEUP},
283 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
284 { KEY_END, KEYSYM_END},
285 { KEY_INSERT, KEYSYM_INSERT},
286 { KEY_DELETE, KEYSYM_DELETE},
287 };
288
Dominik Behr58bb8e12015-09-22 14:30:41 -0700289 if (input.kbd_state.search_state) {
290 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
291 if (search_keys[i].code == event->code) {
292 *keysym = search_keys[i].keysym;
293 *unicode = -1;
294 return;
295 }
296 }
297 }
298
David Sodmanbf3f2842014-11-12 08:26:58 -0800299 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
300 if (non_ascii_keys[i].code == event->code) {
301 *keysym = non_ascii_keys[i].keysym;
302 *unicode = -1;
303 return;
304 }
305 }
306
307 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
308 *keysym = '?';
309 } else {
310 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
311 if ((input.kbd_state.control_state) && isascii(*keysym))
312 *keysym = tolower(*keysym) - 'a' + 1;
313 }
314
315 *unicode = *keysym;
316}
317
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800318static int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700319{
Dominik Behr93899452014-08-18 22:16:21 -0700320 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800321
Dominik Behr93899452014-08-18 22:16:21 -0700322 /* for some reason every device has a null enumerations and notifications
323 of every device come with NULL string first */
324 if (!devname) {
325 ret = -EINVAL;
326 goto errorret;
327 }
Haixia Shid288e032015-09-14 18:33:11 -0700328 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800329 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700330 if (strcmp(devname, input.devs[i].path) == 0) {
331 LOG(WARNING, "Skipping duplicate input device %s", devname);
332 ret = -EINVAL;
333 goto errorret;
334 }
335 }
Dominik Behr93899452014-08-18 22:16:21 -0700336 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700337 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700338 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700339
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800340 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700341 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800342 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700343 if (ret)
344 LOG(ERROR,
345 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
346 } else {
347 LOG(ERROR, "Evdev device %s grabbed by another process",
348 devname);
349 ret = -EBUSY;
350 goto closefd;
351 }
352
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800353 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700354 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
355 if (!newdevs) {
356 ret = -ENOMEM;
357 goto closefd;
358 }
359 input.devs = newdevs;
360 input.devs[input.ndevs].fd = fd;
361 input.devs[input.ndevs].path = strdup(devname);
362 if (!input.devs[input.ndevs].path) {
363 ret = -ENOMEM;
364 goto closefd;
365 }
366 input.ndevs++;
367
368 return fd;
369
370closefd:
371 close(fd);
372errorret:
373 return ret;
374}
375
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800376static void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700377{
Dominik Behr93899452014-08-18 22:16:21 -0700378 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800379
380 if (!devname)
381 return;
382
Dominik Behr93899452014-08-18 22:16:21 -0700383 for (u = 0; u < input.ndevs; u++) {
384 if (!strcmp(devname, input.devs[u].path)) {
385 free(input.devs[u].path);
386 close(input.devs[u].fd);
387 input.ndevs--;
388 if (u != input.ndevs) {
389 input.devs[u] = input.devs[input.ndevs];
390 }
391 return;
392 }
393 }
394}
395
Dominik Behr93899452014-08-18 22:16:21 -0700396
397int input_init()
398{
399 input.udev = udev_new();
400 if (!input.udev)
401 return -ENOENT;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800402
Dominik Behr93899452014-08-18 22:16:21 -0700403 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
404 if (!input.udev_monitor) {
405 udev_unref(input.udev);
406 return -ENOENT;
407 }
408 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
409 NULL);
410 udev_monitor_enable_receiving(input.udev_monitor);
411 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
412
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800413 struct udev_enumerate* udev_enum;
414 struct udev_list_entry* devices, *deventry;
Dominik Behr93899452014-08-18 22:16:21 -0700415 udev_enum = udev_enumerate_new(input.udev);
416 udev_enumerate_add_match_subsystem(udev_enum, "input");
417 udev_enumerate_scan_devices(udev_enum);
418 devices = udev_enumerate_get_list_entry(udev_enum);
419 udev_list_entry_foreach(deventry, devices) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800420 const char* syspath;
421 struct udev_device* dev;
Dominik Behr93899452014-08-18 22:16:21 -0700422 syspath = udev_list_entry_get_name(deventry);
423 dev = udev_device_new_from_syspath(input.udev, syspath);
424 input_add(udev_device_get_devnode(dev));
425 udev_device_unref(dev);
426 }
427 udev_enumerate_unref(udev_enum);
428
429 if (!isatty(fileno(stdout)))
430 setbuf(stdout, NULL);
431
David Sodmanbbcb0522014-09-19 10:34:07 -0700432 if (input.ndevs == 0) {
433 LOG(ERROR, "No valid inputs for terminal");
434 exit(EXIT_SUCCESS);
435 }
436
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700437 return 0;
438}
439
440void input_close()
441{
Dominik Behr93899452014-08-18 22:16:21 -0700442 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800443
Dominik Behr93899452014-08-18 22:16:21 -0700444 for (u = 0; u < input.ndevs; u++) {
445 free(input.devs[u].path);
446 close(input.devs[u].fd);
447 }
448 free(input.devs);
449 input.devs = NULL;
450 input.ndevs = 0;
451
452 udev_monitor_unref(input.udev_monitor);
453 input.udev_monitor = NULL;
454 udev_unref(input.udev);
455 input.udev = NULL;
456 input.udev_fd = -1;
457
David Sodmanbbcb0522014-09-19 10:34:07 -0700458 dbus_destroy(input.dbus);
459
460}
461
462void input_set_dbus(dbus_t* dbus)
463{
464 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700465}
466
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800467int input_setfds(fd_set* read_set, fd_set* exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700468{
Dominik Behr93899452014-08-18 22:16:21 -0700469 unsigned int u;
470 int max = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800471
Dominik Behr93899452014-08-18 22:16:21 -0700472 for (u = 0; u < input.ndevs; u++) {
473 FD_SET(input.devs[u].fd, read_set);
474 FD_SET(input.devs[u].fd, exception_set);
475 if (input.devs[u].fd > max)
476 max = input.devs[u].fd;
477 }
478
479 FD_SET(input.udev_fd, read_set);
480 FD_SET(input.udev_fd, exception_set);
481 if (input.udev_fd > max)
482 max = input.udev_fd;
483 return max;
484}
485
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800486struct input_key_event* input_get_event(fd_set* read_set,
487 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700488{
489 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700490 struct input_event ev;
491 int ret;
492
Dominik Behr93899452014-08-18 22:16:21 -0700493 if (FD_ISSET(input.udev_fd, exception_set)) {
494 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700495 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700496 }
497
Dominik Behr93899452014-08-18 22:16:21 -0700498 if (FD_ISSET(input.udev_fd, read_set)
499 && !FD_ISSET(input.udev_fd, exception_set)) {
500 /* we got an udev notification */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800501 struct udev_device* dev =
Dominik Behr93899452014-08-18 22:16:21 -0700502 udev_monitor_receive_device(input.udev_monitor);
503 if (dev) {
504 if (!strcmp("add", udev_device_get_action(dev))) {
505 input_add(udev_device_get_devnode(dev));
506 } else
507 if (!strcmp("remove", udev_device_get_action(dev)))
508 {
509 input_remove(udev_device_get_devnode(dev));
510 }
511 udev_device_unref(dev);
512 }
513 }
514
515 for (u = 0; u < input.ndevs; u++) {
516 if (FD_ISSET(input.devs[u].fd, read_set)
517 && !FD_ISSET(input.devs[u].fd, exception_set)) {
518 ret =
519 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400520 if (ret < 0) {
521 if (errno == EINTR || errno == EAGAIN)
522 continue;
523 if (errno != ENODEV) {
524 LOG(ERROR, "read: %s: %s", input.devs[u].path,
525 strerror(errno));
526 }
527 input_remove(input.devs[u].path);
528 return NULL;
529 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700530 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700531 (int) sizeof (struct input_event), ret);
532 return NULL;
533 }
534
535 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800536 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700537 malloc(sizeof (*event));
538 event->code = ev.code;
539 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700540 return event;
541 }
542 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700543 }
544
545 return NULL;
546}
547
David Sodmanf0a925a2015-05-04 11:19:19 -0700548int input_process(terminal_t* splash_term, uint32_t usec)
549{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800550 terminal_t* terminal;
551 terminal_t* new_terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700552 fd_set read_set, exception_set;
553 int maxfd;
554 int sstat;
555 struct timeval tm;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800556 struct timeval* ptm;
David Sodmanf0a925a2015-05-04 11:19:19 -0700557
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800558 terminal = term_get_terminal(input.current_terminal);
David Sodmanf0a925a2015-05-04 11:19:19 -0700559
560 FD_ZERO(&read_set);
561 FD_ZERO(&exception_set);
562
563 if (input.dbus) {
564 dbus_add_fd(input.dbus, &read_set, &exception_set);
565 maxfd = dbus_get_fd(input.dbus) + 1;
566 } else {
567 maxfd = 0;
568 }
569
570 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
571
572 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800573 if (term_is_valid(term_get_terminal(i))) {
574 term_add_fd(term_get_terminal(i), &read_set, &exception_set);
575 maxfd = MAX(maxfd, term_fd(term_get_terminal(i))) + 1;
576 term_dispatch_io(term_get_terminal(i), &read_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700577 }
578 }
579
580 if (usec) {
581 ptm = &tm;
582 tm.tv_sec = 0;
583 tm.tv_usec = usec;
584 } else
585 ptm = NULL;
586
587 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
588 if (sstat == 0)
589 return 0;
590
David Sodmanf0a925a2015-05-04 11:19:19 -0700591 if (input.dbus)
592 dbus_dispatch_io(input.dbus);
593
594 if (term_exception(terminal, &exception_set))
595 return -1;
596
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800597 struct input_key_event* event;
David Sodmanf0a925a2015-05-04 11:19:19 -0700598 event = input_get_event(&read_set, &exception_set);
599 if (event) {
600 if (!input_special_key(event) && event->value) {
601 uint32_t keysym, unicode;
602 // current_terminal can possibly change during
603 // execution of input_special_key
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800604 terminal = term_get_terminal(input.current_terminal);
David Sodmanf0a925a2015-05-04 11:19:19 -0700605 if (term_is_active(terminal)) {
606 // Only report user activity when the terminal is active
607 report_user_activity(USER_ACTIVITY_OTHER);
608 input_get_keysym_and_unicode(
609 event, &keysym, &unicode);
610 term_key_event(terminal,
611 keysym, unicode);
612 }
613 }
614 input_put_event(event);
615 }
616
617 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800618 if (term_is_valid(term_get_terminal(i))) {
619 term_add_fd(term_get_terminal(i), &read_set, &exception_set);
620 term_dispatch_io(term_get_terminal(i), &read_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700621 }
622 }
623
624 if (term_is_valid(terminal)) {
625 if (term_is_child_done(terminal)) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800626 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700627 /*
628 * Note: reference is not lost because it is still referenced
629 * by the splash_t structure which will ultimately destroy
630 * it, once it's safe to do so
631 */
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800632 term_set_terminal(SPLASH_TERMINAL, NULL);
David Sodmanf0a925a2015-05-04 11:19:19 -0700633 return -1;
634 }
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800635 term_set_terminal(input.current_terminal,
636 term_init(true, term_getvideo(terminal)));
637 new_terminal = term_get_terminal(input.current_terminal);
David Sodmanf0a925a2015-05-04 11:19:19 -0700638 if (!term_is_valid(new_terminal)) {
639 return -1;
640 }
641 term_activate(new_terminal);
642 term_close(terminal);
643 }
644 }
645
646 return 0;
647}
648
David Sodmanbf3f2842014-11-12 08:26:58 -0800649int input_run(bool standalone)
650{
David Sodmanbf3f2842014-11-12 08:26:58 -0800651 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700652 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800653
654 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800655 if (input.dbus) {
656 (void)dbus_method_call0(input.dbus,
657 kLibCrosServiceName,
658 kLibCrosServicePath,
659 kLibCrosServiceInterface,
660 kReleaseDisplayOwnership);
661 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800662
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800663 term_set_terminal(input.current_terminal, term_init(true, NULL));
664 terminal = term_get_terminal(input.current_terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800665 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800666 }
667
668 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700669 status = input_process(NULL, 0);
670 if (status != 0) {
671 LOG(ERROR, "input process returned %d", status);
672 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800673 }
674 }
675
676 return 0;
677}
678
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800679void input_put_event(struct input_key_event* event)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700680{
681 free(event);
682}
David Sodmanbbcb0522014-09-19 10:34:07 -0700683
Stéphane Marchesine38b8e72016-01-07 19:20:28 -0800684terminal_t* input_get_current_term()
685{
686 return term_get_terminal(input.current_terminal);
687}
688
David Sodman8ef20062015-01-06 09:23:40 -0800689void input_set_current(terminal_t* terminal)
690{
David Sodmanf0a925a2015-05-04 11:19:19 -0700691 if (!terminal) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800692 term_set_terminal(input.current_terminal, NULL);
David Sodmanf0a925a2015-05-04 11:19:19 -0700693 input.current_terminal = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800694 return;
David Sodmanf0a925a2015-05-04 11:19:19 -0700695 }
David Sodman8ef20062015-01-06 09:23:40 -0800696
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800697 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800698 if (terminal == term_get_terminal(i)) {
David Sodman8ef20062015-01-06 09:23:40 -0800699 input.current_terminal = i;
700 return;
701 }
702 }
703}