blob: 499e8e59be710a2d1575c1193b95521353430418 [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
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070018#include "input.h"
David Sodman8ef20062015-01-06 09:23:40 -080019
David Sodmanbbcb0522014-09-19 10:34:07 -070020#include "dbus_interface.h"
21#include "dbus.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080022#include "keysym.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070023#include "util.h"
David Sodman8ef20062015-01-06 09:23:40 -080024
David Sodmanf0a925a2015-05-04 11:19:19 -070025#define MAX_STD_TERMINALS (3)
26#define NUM_SPLASH_TERMINAL (1)
27#define MAX_TERMINALS (MAX_STD_TERMINALS + NUM_SPLASH_TERMINAL)
28#define SPLASH_TERMINAL (MAX_TERMINALS - 1)
David Sodmanbf3f2842014-11-12 08:26:58 -080029
Dominik Behr93899452014-08-18 22:16:21 -070030struct input_dev {
31 int fd;
32 char *path;
33};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070034
David Sodmanbf3f2842014-11-12 08:26:58 -080035struct keyboard_state {
36 int shift_state;
37 int control_state;
38 int alt_state;
David Sodmane0cc8312014-11-18 11:16:36 -080039 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080040};
41
Dylan Reid342aed02015-06-18 12:15:52 -070042/*
43 * structure to keep input state:
44 * udev - for udev events.
45 * udev_monitor - used to listen for udev events.
46 * udev_fd - to poll for udev messages.
47 * ndevs - number of input devices.
48 * devs - input devices to listen to.
49 * kbd_state - tracks modifier keys that are pressed.
50 * dbus - where to send dbus events.
51 * current_terminal - the currently selected terminal.
52 * terminals - list of all terminals that have been created.
53 */
Dominik Behr93899452014-08-18 22:16:21 -070054struct {
55 struct udev *udev;
56 struct udev_monitor *udev_monitor;
57 int udev_fd;
58 unsigned int ndevs;
59 struct input_dev *devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080060 struct keyboard_state kbd_state;
David Sodmanbbcb0522014-09-19 10:34:07 -070061 dbus_t *dbus;
David Sodmanbf3f2842014-11-12 08:26:58 -080062 uint32_t current_terminal;
63 terminal_t *terminals[MAX_TERMINALS];
Dominik Behr93899452014-08-18 22:16:21 -070064} input = {
65 .udev = NULL,
66 .udev_monitor = NULL,
67 .udev_fd = -1,
68 .ndevs = 0,
69 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080070 .dbus = NULL,
71 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070072};
73
David Sodmane0cc8312014-11-18 11:16:36 -080074static void report_user_activity(int activity_type)
75{
David Sodman19e4f9d2015-03-10 11:11:09 -070076 dbus_bool_t allow_off = false;
David Sodman8ef20062015-01-06 09:23:40 -080077 if (!input.dbus)
78 return;
79
David Sodmane0cc8312014-11-18 11:16:36 -080080 dbus_method_call1(input.dbus, kPowerManagerServiceName,
81 kPowerManagerServicePath,
82 kPowerManagerInterface,
83 kHandleUserActivityMethod,
David Sodman19e4f9d2015-03-10 11:11:09 -070084 DBUS_TYPE_INT32, &activity_type);
David Sodmane0cc8312014-11-18 11:16:36 -080085
86 switch (activity_type) {
87 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
88 (void)dbus_method_call0(input.dbus,
89 kPowerManagerServiceName,
90 kPowerManagerServicePath,
91 kPowerManagerInterface,
92 kIncreaseScreenBrightnessMethod);
93 break;
94 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
David Sodman19e4f9d2015-03-10 11:11:09 -070095 /*
96 * Shouldn't allow the screen to go
97 * completely off while frecon is active
98 * so passing false to allow_off
99 */
100 (void)dbus_method_call1(input.dbus,
David Sodmane0cc8312014-11-18 11:16:36 -0800101 kPowerManagerServiceName,
102 kPowerManagerServicePath,
103 kPowerManagerInterface,
David Sodman19e4f9d2015-03-10 11:11:09 -0700104 kDecreaseScreenBrightnessMethod,
105 DBUS_TYPE_BOOLEAN, &allow_off);
David Sodmane0cc8312014-11-18 11:16:36 -0800106 break;
107 }
108}
109
David Sodmanbf3f2842014-11-12 08:26:58 -0800110static int input_special_key(struct input_key_event *ev)
111{
112 unsigned int i;
David Sodmanb0697c22014-12-12 10:29:25 -0800113 terminal_t *terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -0800114
115 uint32_t ignore_keys[] = {
116 BTN_TOUCH, // touchpad events
117 BTN_TOOL_FINGER,
118 BTN_TOOL_DOUBLETAP,
119 BTN_TOOL_TRIPLETAP,
120 BTN_TOOL_QUADTAP,
121 BTN_TOOL_QUINTTAP,
122 BTN_LEFT, // mouse buttons
123 BTN_RIGHT,
124 BTN_MIDDLE,
125 BTN_SIDE,
126 BTN_EXTRA,
127 BTN_FORWARD,
128 BTN_BACK,
129 BTN_TASK
130 };
131
David Sodmanafba0d92015-01-27 19:07:46 -0800132 terminal = input.terminals[input.current_terminal];
133
David Sodmanbf3f2842014-11-12 08:26:58 -0800134 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
135 if (ev->code == ignore_keys[i])
136 return 1;
137
138 switch (ev->code) {
139 case KEY_LEFTSHIFT:
140 case KEY_RIGHTSHIFT:
141 input.kbd_state.shift_state = ! !ev->value;
142 return 1;
143 case KEY_LEFTCTRL:
144 case KEY_RIGHTCTRL:
145 input.kbd_state.control_state = ! !ev->value;
146 return 1;
147 case KEY_LEFTALT:
148 case KEY_RIGHTALT:
149 input.kbd_state.alt_state = ! !ev->value;
150 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800151 case KEY_LEFTMETA: // search key
152 input.kbd_state.search_state = ! !ev->value;
153 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800154 }
155
David Sodmanafba0d92015-01-27 19:07:46 -0800156 if (term_is_active(terminal)) {
157 if (input.kbd_state.shift_state && ev->value) {
158 switch (ev->code) {
159 case KEY_PAGEUP:
David Sodmane0cc8312014-11-18 11:16:36 -0800160 term_page_up(input.terminals[input.current_terminal]);
161 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800162 case KEY_PAGEDOWN:
David Sodmane0cc8312014-11-18 11:16:36 -0800163 term_page_down(input.terminals[input.current_terminal]);
164 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800165 case KEY_UP:
166 term_line_up(input.terminals[input.current_terminal]);
167 return 1;
168 case KEY_DOWN:
169 term_line_down(input.terminals[input.current_terminal]);
170 return 1;
171 }
172 }
173
174 if (input.kbd_state.search_state && ev->value) {
175 switch (ev->code) {
176 case KEY_UP:
177 term_page_up(input.terminals[input.current_terminal]);
178 return 1;
179 case KEY_DOWN:
180 term_page_down(input.terminals[input.current_terminal]);
181 return 1;
182 }
183 }
184
185 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
186 input.kbd_state.control_state) &&
187 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
188 switch (ev->code) {
189 case KEY_F1:
190 case KEY_F2:
191 case KEY_F3:
192 case KEY_F4:
193 case KEY_F5:
194 break;
195 case KEY_F6:
196 case KEY_F7:
197 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
198 (ev->code - KEY_F6));
199 break;
200 case KEY_F8:
201 case KEY_F9:
202 case KEY_F10:
203 break;
204 }
205 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800206 }
207 }
208
David Sodmanbf3f2842014-11-12 08:26:58 -0800209 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700210 /*
211 * Special case for key sequence that is used by external program. Just
212 * explicitly ignore here and do nothing.
213 */
214 if (input.kbd_state.shift_state)
215 return 1;
216
David Sodmanb0697c22014-12-12 10:29:25 -0800217 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800218 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700219 term_deactivate(terminal);
220 if (input.terminals[SPLASH_TERMINAL] != NULL) {
221 term_activate(input.terminals[SPLASH_TERMINAL]);
222 } else {
223 if (input.dbus != NULL)
224 (void)dbus_method_call0(input.dbus,
225 kLibCrosServiceName,
226 kLibCrosServicePath,
227 kLibCrosServiceInterface,
228 kTakeDisplayOwnership);
229 }
David Sodman8ef20062015-01-06 09:23:40 -0800230 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700231 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
David Sodman8ef20062015-01-06 09:23:40 -0800232 if (input.dbus != NULL)
David Sodmanbf3f2842014-11-12 08:26:58 -0800233 (void)dbus_method_call0(input.dbus,
234 kLibCrosServiceName,
235 kLibCrosServicePath,
236 kLibCrosServiceInterface,
David Sodman8ef20062015-01-06 09:23:40 -0800237 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800238 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700239 term_deactivate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800240 input.current_terminal = ev->code - KEY_F2;
241 terminal = input.terminals[input.current_terminal];
242 if (terminal == NULL) {
243 input.terminals[input.current_terminal] =
David Sodmanf0a925a2015-05-04 11:19:19 -0700244 term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800245 terminal =
246 input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800247 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800248 if (!term_is_valid(terminal)) {
249 LOG(ERROR, "Term init failed");
250 return 1;
251 }
252 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700253 term_activate(input.terminals[input.current_terminal]);
David Sodmanbf3f2842014-11-12 08:26:58 -0800254 }
255
256 return 1;
257
258 }
259
260 return 0;
261}
262
263static void input_get_keysym_and_unicode(struct input_key_event *event,
264 uint32_t *keysym, uint32_t *unicode)
265{
266 struct {
267 uint32_t code;
268 uint32_t keysym;
269 } non_ascii_keys[] = {
270 { KEY_ESC, KEYSYM_ESC},
271 { KEY_HOME, KEYSYM_HOME},
272 { KEY_LEFT, KEYSYM_LEFT},
273 { KEY_UP, KEYSYM_UP},
274 { KEY_RIGHT, KEYSYM_RIGHT},
275 { KEY_DOWN, KEYSYM_DOWN},
276 { KEY_PAGEUP, KEYSYM_PAGEUP},
277 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
278 { KEY_END, KEYSYM_END},
279 { KEY_INSERT, KEYSYM_INSERT},
280 { KEY_DELETE, KEYSYM_DELETE},
281 };
282
283 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
284 if (non_ascii_keys[i].code == event->code) {
285 *keysym = non_ascii_keys[i].keysym;
286 *unicode = -1;
287 return;
288 }
289 }
290
291 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
292 *keysym = '?';
293 } else {
294 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
295 if ((input.kbd_state.control_state) && isascii(*keysym))
296 *keysym = tolower(*keysym) - 'a' + 1;
297 }
298
299 *unicode = *keysym;
300}
301
Dominik Behr93899452014-08-18 22:16:21 -0700302static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700303{
Dominik Behr93899452014-08-18 22:16:21 -0700304 int ret = 0, fd = -1;
Haixia Shid288e032015-09-14 18:33:11 -0700305 unsigned int i;
Dominik Behr93899452014-08-18 22:16:21 -0700306 /* for some reason every device has a null enumerations and notifications
307 of every device come with NULL string first */
308 if (!devname) {
309 ret = -EINVAL;
310 goto errorret;
311 }
Haixia Shid288e032015-09-14 18:33:11 -0700312 /* check for duplicates */
313 for (i = 0; i < input.ndevs; ++i) {
314 if (strcmp(devname, input.devs[i].path) == 0) {
315 LOG(WARNING, "Skipping duplicate input device %s", devname);
316 ret = -EINVAL;
317 goto errorret;
318 }
319 }
Dominik Behr93899452014-08-18 22:16:21 -0700320 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700321 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700322 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700323
David Sodmaneef3fd22015-08-20 15:08:52 -0700324 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
325 if (!ret) {
326 ret = ioctl(fd, EVIOCGRAB, (void *) 0);
327 if (ret)
328 LOG(ERROR,
329 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
330 } else {
331 LOG(ERROR, "Evdev device %s grabbed by another process",
332 devname);
333 ret = -EBUSY;
334 goto closefd;
335 }
336
Dominik Behr93899452014-08-18 22:16:21 -0700337 struct input_dev *newdevs =
338 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
339 if (!newdevs) {
340 ret = -ENOMEM;
341 goto closefd;
342 }
343 input.devs = newdevs;
344 input.devs[input.ndevs].fd = fd;
345 input.devs[input.ndevs].path = strdup(devname);
346 if (!input.devs[input.ndevs].path) {
347 ret = -ENOMEM;
348 goto closefd;
349 }
350 input.ndevs++;
351
352 return fd;
353
354closefd:
355 close(fd);
356errorret:
357 return ret;
358}
359
360static void input_remove(const char *devname)
361{
362 if (!devname) {
363 return;
364 }
365 unsigned int u;
366 for (u = 0; u < input.ndevs; u++) {
367 if (!strcmp(devname, input.devs[u].path)) {
368 free(input.devs[u].path);
369 close(input.devs[u].fd);
370 input.ndevs--;
371 if (u != input.ndevs) {
372 input.devs[u] = input.devs[input.ndevs];
373 }
374 return;
375 }
376 }
377}
378
Dominik Behr93899452014-08-18 22:16:21 -0700379
380int input_init()
381{
382 input.udev = udev_new();
383 if (!input.udev)
384 return -ENOENT;
385 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
386 if (!input.udev_monitor) {
387 udev_unref(input.udev);
388 return -ENOENT;
389 }
390 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
391 NULL);
392 udev_monitor_enable_receiving(input.udev_monitor);
393 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
394
395 struct udev_enumerate *udev_enum;
396 struct udev_list_entry *devices, *deventry;
397 udev_enum = udev_enumerate_new(input.udev);
398 udev_enumerate_add_match_subsystem(udev_enum, "input");
399 udev_enumerate_scan_devices(udev_enum);
400 devices = udev_enumerate_get_list_entry(udev_enum);
401 udev_list_entry_foreach(deventry, devices) {
402 const char *syspath;
403 struct udev_device *dev;
404 syspath = udev_list_entry_get_name(deventry);
405 dev = udev_device_new_from_syspath(input.udev, syspath);
406 input_add(udev_device_get_devnode(dev));
407 udev_device_unref(dev);
408 }
409 udev_enumerate_unref(udev_enum);
410
411 if (!isatty(fileno(stdout)))
412 setbuf(stdout, NULL);
413
David Sodmanbbcb0522014-09-19 10:34:07 -0700414 if (input.ndevs == 0) {
415 LOG(ERROR, "No valid inputs for terminal");
416 exit(EXIT_SUCCESS);
417 }
418
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700419 return 0;
420}
421
422void input_close()
423{
Dominik Behr93899452014-08-18 22:16:21 -0700424 unsigned int u;
425 for (u = 0; u < input.ndevs; u++) {
426 free(input.devs[u].path);
427 close(input.devs[u].fd);
428 }
429 free(input.devs);
430 input.devs = NULL;
431 input.ndevs = 0;
432
433 udev_monitor_unref(input.udev_monitor);
434 input.udev_monitor = NULL;
435 udev_unref(input.udev);
436 input.udev = NULL;
437 input.udev_fd = -1;
438
David Sodmanbbcb0522014-09-19 10:34:07 -0700439 dbus_destroy(input.dbus);
440
441}
442
443void input_set_dbus(dbus_t* dbus)
444{
445 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700446}
447
Dominik Behr93899452014-08-18 22:16:21 -0700448int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700449{
Dominik Behr93899452014-08-18 22:16:21 -0700450 unsigned int u;
451 int max = -1;
452 for (u = 0; u < input.ndevs; u++) {
453 FD_SET(input.devs[u].fd, read_set);
454 FD_SET(input.devs[u].fd, exception_set);
455 if (input.devs[u].fd > max)
456 max = input.devs[u].fd;
457 }
458
459 FD_SET(input.udev_fd, read_set);
460 FD_SET(input.udev_fd, exception_set);
461 if (input.udev_fd > max)
462 max = input.udev_fd;
463 return max;
464}
465
Dominik Behr93899452014-08-18 22:16:21 -0700466struct input_key_event *input_get_event(fd_set * read_set,
467 fd_set * exception_set)
468{
469 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700470 struct input_event ev;
471 int ret;
472
Dominik Behr93899452014-08-18 22:16:21 -0700473 if (FD_ISSET(input.udev_fd, exception_set)) {
474 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700475 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700476 }
477
Dominik Behr93899452014-08-18 22:16:21 -0700478 if (FD_ISSET(input.udev_fd, read_set)
479 && !FD_ISSET(input.udev_fd, exception_set)) {
480 /* we got an udev notification */
481 struct udev_device *dev =
482 udev_monitor_receive_device(input.udev_monitor);
483 if (dev) {
484 if (!strcmp("add", udev_device_get_action(dev))) {
485 input_add(udev_device_get_devnode(dev));
486 } else
487 if (!strcmp("remove", udev_device_get_action(dev)))
488 {
489 input_remove(udev_device_get_devnode(dev));
490 }
491 udev_device_unref(dev);
492 }
493 }
494
495 for (u = 0; u < input.ndevs; u++) {
496 if (FD_ISSET(input.devs[u].fd, read_set)
497 && !FD_ISSET(input.devs[u].fd, exception_set)) {
498 ret =
499 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400500 if (ret < 0) {
501 if (errno == EINTR || errno == EAGAIN)
502 continue;
503 if (errno != ENODEV) {
504 LOG(ERROR, "read: %s: %s", input.devs[u].path,
505 strerror(errno));
506 }
507 input_remove(input.devs[u].path);
508 return NULL;
509 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700510 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700511 (int) sizeof (struct input_event), ret);
512 return NULL;
513 }
514
515 if (ev.type == EV_KEY) {
516 struct input_key_event *event =
517 malloc(sizeof (*event));
518 event->code = ev.code;
519 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700520 return event;
521 }
522 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700523 }
524
525 return NULL;
526}
527
David Sodmanf0a925a2015-05-04 11:19:19 -0700528int input_process(terminal_t* splash_term, uint32_t usec)
529{
530 terminal_t *terminal;
531 terminal_t *new_terminal;
532 fd_set read_set, exception_set;
533 int maxfd;
534 int sstat;
535 struct timeval tm;
536 struct timeval *ptm;
537
538 terminal = input.terminals[input.current_terminal];
539
540 FD_ZERO(&read_set);
541 FD_ZERO(&exception_set);
542
543 if (input.dbus) {
544 dbus_add_fd(input.dbus, &read_set, &exception_set);
545 maxfd = dbus_get_fd(input.dbus) + 1;
546 } else {
547 maxfd = 0;
548 }
549
550 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
551
552 for (int i = 0; i < MAX_TERMINALS; i++) {
553 if (term_is_valid(input.terminals[i])) {
554 term_add_fd(input.terminals[i], &read_set, &exception_set);
555 maxfd = MAX(maxfd, term_fd(input.terminals[i])) + 1;
556 term_dispatch_io(input.terminals[i], &read_set);
557 }
558 }
559
560 if (usec) {
561 ptm = &tm;
562 tm.tv_sec = 0;
563 tm.tv_usec = usec;
564 } else
565 ptm = NULL;
566
567 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
568 if (sstat == 0)
569 return 0;
570
571
572 if (input.dbus)
573 dbus_dispatch_io(input.dbus);
574
575 if (term_exception(terminal, &exception_set))
576 return -1;
577
578 struct input_key_event *event;
579 event = input_get_event(&read_set, &exception_set);
580 if (event) {
581 if (!input_special_key(event) && event->value) {
582 uint32_t keysym, unicode;
583 // current_terminal can possibly change during
584 // execution of input_special_key
585 terminal = input.terminals[input.current_terminal];
586 if (term_is_active(terminal)) {
587 // Only report user activity when the terminal is active
588 report_user_activity(USER_ACTIVITY_OTHER);
589 input_get_keysym_and_unicode(
590 event, &keysym, &unicode);
591 term_key_event(terminal,
592 keysym, unicode);
593 }
594 }
595 input_put_event(event);
596 }
597
598 for (int i = 0; i < MAX_TERMINALS; i++) {
599 if (term_is_valid(input.terminals[i])) {
600 term_add_fd(input.terminals[i], &read_set, &exception_set);
601 term_dispatch_io(input.terminals[i], &read_set);
602 }
603 }
604
605 if (term_is_valid(terminal)) {
606 if (term_is_child_done(terminal)) {
607 if (terminal == input.terminals[SPLASH_TERMINAL]) {
608 /*
609 * Note: reference is not lost because it is still referenced
610 * by the splash_t structure which will ultimately destroy
611 * it, once it's safe to do so
612 */
613 input.terminals[SPLASH_TERMINAL] = NULL;
614 return -1;
615 }
David Sodman30a94ef2015-07-26 17:37:12 -0700616 input.terminals[input.current_terminal] =
617 term_init(true, term_getvideo(terminal));
David Sodmanf0a925a2015-05-04 11:19:19 -0700618 new_terminal = input.terminals[input.current_terminal];
619 if (!term_is_valid(new_terminal)) {
620 return -1;
621 }
622 term_activate(new_terminal);
623 term_close(terminal);
624 }
625 }
626
627 return 0;
628}
629
David Sodmanbf3f2842014-11-12 08:26:58 -0800630int input_run(bool standalone)
631{
David Sodmanbf3f2842014-11-12 08:26:58 -0800632 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700633 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800634
635 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800636 if (input.dbus) {
637 (void)dbus_method_call0(input.dbus,
638 kLibCrosServiceName,
639 kLibCrosServicePath,
640 kLibCrosServiceInterface,
641 kReleaseDisplayOwnership);
642 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800643
David Sodmanf0a925a2015-05-04 11:19:19 -0700644 input.terminals[input.current_terminal] = term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800645 terminal = input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800646 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800647 }
648
649 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700650 status = input_process(NULL, 0);
651 if (status != 0) {
652 LOG(ERROR, "input process returned %d", status);
653 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800654 }
655 }
656
657 return 0;
658}
659
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700660void input_put_event(struct input_key_event *event)
661{
662 free(event);
663}
David Sodmanbbcb0522014-09-19 10:34:07 -0700664
David Sodman8ef20062015-01-06 09:23:40 -0800665terminal_t* input_create_term(int vt)
666{
667 terminal_t* terminal;
668
669 if (vt == 0)
670 return input.terminals[input.current_terminal];
671
672 terminal = input.terminals[vt-1];
673 if (term_is_active(terminal))
674 return terminal;
675
676 if (terminal == NULL) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700677 input.terminals[vt-1] = term_init(false, NULL);
David Sodman8ef20062015-01-06 09:23:40 -0800678 terminal = input.terminals[vt-1];
679 if (!term_is_valid(terminal)) {
680 LOG(ERROR, "create_term: Term init failed");
681 }
682 }
683
684 return terminal;
685}
686
David Sodmanf0a925a2015-05-04 11:19:19 -0700687terminal_t* input_create_splash_term(video_t* video)
688{
689 input.terminals[SPLASH_TERMINAL] = term_init(false, video);
690 return input.terminals[SPLASH_TERMINAL];
691}
692
693void input_destroy_splash_term()
694{
695 input.terminals[SPLASH_TERMINAL] = NULL;
696}
697
David Sodman8ef20062015-01-06 09:23:40 -0800698void input_set_current(terminal_t* terminal)
699{
700 int i;
701
David Sodmanf0a925a2015-05-04 11:19:19 -0700702 if (!terminal) {
703 input.terminals[input.current_terminal] = NULL;
704 input.current_terminal = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800705 return;
David Sodmanf0a925a2015-05-04 11:19:19 -0700706 }
David Sodman8ef20062015-01-06 09:23:40 -0800707
708 for (i = 0; i < MAX_TERMINALS; i++) {
709 if (terminal == input.terminals[i]) {
710 input.current_terminal = i;
711 return;
712 }
713 }
714}
715
716unsigned int input_get_maxterminals()
717{
David Sodmanf0a925a2015-05-04 11:19:19 -0700718 return MAX_STD_TERMINALS;
David Sodman8ef20062015-01-06 09:23:40 -0800719}