blob: ecc4544cd7cf127b2c0e05f1b88cb24c77bb10a2 [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_interface.h"
19#include "dbus.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
David Sodmanf0a925a2015-05-04 11:19:19 -070024#define MAX_STD_TERMINALS (3)
25#define NUM_SPLASH_TERMINAL (1)
26#define MAX_TERMINALS (MAX_STD_TERMINALS + NUM_SPLASH_TERMINAL)
27#define SPLASH_TERMINAL (MAX_TERMINALS - 1)
David Sodmanbf3f2842014-11-12 08:26:58 -080028
Dominik Behr93899452014-08-18 22:16:21 -070029struct input_dev {
30 int fd;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080031 char* path;
Dominik Behr93899452014-08-18 22:16:21 -070032};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070033
David Sodmanbf3f2842014-11-12 08:26:58 -080034struct keyboard_state {
35 int shift_state;
36 int control_state;
37 int alt_state;
David Sodmane0cc8312014-11-18 11:16:36 -080038 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080039};
40
Dylan Reid342aed02015-06-18 12:15:52 -070041/*
42 * structure to keep input state:
43 * udev - for udev events.
44 * udev_monitor - used to listen for udev events.
45 * udev_fd - to poll for udev messages.
46 * ndevs - number of input devices.
47 * devs - input devices to listen to.
48 * kbd_state - tracks modifier keys that are pressed.
49 * dbus - where to send dbus events.
50 * current_terminal - the currently selected terminal.
51 * terminals - list of all terminals that have been created.
52 */
Dominik Behr93899452014-08-18 22:16:21 -070053struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080054 struct udev* udev;
55 struct udev_monitor* udev_monitor;
Dominik Behr93899452014-08-18 22:16:21 -070056 int udev_fd;
57 unsigned int ndevs;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080058 struct input_dev* devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080059 struct keyboard_state kbd_state;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080060 dbus_t* dbus;
61 uint32_t current_terminal;
62 terminal_t* terminals[MAX_TERMINALS];
Dominik Behr93899452014-08-18 22:16:21 -070063} input = {
64 .udev = NULL,
65 .udev_monitor = NULL,
66 .udev_fd = -1,
67 .ndevs = 0,
68 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080069 .dbus = NULL,
70 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070071};
72
David Sodmane0cc8312014-11-18 11:16:36 -080073static void report_user_activity(int activity_type)
74{
David Sodman19e4f9d2015-03-10 11:11:09 -070075 dbus_bool_t allow_off = false;
David Sodman8ef20062015-01-06 09:23:40 -080076 if (!input.dbus)
77 return;
78
David Sodmane0cc8312014-11-18 11:16:36 -080079 dbus_method_call1(input.dbus, kPowerManagerServiceName,
80 kPowerManagerServicePath,
81 kPowerManagerInterface,
82 kHandleUserActivityMethod,
David Sodman19e4f9d2015-03-10 11:11:09 -070083 DBUS_TYPE_INT32, &activity_type);
David Sodmane0cc8312014-11-18 11:16:36 -080084
85 switch (activity_type) {
86 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
87 (void)dbus_method_call0(input.dbus,
88 kPowerManagerServiceName,
89 kPowerManagerServicePath,
90 kPowerManagerInterface,
91 kIncreaseScreenBrightnessMethod);
92 break;
93 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
David Sodman19e4f9d2015-03-10 11:11:09 -070094 /*
95 * Shouldn't allow the screen to go
96 * completely off while frecon is active
97 * so passing false to allow_off
98 */
99 (void)dbus_method_call1(input.dbus,
David Sodmane0cc8312014-11-18 11:16:36 -0800100 kPowerManagerServiceName,
101 kPowerManagerServicePath,
102 kPowerManagerInterface,
David Sodman19e4f9d2015-03-10 11:11:09 -0700103 kDecreaseScreenBrightnessMethod,
104 DBUS_TYPE_BOOLEAN, &allow_off);
David Sodmane0cc8312014-11-18 11:16:36 -0800105 break;
106 }
107}
108
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800109static int input_special_key(struct input_key_event* ev)
David Sodmanbf3f2842014-11-12 08:26:58 -0800110{
111 unsigned int i;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800112 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -0800113
114 uint32_t ignore_keys[] = {
115 BTN_TOUCH, // touchpad events
116 BTN_TOOL_FINGER,
117 BTN_TOOL_DOUBLETAP,
118 BTN_TOOL_TRIPLETAP,
119 BTN_TOOL_QUADTAP,
120 BTN_TOOL_QUINTTAP,
121 BTN_LEFT, // mouse buttons
122 BTN_RIGHT,
123 BTN_MIDDLE,
124 BTN_SIDE,
125 BTN_EXTRA,
126 BTN_FORWARD,
127 BTN_BACK,
128 BTN_TASK
129 };
130
David Sodmanafba0d92015-01-27 19:07:46 -0800131 terminal = input.terminals[input.current_terminal];
132
David Sodmanbf3f2842014-11-12 08:26:58 -0800133 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
134 if (ev->code == ignore_keys[i])
135 return 1;
136
137 switch (ev->code) {
138 case KEY_LEFTSHIFT:
139 case KEY_RIGHTSHIFT:
140 input.kbd_state.shift_state = ! !ev->value;
141 return 1;
142 case KEY_LEFTCTRL:
143 case KEY_RIGHTCTRL:
144 input.kbd_state.control_state = ! !ev->value;
145 return 1;
146 case KEY_LEFTALT:
147 case KEY_RIGHTALT:
148 input.kbd_state.alt_state = ! !ev->value;
149 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800150 case KEY_LEFTMETA: // search key
151 input.kbd_state.search_state = ! !ev->value;
152 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800153 }
154
David Sodmanafba0d92015-01-27 19:07:46 -0800155 if (term_is_active(terminal)) {
156 if (input.kbd_state.shift_state && ev->value) {
157 switch (ev->code) {
158 case KEY_PAGEUP:
David Sodmane0cc8312014-11-18 11:16:36 -0800159 term_page_up(input.terminals[input.current_terminal]);
160 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800161 case KEY_PAGEDOWN:
David Sodmane0cc8312014-11-18 11:16:36 -0800162 term_page_down(input.terminals[input.current_terminal]);
163 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800164 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700165 if (input.kbd_state.search_state)
166 term_page_up(input.terminals[input.current_terminal]);
167 else
168 term_line_up(input.terminals[input.current_terminal]);
David Sodmanafba0d92015-01-27 19:07:46 -0800169 return 1;
170 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700171 if (input.kbd_state.search_state)
David Sodmanafba0d92015-01-27 19:07:46 -0800172 term_page_down(input.terminals[input.current_terminal]);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700173 else
174 term_line_down(input.terminals[input.current_terminal]);
175 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800176 }
177 }
178
179 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
180 input.kbd_state.control_state) &&
181 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
182 switch (ev->code) {
183 case KEY_F1:
184 case KEY_F2:
185 case KEY_F3:
186 case KEY_F4:
187 case KEY_F5:
188 break;
189 case KEY_F6:
190 case KEY_F7:
191 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
192 (ev->code - KEY_F6));
193 break;
194 case KEY_F8:
195 case KEY_F9:
196 case KEY_F10:
197 break;
198 }
199 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800200 }
201 }
202
David Sodmanbf3f2842014-11-12 08:26:58 -0800203 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700204 /*
205 * Special case for key sequence that is used by external program. Just
206 * explicitly ignore here and do nothing.
207 */
208 if (input.kbd_state.shift_state)
209 return 1;
210
David Sodmanb0697c22014-12-12 10:29:25 -0800211 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800212 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700213 term_deactivate(terminal);
214 if (input.terminals[SPLASH_TERMINAL] != NULL) {
215 term_activate(input.terminals[SPLASH_TERMINAL]);
216 } else {
217 if (input.dbus != NULL)
218 (void)dbus_method_call0(input.dbus,
219 kLibCrosServiceName,
220 kLibCrosServicePath,
221 kLibCrosServiceInterface,
222 kTakeDisplayOwnership);
223 }
David Sodman8ef20062015-01-06 09:23:40 -0800224 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700225 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
David Sodman8ef20062015-01-06 09:23:40 -0800226 if (input.dbus != NULL)
David Sodmanbf3f2842014-11-12 08:26:58 -0800227 (void)dbus_method_call0(input.dbus,
228 kLibCrosServiceName,
229 kLibCrosServicePath,
230 kLibCrosServiceInterface,
David Sodman8ef20062015-01-06 09:23:40 -0800231 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800232 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700233 term_deactivate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800234 input.current_terminal = ev->code - KEY_F2;
235 terminal = input.terminals[input.current_terminal];
236 if (terminal == NULL) {
237 input.terminals[input.current_terminal] =
David Sodmanf0a925a2015-05-04 11:19:19 -0700238 term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800239 terminal =
240 input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800241 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800242 if (!term_is_valid(terminal)) {
243 LOG(ERROR, "Term init failed");
244 return 1;
245 }
246 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700247 term_activate(input.terminals[input.current_terminal]);
David Sodmanbf3f2842014-11-12 08:26:58 -0800248 }
249
250 return 1;
251
252 }
253
254 return 0;
255}
256
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800257static void input_get_keysym_and_unicode(struct input_key_event* event,
258 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800259{
260 struct {
261 uint32_t code;
262 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700263 } search_keys[] = {
264 { KEY_F1, KEYSYM_F1},
265 { KEY_F2, KEYSYM_F2},
266 { KEY_F3, KEYSYM_F3},
267 { KEY_F4, KEYSYM_F4},
268 { KEY_F5, KEYSYM_F5},
269 { KEY_F6, KEYSYM_F6},
270 { KEY_F7, KEYSYM_F7},
271 { KEY_F8, KEYSYM_F8},
272 { KEY_F9, KEYSYM_F8},
273 { KEY_F10, KEYSYM_F10},
274 { KEY_UP, KEYSYM_PAGEUP},
275 { KEY_DOWN, KEYSYM_PAGEDOWN},
276 { KEY_LEFT, KEYSYM_HOME},
277 { KEY_RIGHT, KEYSYM_END},
278 };
279
280 struct {
281 uint32_t code;
282 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800283 } non_ascii_keys[] = {
284 { KEY_ESC, KEYSYM_ESC},
285 { KEY_HOME, KEYSYM_HOME},
286 { KEY_LEFT, KEYSYM_LEFT},
287 { KEY_UP, KEYSYM_UP},
288 { KEY_RIGHT, KEYSYM_RIGHT},
289 { KEY_DOWN, KEYSYM_DOWN},
290 { KEY_PAGEUP, KEYSYM_PAGEUP},
291 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
292 { KEY_END, KEYSYM_END},
293 { KEY_INSERT, KEYSYM_INSERT},
294 { KEY_DELETE, KEYSYM_DELETE},
295 };
296
Dominik Behr58bb8e12015-09-22 14:30:41 -0700297 if (input.kbd_state.search_state) {
298 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
299 if (search_keys[i].code == event->code) {
300 *keysym = search_keys[i].keysym;
301 *unicode = -1;
302 return;
303 }
304 }
305 }
306
David Sodmanbf3f2842014-11-12 08:26:58 -0800307 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
308 if (non_ascii_keys[i].code == event->code) {
309 *keysym = non_ascii_keys[i].keysym;
310 *unicode = -1;
311 return;
312 }
313 }
314
315 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
316 *keysym = '?';
317 } else {
318 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
319 if ((input.kbd_state.control_state) && isascii(*keysym))
320 *keysym = tolower(*keysym) - 'a' + 1;
321 }
322
323 *unicode = *keysym;
324}
325
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800326static int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700327{
Dominik Behr93899452014-08-18 22:16:21 -0700328 int ret = 0, fd = -1;
Haixia Shid288e032015-09-14 18:33:11 -0700329 unsigned int i;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800330
Dominik Behr93899452014-08-18 22:16:21 -0700331 /* for some reason every device has a null enumerations and notifications
332 of every device come with NULL string first */
333 if (!devname) {
334 ret = -EINVAL;
335 goto errorret;
336 }
Haixia Shid288e032015-09-14 18:33:11 -0700337 /* check for duplicates */
338 for (i = 0; i < input.ndevs; ++i) {
339 if (strcmp(devname, input.devs[i].path) == 0) {
340 LOG(WARNING, "Skipping duplicate input device %s", devname);
341 ret = -EINVAL;
342 goto errorret;
343 }
344 }
Dominik Behr93899452014-08-18 22:16:21 -0700345 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700346 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700347 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700348
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800349 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700350 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800351 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700352 if (ret)
353 LOG(ERROR,
354 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
355 } else {
356 LOG(ERROR, "Evdev device %s grabbed by another process",
357 devname);
358 ret = -EBUSY;
359 goto closefd;
360 }
361
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800362 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700363 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
364 if (!newdevs) {
365 ret = -ENOMEM;
366 goto closefd;
367 }
368 input.devs = newdevs;
369 input.devs[input.ndevs].fd = fd;
370 input.devs[input.ndevs].path = strdup(devname);
371 if (!input.devs[input.ndevs].path) {
372 ret = -ENOMEM;
373 goto closefd;
374 }
375 input.ndevs++;
376
377 return fd;
378
379closefd:
380 close(fd);
381errorret:
382 return ret;
383}
384
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800385static void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700386{
Dominik Behr93899452014-08-18 22:16:21 -0700387 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800388
389 if (!devname)
390 return;
391
Dominik Behr93899452014-08-18 22:16:21 -0700392 for (u = 0; u < input.ndevs; u++) {
393 if (!strcmp(devname, input.devs[u].path)) {
394 free(input.devs[u].path);
395 close(input.devs[u].fd);
396 input.ndevs--;
397 if (u != input.ndevs) {
398 input.devs[u] = input.devs[input.ndevs];
399 }
400 return;
401 }
402 }
403}
404
Dominik Behr93899452014-08-18 22:16:21 -0700405
406int input_init()
407{
408 input.udev = udev_new();
409 if (!input.udev)
410 return -ENOENT;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800411
Dominik Behr93899452014-08-18 22:16:21 -0700412 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
413 if (!input.udev_monitor) {
414 udev_unref(input.udev);
415 return -ENOENT;
416 }
417 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
418 NULL);
419 udev_monitor_enable_receiving(input.udev_monitor);
420 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
421
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800422 struct udev_enumerate* udev_enum;
423 struct udev_list_entry* devices, *deventry;
Dominik Behr93899452014-08-18 22:16:21 -0700424 udev_enum = udev_enumerate_new(input.udev);
425 udev_enumerate_add_match_subsystem(udev_enum, "input");
426 udev_enumerate_scan_devices(udev_enum);
427 devices = udev_enumerate_get_list_entry(udev_enum);
428 udev_list_entry_foreach(deventry, devices) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800429 const char* syspath;
430 struct udev_device* dev;
Dominik Behr93899452014-08-18 22:16:21 -0700431 syspath = udev_list_entry_get_name(deventry);
432 dev = udev_device_new_from_syspath(input.udev, syspath);
433 input_add(udev_device_get_devnode(dev));
434 udev_device_unref(dev);
435 }
436 udev_enumerate_unref(udev_enum);
437
438 if (!isatty(fileno(stdout)))
439 setbuf(stdout, NULL);
440
David Sodmanbbcb0522014-09-19 10:34:07 -0700441 if (input.ndevs == 0) {
442 LOG(ERROR, "No valid inputs for terminal");
443 exit(EXIT_SUCCESS);
444 }
445
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700446 return 0;
447}
448
449void input_close()
450{
Dominik Behr93899452014-08-18 22:16:21 -0700451 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800452
Dominik Behr93899452014-08-18 22:16:21 -0700453 for (u = 0; u < input.ndevs; u++) {
454 free(input.devs[u].path);
455 close(input.devs[u].fd);
456 }
457 free(input.devs);
458 input.devs = NULL;
459 input.ndevs = 0;
460
461 udev_monitor_unref(input.udev_monitor);
462 input.udev_monitor = NULL;
463 udev_unref(input.udev);
464 input.udev = NULL;
465 input.udev_fd = -1;
466
David Sodmanbbcb0522014-09-19 10:34:07 -0700467 dbus_destroy(input.dbus);
468
469}
470
471void input_set_dbus(dbus_t* dbus)
472{
473 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700474}
475
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800476int input_setfds(fd_set* read_set, fd_set* exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700477{
Dominik Behr93899452014-08-18 22:16:21 -0700478 unsigned int u;
479 int max = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800480
Dominik Behr93899452014-08-18 22:16:21 -0700481 for (u = 0; u < input.ndevs; u++) {
482 FD_SET(input.devs[u].fd, read_set);
483 FD_SET(input.devs[u].fd, exception_set);
484 if (input.devs[u].fd > max)
485 max = input.devs[u].fd;
486 }
487
488 FD_SET(input.udev_fd, read_set);
489 FD_SET(input.udev_fd, exception_set);
490 if (input.udev_fd > max)
491 max = input.udev_fd;
492 return max;
493}
494
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800495struct input_key_event* input_get_event(fd_set* read_set,
496 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700497{
498 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700499 struct input_event ev;
500 int ret;
501
Dominik Behr93899452014-08-18 22:16:21 -0700502 if (FD_ISSET(input.udev_fd, exception_set)) {
503 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700504 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700505 }
506
Dominik Behr93899452014-08-18 22:16:21 -0700507 if (FD_ISSET(input.udev_fd, read_set)
508 && !FD_ISSET(input.udev_fd, exception_set)) {
509 /* we got an udev notification */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800510 struct udev_device* dev =
Dominik Behr93899452014-08-18 22:16:21 -0700511 udev_monitor_receive_device(input.udev_monitor);
512 if (dev) {
513 if (!strcmp("add", udev_device_get_action(dev))) {
514 input_add(udev_device_get_devnode(dev));
515 } else
516 if (!strcmp("remove", udev_device_get_action(dev)))
517 {
518 input_remove(udev_device_get_devnode(dev));
519 }
520 udev_device_unref(dev);
521 }
522 }
523
524 for (u = 0; u < input.ndevs; u++) {
525 if (FD_ISSET(input.devs[u].fd, read_set)
526 && !FD_ISSET(input.devs[u].fd, exception_set)) {
527 ret =
528 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400529 if (ret < 0) {
530 if (errno == EINTR || errno == EAGAIN)
531 continue;
532 if (errno != ENODEV) {
533 LOG(ERROR, "read: %s: %s", input.devs[u].path,
534 strerror(errno));
535 }
536 input_remove(input.devs[u].path);
537 return NULL;
538 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700539 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700540 (int) sizeof (struct input_event), ret);
541 return NULL;
542 }
543
544 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800545 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700546 malloc(sizeof (*event));
547 event->code = ev.code;
548 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700549 return event;
550 }
551 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700552 }
553
554 return NULL;
555}
556
David Sodmanf0a925a2015-05-04 11:19:19 -0700557int input_process(terminal_t* splash_term, uint32_t usec)
558{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800559 terminal_t* terminal;
560 terminal_t* new_terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700561 fd_set read_set, exception_set;
562 int maxfd;
563 int sstat;
564 struct timeval tm;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800565 struct timeval* ptm;
David Sodmanf0a925a2015-05-04 11:19:19 -0700566
567 terminal = input.terminals[input.current_terminal];
568
569 FD_ZERO(&read_set);
570 FD_ZERO(&exception_set);
571
572 if (input.dbus) {
573 dbus_add_fd(input.dbus, &read_set, &exception_set);
574 maxfd = dbus_get_fd(input.dbus) + 1;
575 } else {
576 maxfd = 0;
577 }
578
579 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
580
581 for (int i = 0; i < MAX_TERMINALS; i++) {
582 if (term_is_valid(input.terminals[i])) {
583 term_add_fd(input.terminals[i], &read_set, &exception_set);
584 maxfd = MAX(maxfd, term_fd(input.terminals[i])) + 1;
585 term_dispatch_io(input.terminals[i], &read_set);
586 }
587 }
588
589 if (usec) {
590 ptm = &tm;
591 tm.tv_sec = 0;
592 tm.tv_usec = usec;
593 } else
594 ptm = NULL;
595
596 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
597 if (sstat == 0)
598 return 0;
599
David Sodmanf0a925a2015-05-04 11:19:19 -0700600 if (input.dbus)
601 dbus_dispatch_io(input.dbus);
602
603 if (term_exception(terminal, &exception_set))
604 return -1;
605
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800606 struct input_key_event* event;
David Sodmanf0a925a2015-05-04 11:19:19 -0700607 event = input_get_event(&read_set, &exception_set);
608 if (event) {
609 if (!input_special_key(event) && event->value) {
610 uint32_t keysym, unicode;
611 // current_terminal can possibly change during
612 // execution of input_special_key
613 terminal = input.terminals[input.current_terminal];
614 if (term_is_active(terminal)) {
615 // Only report user activity when the terminal is active
616 report_user_activity(USER_ACTIVITY_OTHER);
617 input_get_keysym_and_unicode(
618 event, &keysym, &unicode);
619 term_key_event(terminal,
620 keysym, unicode);
621 }
622 }
623 input_put_event(event);
624 }
625
626 for (int i = 0; i < MAX_TERMINALS; i++) {
627 if (term_is_valid(input.terminals[i])) {
628 term_add_fd(input.terminals[i], &read_set, &exception_set);
629 term_dispatch_io(input.terminals[i], &read_set);
630 }
631 }
632
633 if (term_is_valid(terminal)) {
634 if (term_is_child_done(terminal)) {
635 if (terminal == input.terminals[SPLASH_TERMINAL]) {
636 /*
637 * Note: reference is not lost because it is still referenced
638 * by the splash_t structure which will ultimately destroy
639 * it, once it's safe to do so
640 */
641 input.terminals[SPLASH_TERMINAL] = NULL;
642 return -1;
643 }
David Sodman30a94ef2015-07-26 17:37:12 -0700644 input.terminals[input.current_terminal] =
645 term_init(true, term_getvideo(terminal));
David Sodmanf0a925a2015-05-04 11:19:19 -0700646 new_terminal = input.terminals[input.current_terminal];
647 if (!term_is_valid(new_terminal)) {
648 return -1;
649 }
650 term_activate(new_terminal);
651 term_close(terminal);
652 }
653 }
654
655 return 0;
656}
657
David Sodmanbf3f2842014-11-12 08:26:58 -0800658int input_run(bool standalone)
659{
David Sodmanbf3f2842014-11-12 08:26:58 -0800660 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700661 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800662
663 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800664 if (input.dbus) {
665 (void)dbus_method_call0(input.dbus,
666 kLibCrosServiceName,
667 kLibCrosServicePath,
668 kLibCrosServiceInterface,
669 kReleaseDisplayOwnership);
670 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800671
David Sodmanf0a925a2015-05-04 11:19:19 -0700672 input.terminals[input.current_terminal] = term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800673 terminal = input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800674 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800675 }
676
677 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700678 status = input_process(NULL, 0);
679 if (status != 0) {
680 LOG(ERROR, "input process returned %d", status);
681 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800682 }
683 }
684
685 return 0;
686}
687
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800688void input_put_event(struct input_key_event* event)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700689{
690 free(event);
691}
David Sodmanbbcb0522014-09-19 10:34:07 -0700692
David Sodman8ef20062015-01-06 09:23:40 -0800693terminal_t* input_create_term(int vt)
694{
695 terminal_t* terminal;
696
697 if (vt == 0)
698 return input.terminals[input.current_terminal];
699
700 terminal = input.terminals[vt-1];
701 if (term_is_active(terminal))
702 return terminal;
703
704 if (terminal == NULL) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700705 input.terminals[vt-1] = term_init(false, NULL);
David Sodman8ef20062015-01-06 09:23:40 -0800706 terminal = input.terminals[vt-1];
707 if (!term_is_valid(terminal)) {
708 LOG(ERROR, "create_term: Term init failed");
709 }
710 }
711
712 return terminal;
713}
714
David Sodmanf0a925a2015-05-04 11:19:19 -0700715terminal_t* input_create_splash_term(video_t* video)
716{
717 input.terminals[SPLASH_TERMINAL] = term_init(false, video);
718 return input.terminals[SPLASH_TERMINAL];
719}
720
721void input_destroy_splash_term()
722{
723 input.terminals[SPLASH_TERMINAL] = NULL;
724}
725
David Sodman8ef20062015-01-06 09:23:40 -0800726void input_set_current(terminal_t* terminal)
727{
728 int i;
729
David Sodmanf0a925a2015-05-04 11:19:19 -0700730 if (!terminal) {
731 input.terminals[input.current_terminal] = NULL;
732 input.current_terminal = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800733 return;
David Sodmanf0a925a2015-05-04 11:19:19 -0700734 }
David Sodman8ef20062015-01-06 09:23:40 -0800735
736 for (i = 0; i < MAX_TERMINALS; i++) {
737 if (terminal == input.terminals[i]) {
738 input.current_terminal = i;
739 return;
740 }
741 }
742}
743
744unsigned int input_get_maxterminals()
745{
David Sodmanf0a925a2015-05-04 11:19:19 -0700746 return MAX_STD_TERMINALS;
David Sodman8ef20062015-01-06 09:23:40 -0800747}