blob: d94a57b7e792b81f0ab1c9af3cd5f0a4611c6823 [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;
Dominik Behr93899452014-08-18 22:16:21 -0700330 /* for some reason every device has a null enumerations and notifications
331 of every device come with NULL string first */
332 if (!devname) {
333 ret = -EINVAL;
334 goto errorret;
335 }
Haixia Shid288e032015-09-14 18:33:11 -0700336 /* check for duplicates */
337 for (i = 0; i < input.ndevs; ++i) {
338 if (strcmp(devname, input.devs[i].path) == 0) {
339 LOG(WARNING, "Skipping duplicate input device %s", devname);
340 ret = -EINVAL;
341 goto errorret;
342 }
343 }
Dominik Behr93899452014-08-18 22:16:21 -0700344 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700345 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700346 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700347
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800348 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700349 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800350 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700351 if (ret)
352 LOG(ERROR,
353 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
354 } else {
355 LOG(ERROR, "Evdev device %s grabbed by another process",
356 devname);
357 ret = -EBUSY;
358 goto closefd;
359 }
360
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800361 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700362 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
363 if (!newdevs) {
364 ret = -ENOMEM;
365 goto closefd;
366 }
367 input.devs = newdevs;
368 input.devs[input.ndevs].fd = fd;
369 input.devs[input.ndevs].path = strdup(devname);
370 if (!input.devs[input.ndevs].path) {
371 ret = -ENOMEM;
372 goto closefd;
373 }
374 input.ndevs++;
375
376 return fd;
377
378closefd:
379 close(fd);
380errorret:
381 return ret;
382}
383
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800384static void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700385{
386 if (!devname) {
387 return;
388 }
389 unsigned int u;
390 for (u = 0; u < input.ndevs; u++) {
391 if (!strcmp(devname, input.devs[u].path)) {
392 free(input.devs[u].path);
393 close(input.devs[u].fd);
394 input.ndevs--;
395 if (u != input.ndevs) {
396 input.devs[u] = input.devs[input.ndevs];
397 }
398 return;
399 }
400 }
401}
402
Dominik Behr93899452014-08-18 22:16:21 -0700403
404int input_init()
405{
406 input.udev = udev_new();
407 if (!input.udev)
408 return -ENOENT;
409 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
410 if (!input.udev_monitor) {
411 udev_unref(input.udev);
412 return -ENOENT;
413 }
414 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
415 NULL);
416 udev_monitor_enable_receiving(input.udev_monitor);
417 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
418
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800419 struct udev_enumerate* udev_enum;
420 struct udev_list_entry* devices, *deventry;
Dominik Behr93899452014-08-18 22:16:21 -0700421 udev_enum = udev_enumerate_new(input.udev);
422 udev_enumerate_add_match_subsystem(udev_enum, "input");
423 udev_enumerate_scan_devices(udev_enum);
424 devices = udev_enumerate_get_list_entry(udev_enum);
425 udev_list_entry_foreach(deventry, devices) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800426 const char* syspath;
427 struct udev_device* dev;
Dominik Behr93899452014-08-18 22:16:21 -0700428 syspath = udev_list_entry_get_name(deventry);
429 dev = udev_device_new_from_syspath(input.udev, syspath);
430 input_add(udev_device_get_devnode(dev));
431 udev_device_unref(dev);
432 }
433 udev_enumerate_unref(udev_enum);
434
435 if (!isatty(fileno(stdout)))
436 setbuf(stdout, NULL);
437
David Sodmanbbcb0522014-09-19 10:34:07 -0700438 if (input.ndevs == 0) {
439 LOG(ERROR, "No valid inputs for terminal");
440 exit(EXIT_SUCCESS);
441 }
442
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700443 return 0;
444}
445
446void input_close()
447{
Dominik Behr93899452014-08-18 22:16:21 -0700448 unsigned int u;
449 for (u = 0; u < input.ndevs; u++) {
450 free(input.devs[u].path);
451 close(input.devs[u].fd);
452 }
453 free(input.devs);
454 input.devs = NULL;
455 input.ndevs = 0;
456
457 udev_monitor_unref(input.udev_monitor);
458 input.udev_monitor = NULL;
459 udev_unref(input.udev);
460 input.udev = NULL;
461 input.udev_fd = -1;
462
David Sodmanbbcb0522014-09-19 10:34:07 -0700463 dbus_destroy(input.dbus);
464
465}
466
467void input_set_dbus(dbus_t* dbus)
468{
469 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700470}
471
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800472int input_setfds(fd_set* read_set, fd_set* exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700473{
Dominik Behr93899452014-08-18 22:16:21 -0700474 unsigned int u;
475 int max = -1;
476 for (u = 0; u < input.ndevs; u++) {
477 FD_SET(input.devs[u].fd, read_set);
478 FD_SET(input.devs[u].fd, exception_set);
479 if (input.devs[u].fd > max)
480 max = input.devs[u].fd;
481 }
482
483 FD_SET(input.udev_fd, read_set);
484 FD_SET(input.udev_fd, exception_set);
485 if (input.udev_fd > max)
486 max = input.udev_fd;
487 return max;
488}
489
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800490struct input_key_event* input_get_event(fd_set* read_set,
491 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700492{
493 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700494 struct input_event ev;
495 int ret;
496
Dominik Behr93899452014-08-18 22:16:21 -0700497 if (FD_ISSET(input.udev_fd, exception_set)) {
498 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700499 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700500 }
501
Dominik Behr93899452014-08-18 22:16:21 -0700502 if (FD_ISSET(input.udev_fd, read_set)
503 && !FD_ISSET(input.udev_fd, exception_set)) {
504 /* we got an udev notification */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800505 struct udev_device* dev =
Dominik Behr93899452014-08-18 22:16:21 -0700506 udev_monitor_receive_device(input.udev_monitor);
507 if (dev) {
508 if (!strcmp("add", udev_device_get_action(dev))) {
509 input_add(udev_device_get_devnode(dev));
510 } else
511 if (!strcmp("remove", udev_device_get_action(dev)))
512 {
513 input_remove(udev_device_get_devnode(dev));
514 }
515 udev_device_unref(dev);
516 }
517 }
518
519 for (u = 0; u < input.ndevs; u++) {
520 if (FD_ISSET(input.devs[u].fd, read_set)
521 && !FD_ISSET(input.devs[u].fd, exception_set)) {
522 ret =
523 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400524 if (ret < 0) {
525 if (errno == EINTR || errno == EAGAIN)
526 continue;
527 if (errno != ENODEV) {
528 LOG(ERROR, "read: %s: %s", input.devs[u].path,
529 strerror(errno));
530 }
531 input_remove(input.devs[u].path);
532 return NULL;
533 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700534 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700535 (int) sizeof (struct input_event), ret);
536 return NULL;
537 }
538
539 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800540 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700541 malloc(sizeof (*event));
542 event->code = ev.code;
543 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700544 return event;
545 }
546 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700547 }
548
549 return NULL;
550}
551
David Sodmanf0a925a2015-05-04 11:19:19 -0700552int input_process(terminal_t* splash_term, uint32_t usec)
553{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800554 terminal_t* terminal;
555 terminal_t* new_terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700556 fd_set read_set, exception_set;
557 int maxfd;
558 int sstat;
559 struct timeval tm;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800560 struct timeval* ptm;
David Sodmanf0a925a2015-05-04 11:19:19 -0700561
562 terminal = input.terminals[input.current_terminal];
563
564 FD_ZERO(&read_set);
565 FD_ZERO(&exception_set);
566
567 if (input.dbus) {
568 dbus_add_fd(input.dbus, &read_set, &exception_set);
569 maxfd = dbus_get_fd(input.dbus) + 1;
570 } else {
571 maxfd = 0;
572 }
573
574 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
575
576 for (int i = 0; i < MAX_TERMINALS; i++) {
577 if (term_is_valid(input.terminals[i])) {
578 term_add_fd(input.terminals[i], &read_set, &exception_set);
579 maxfd = MAX(maxfd, term_fd(input.terminals[i])) + 1;
580 term_dispatch_io(input.terminals[i], &read_set);
581 }
582 }
583
584 if (usec) {
585 ptm = &tm;
586 tm.tv_sec = 0;
587 tm.tv_usec = usec;
588 } else
589 ptm = NULL;
590
591 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
592 if (sstat == 0)
593 return 0;
594
595
596 if (input.dbus)
597 dbus_dispatch_io(input.dbus);
598
599 if (term_exception(terminal, &exception_set))
600 return -1;
601
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800602 struct input_key_event* event;
David Sodmanf0a925a2015-05-04 11:19:19 -0700603 event = input_get_event(&read_set, &exception_set);
604 if (event) {
605 if (!input_special_key(event) && event->value) {
606 uint32_t keysym, unicode;
607 // current_terminal can possibly change during
608 // execution of input_special_key
609 terminal = input.terminals[input.current_terminal];
610 if (term_is_active(terminal)) {
611 // Only report user activity when the terminal is active
612 report_user_activity(USER_ACTIVITY_OTHER);
613 input_get_keysym_and_unicode(
614 event, &keysym, &unicode);
615 term_key_event(terminal,
616 keysym, unicode);
617 }
618 }
619 input_put_event(event);
620 }
621
622 for (int i = 0; i < MAX_TERMINALS; i++) {
623 if (term_is_valid(input.terminals[i])) {
624 term_add_fd(input.terminals[i], &read_set, &exception_set);
625 term_dispatch_io(input.terminals[i], &read_set);
626 }
627 }
628
629 if (term_is_valid(terminal)) {
630 if (term_is_child_done(terminal)) {
631 if (terminal == input.terminals[SPLASH_TERMINAL]) {
632 /*
633 * Note: reference is not lost because it is still referenced
634 * by the splash_t structure which will ultimately destroy
635 * it, once it's safe to do so
636 */
637 input.terminals[SPLASH_TERMINAL] = NULL;
638 return -1;
639 }
David Sodman30a94ef2015-07-26 17:37:12 -0700640 input.terminals[input.current_terminal] =
641 term_init(true, term_getvideo(terminal));
David Sodmanf0a925a2015-05-04 11:19:19 -0700642 new_terminal = input.terminals[input.current_terminal];
643 if (!term_is_valid(new_terminal)) {
644 return -1;
645 }
646 term_activate(new_terminal);
647 term_close(terminal);
648 }
649 }
650
651 return 0;
652}
653
David Sodmanbf3f2842014-11-12 08:26:58 -0800654int input_run(bool standalone)
655{
David Sodmanbf3f2842014-11-12 08:26:58 -0800656 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700657 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800658
659 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800660 if (input.dbus) {
661 (void)dbus_method_call0(input.dbus,
662 kLibCrosServiceName,
663 kLibCrosServicePath,
664 kLibCrosServiceInterface,
665 kReleaseDisplayOwnership);
666 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800667
David Sodmanf0a925a2015-05-04 11:19:19 -0700668 input.terminals[input.current_terminal] = term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800669 terminal = input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800670 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800671 }
672
673 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700674 status = input_process(NULL, 0);
675 if (status != 0) {
676 LOG(ERROR, "input process returned %d", status);
677 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800678 }
679 }
680
681 return 0;
682}
683
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800684void input_put_event(struct input_key_event* event)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700685{
686 free(event);
687}
David Sodmanbbcb0522014-09-19 10:34:07 -0700688
David Sodman8ef20062015-01-06 09:23:40 -0800689terminal_t* input_create_term(int vt)
690{
691 terminal_t* terminal;
692
693 if (vt == 0)
694 return input.terminals[input.current_terminal];
695
696 terminal = input.terminals[vt-1];
697 if (term_is_active(terminal))
698 return terminal;
699
700 if (terminal == NULL) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700701 input.terminals[vt-1] = term_init(false, NULL);
David Sodman8ef20062015-01-06 09:23:40 -0800702 terminal = input.terminals[vt-1];
703 if (!term_is_valid(terminal)) {
704 LOG(ERROR, "create_term: Term init failed");
705 }
706 }
707
708 return terminal;
709}
710
David Sodmanf0a925a2015-05-04 11:19:19 -0700711terminal_t* input_create_splash_term(video_t* video)
712{
713 input.terminals[SPLASH_TERMINAL] = term_init(false, video);
714 return input.terminals[SPLASH_TERMINAL];
715}
716
717void input_destroy_splash_term()
718{
719 input.terminals[SPLASH_TERMINAL] = NULL;
720}
721
David Sodman8ef20062015-01-06 09:23:40 -0800722void input_set_current(terminal_t* terminal)
723{
724 int i;
725
David Sodmanf0a925a2015-05-04 11:19:19 -0700726 if (!terminal) {
727 input.terminals[input.current_terminal] = NULL;
728 input.current_terminal = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800729 return;
David Sodmanf0a925a2015-05-04 11:19:19 -0700730 }
David Sodman8ef20062015-01-06 09:23:40 -0800731
732 for (i = 0; i < MAX_TERMINALS; i++) {
733 if (terminal == input.terminals[i]) {
734 input.current_terminal = i;
735 return;
736 }
737 }
738}
739
740unsigned int input_get_maxterminals()
741{
David Sodmanf0a925a2015-05-04 11:19:19 -0700742 return MAX_STD_TERMINALS;
David Sodman8ef20062015-01-06 09:23:40 -0800743}