blob: 64b08b2958528b91195350ab265fd9cf0ad497d8 [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:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700166 if (input.kbd_state.search_state)
167 term_page_up(input.terminals[input.current_terminal]);
168 else
169 term_line_up(input.terminals[input.current_terminal]);
David Sodmanafba0d92015-01-27 19:07:46 -0800170 return 1;
171 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700172 if (input.kbd_state.search_state)
David Sodmanafba0d92015-01-27 19:07:46 -0800173 term_page_down(input.terminals[input.current_terminal]);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700174 else
175 term_line_down(input.terminals[input.current_terminal]);
176 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800177 }
178 }
179
180 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
181 input.kbd_state.control_state) &&
182 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
183 switch (ev->code) {
184 case KEY_F1:
185 case KEY_F2:
186 case KEY_F3:
187 case KEY_F4:
188 case KEY_F5:
189 break;
190 case KEY_F6:
191 case KEY_F7:
192 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
193 (ev->code - KEY_F6));
194 break;
195 case KEY_F8:
196 case KEY_F9:
197 case KEY_F10:
198 break;
199 }
200 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800201 }
202 }
203
David Sodmanbf3f2842014-11-12 08:26:58 -0800204 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700205 /*
206 * Special case for key sequence that is used by external program. Just
207 * explicitly ignore here and do nothing.
208 */
209 if (input.kbd_state.shift_state)
210 return 1;
211
David Sodmanb0697c22014-12-12 10:29:25 -0800212 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800213 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700214 term_deactivate(terminal);
215 if (input.terminals[SPLASH_TERMINAL] != NULL) {
216 term_activate(input.terminals[SPLASH_TERMINAL]);
217 } else {
218 if (input.dbus != NULL)
219 (void)dbus_method_call0(input.dbus,
220 kLibCrosServiceName,
221 kLibCrosServicePath,
222 kLibCrosServiceInterface,
223 kTakeDisplayOwnership);
224 }
David Sodman8ef20062015-01-06 09:23:40 -0800225 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700226 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
David Sodman8ef20062015-01-06 09:23:40 -0800227 if (input.dbus != NULL)
David Sodmanbf3f2842014-11-12 08:26:58 -0800228 (void)dbus_method_call0(input.dbus,
229 kLibCrosServiceName,
230 kLibCrosServicePath,
231 kLibCrosServiceInterface,
David Sodman8ef20062015-01-06 09:23:40 -0800232 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800233 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700234 term_deactivate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800235 input.current_terminal = ev->code - KEY_F2;
236 terminal = input.terminals[input.current_terminal];
237 if (terminal == NULL) {
238 input.terminals[input.current_terminal] =
David Sodmanf0a925a2015-05-04 11:19:19 -0700239 term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800240 terminal =
241 input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800242 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800243 if (!term_is_valid(terminal)) {
244 LOG(ERROR, "Term init failed");
245 return 1;
246 }
247 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700248 term_activate(input.terminals[input.current_terminal]);
David Sodmanbf3f2842014-11-12 08:26:58 -0800249 }
250
251 return 1;
252
253 }
254
255 return 0;
256}
257
258static void input_get_keysym_and_unicode(struct input_key_event *event,
259 uint32_t *keysym, uint32_t *unicode)
260{
261 struct {
262 uint32_t code;
263 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700264 } search_keys[] = {
265 { KEY_F1, KEYSYM_F1},
266 { KEY_F2, KEYSYM_F2},
267 { KEY_F3, KEYSYM_F3},
268 { KEY_F4, KEYSYM_F4},
269 { KEY_F5, KEYSYM_F5},
270 { KEY_F6, KEYSYM_F6},
271 { KEY_F7, KEYSYM_F7},
272 { KEY_F8, KEYSYM_F8},
273 { KEY_F9, KEYSYM_F8},
274 { KEY_F10, KEYSYM_F10},
275 { KEY_UP, KEYSYM_PAGEUP},
276 { KEY_DOWN, KEYSYM_PAGEDOWN},
277 { KEY_LEFT, KEYSYM_HOME},
278 { KEY_RIGHT, KEYSYM_END},
279 };
280
281 struct {
282 uint32_t code;
283 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800284 } non_ascii_keys[] = {
285 { KEY_ESC, KEYSYM_ESC},
286 { KEY_HOME, KEYSYM_HOME},
287 { KEY_LEFT, KEYSYM_LEFT},
288 { KEY_UP, KEYSYM_UP},
289 { KEY_RIGHT, KEYSYM_RIGHT},
290 { KEY_DOWN, KEYSYM_DOWN},
291 { KEY_PAGEUP, KEYSYM_PAGEUP},
292 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
293 { KEY_END, KEYSYM_END},
294 { KEY_INSERT, KEYSYM_INSERT},
295 { KEY_DELETE, KEYSYM_DELETE},
296 };
297
Dominik Behr58bb8e12015-09-22 14:30:41 -0700298 if (input.kbd_state.search_state) {
299 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
300 if (search_keys[i].code == event->code) {
301 *keysym = search_keys[i].keysym;
302 *unicode = -1;
303 return;
304 }
305 }
306 }
307
David Sodmanbf3f2842014-11-12 08:26:58 -0800308 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
309 if (non_ascii_keys[i].code == event->code) {
310 *keysym = non_ascii_keys[i].keysym;
311 *unicode = -1;
312 return;
313 }
314 }
315
316 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
317 *keysym = '?';
318 } else {
319 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
320 if ((input.kbd_state.control_state) && isascii(*keysym))
321 *keysym = tolower(*keysym) - 'a' + 1;
322 }
323
324 *unicode = *keysym;
325}
326
Dominik Behr93899452014-08-18 22:16:21 -0700327static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700328{
Dominik Behr93899452014-08-18 22:16:21 -0700329 int ret = 0, fd = -1;
Haixia Shid288e032015-09-14 18:33:11 -0700330 unsigned int i;
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
David Sodmaneef3fd22015-08-20 15:08:52 -0700349 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
350 if (!ret) {
351 ret = ioctl(fd, EVIOCGRAB, (void *) 0);
352 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
Dominik Behr93899452014-08-18 22:16:21 -0700362 struct input_dev *newdevs =
363 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
385static void input_remove(const char *devname)
386{
387 if (!devname) {
388 return;
389 }
390 unsigned int u;
391 for (u = 0; u < input.ndevs; u++) {
392 if (!strcmp(devname, input.devs[u].path)) {
393 free(input.devs[u].path);
394 close(input.devs[u].fd);
395 input.ndevs--;
396 if (u != input.ndevs) {
397 input.devs[u] = input.devs[input.ndevs];
398 }
399 return;
400 }
401 }
402}
403
Dominik Behr93899452014-08-18 22:16:21 -0700404
405int input_init()
406{
407 input.udev = udev_new();
408 if (!input.udev)
409 return -ENOENT;
410 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
411 if (!input.udev_monitor) {
412 udev_unref(input.udev);
413 return -ENOENT;
414 }
415 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
416 NULL);
417 udev_monitor_enable_receiving(input.udev_monitor);
418 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
419
420 struct udev_enumerate *udev_enum;
421 struct udev_list_entry *devices, *deventry;
422 udev_enum = udev_enumerate_new(input.udev);
423 udev_enumerate_add_match_subsystem(udev_enum, "input");
424 udev_enumerate_scan_devices(udev_enum);
425 devices = udev_enumerate_get_list_entry(udev_enum);
426 udev_list_entry_foreach(deventry, devices) {
427 const char *syspath;
428 struct udev_device *dev;
429 syspath = udev_list_entry_get_name(deventry);
430 dev = udev_device_new_from_syspath(input.udev, syspath);
431 input_add(udev_device_get_devnode(dev));
432 udev_device_unref(dev);
433 }
434 udev_enumerate_unref(udev_enum);
435
436 if (!isatty(fileno(stdout)))
437 setbuf(stdout, NULL);
438
David Sodmanbbcb0522014-09-19 10:34:07 -0700439 if (input.ndevs == 0) {
440 LOG(ERROR, "No valid inputs for terminal");
441 exit(EXIT_SUCCESS);
442 }
443
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700444 return 0;
445}
446
447void input_close()
448{
Dominik Behr93899452014-08-18 22:16:21 -0700449 unsigned int u;
450 for (u = 0; u < input.ndevs; u++) {
451 free(input.devs[u].path);
452 close(input.devs[u].fd);
453 }
454 free(input.devs);
455 input.devs = NULL;
456 input.ndevs = 0;
457
458 udev_monitor_unref(input.udev_monitor);
459 input.udev_monitor = NULL;
460 udev_unref(input.udev);
461 input.udev = NULL;
462 input.udev_fd = -1;
463
David Sodmanbbcb0522014-09-19 10:34:07 -0700464 dbus_destroy(input.dbus);
465
466}
467
468void input_set_dbus(dbus_t* dbus)
469{
470 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700471}
472
Dominik Behr93899452014-08-18 22:16:21 -0700473int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700474{
Dominik Behr93899452014-08-18 22:16:21 -0700475 unsigned int u;
476 int max = -1;
477 for (u = 0; u < input.ndevs; u++) {
478 FD_SET(input.devs[u].fd, read_set);
479 FD_SET(input.devs[u].fd, exception_set);
480 if (input.devs[u].fd > max)
481 max = input.devs[u].fd;
482 }
483
484 FD_SET(input.udev_fd, read_set);
485 FD_SET(input.udev_fd, exception_set);
486 if (input.udev_fd > max)
487 max = input.udev_fd;
488 return max;
489}
490
Dominik Behr93899452014-08-18 22:16:21 -0700491struct input_key_event *input_get_event(fd_set * read_set,
492 fd_set * exception_set)
493{
494 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700495 struct input_event ev;
496 int ret;
497
Dominik Behr93899452014-08-18 22:16:21 -0700498 if (FD_ISSET(input.udev_fd, exception_set)) {
499 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700500 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700501 }
502
Dominik Behr93899452014-08-18 22:16:21 -0700503 if (FD_ISSET(input.udev_fd, read_set)
504 && !FD_ISSET(input.udev_fd, exception_set)) {
505 /* we got an udev notification */
506 struct udev_device *dev =
507 udev_monitor_receive_device(input.udev_monitor);
508 if (dev) {
509 if (!strcmp("add", udev_device_get_action(dev))) {
510 input_add(udev_device_get_devnode(dev));
511 } else
512 if (!strcmp("remove", udev_device_get_action(dev)))
513 {
514 input_remove(udev_device_get_devnode(dev));
515 }
516 udev_device_unref(dev);
517 }
518 }
519
520 for (u = 0; u < input.ndevs; u++) {
521 if (FD_ISSET(input.devs[u].fd, read_set)
522 && !FD_ISSET(input.devs[u].fd, exception_set)) {
523 ret =
524 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400525 if (ret < 0) {
526 if (errno == EINTR || errno == EAGAIN)
527 continue;
528 if (errno != ENODEV) {
529 LOG(ERROR, "read: %s: %s", input.devs[u].path,
530 strerror(errno));
531 }
532 input_remove(input.devs[u].path);
533 return NULL;
534 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700535 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700536 (int) sizeof (struct input_event), ret);
537 return NULL;
538 }
539
540 if (ev.type == EV_KEY) {
541 struct input_key_event *event =
542 malloc(sizeof (*event));
543 event->code = ev.code;
544 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700545 return event;
546 }
547 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700548 }
549
550 return NULL;
551}
552
David Sodmanf0a925a2015-05-04 11:19:19 -0700553int input_process(terminal_t* splash_term, uint32_t usec)
554{
555 terminal_t *terminal;
556 terminal_t *new_terminal;
557 fd_set read_set, exception_set;
558 int maxfd;
559 int sstat;
560 struct timeval tm;
561 struct timeval *ptm;
562
563 terminal = input.terminals[input.current_terminal];
564
565 FD_ZERO(&read_set);
566 FD_ZERO(&exception_set);
567
568 if (input.dbus) {
569 dbus_add_fd(input.dbus, &read_set, &exception_set);
570 maxfd = dbus_get_fd(input.dbus) + 1;
571 } else {
572 maxfd = 0;
573 }
574
575 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
576
577 for (int i = 0; i < MAX_TERMINALS; i++) {
578 if (term_is_valid(input.terminals[i])) {
579 term_add_fd(input.terminals[i], &read_set, &exception_set);
580 maxfd = MAX(maxfd, term_fd(input.terminals[i])) + 1;
581 term_dispatch_io(input.terminals[i], &read_set);
582 }
583 }
584
585 if (usec) {
586 ptm = &tm;
587 tm.tv_sec = 0;
588 tm.tv_usec = usec;
589 } else
590 ptm = NULL;
591
592 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
593 if (sstat == 0)
594 return 0;
595
596
597 if (input.dbus)
598 dbus_dispatch_io(input.dbus);
599
600 if (term_exception(terminal, &exception_set))
601 return -1;
602
603 struct input_key_event *event;
604 event = input_get_event(&read_set, &exception_set);
605 if (event) {
606 if (!input_special_key(event) && event->value) {
607 uint32_t keysym, unicode;
608 // current_terminal can possibly change during
609 // execution of input_special_key
610 terminal = input.terminals[input.current_terminal];
611 if (term_is_active(terminal)) {
612 // Only report user activity when the terminal is active
613 report_user_activity(USER_ACTIVITY_OTHER);
614 input_get_keysym_and_unicode(
615 event, &keysym, &unicode);
616 term_key_event(terminal,
617 keysym, unicode);
618 }
619 }
620 input_put_event(event);
621 }
622
623 for (int i = 0; i < MAX_TERMINALS; i++) {
624 if (term_is_valid(input.terminals[i])) {
625 term_add_fd(input.terminals[i], &read_set, &exception_set);
626 term_dispatch_io(input.terminals[i], &read_set);
627 }
628 }
629
630 if (term_is_valid(terminal)) {
631 if (term_is_child_done(terminal)) {
632 if (terminal == input.terminals[SPLASH_TERMINAL]) {
633 /*
634 * Note: reference is not lost because it is still referenced
635 * by the splash_t structure which will ultimately destroy
636 * it, once it's safe to do so
637 */
638 input.terminals[SPLASH_TERMINAL] = NULL;
639 return -1;
640 }
David Sodman30a94ef2015-07-26 17:37:12 -0700641 input.terminals[input.current_terminal] =
642 term_init(true, term_getvideo(terminal));
David Sodmanf0a925a2015-05-04 11:19:19 -0700643 new_terminal = input.terminals[input.current_terminal];
644 if (!term_is_valid(new_terminal)) {
645 return -1;
646 }
647 term_activate(new_terminal);
648 term_close(terminal);
649 }
650 }
651
652 return 0;
653}
654
David Sodmanbf3f2842014-11-12 08:26:58 -0800655int input_run(bool standalone)
656{
David Sodmanbf3f2842014-11-12 08:26:58 -0800657 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700658 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800659
660 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800661 if (input.dbus) {
662 (void)dbus_method_call0(input.dbus,
663 kLibCrosServiceName,
664 kLibCrosServicePath,
665 kLibCrosServiceInterface,
666 kReleaseDisplayOwnership);
667 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800668
David Sodmanf0a925a2015-05-04 11:19:19 -0700669 input.terminals[input.current_terminal] = term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800670 terminal = input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800671 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800672 }
673
674 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700675 status = input_process(NULL, 0);
676 if (status != 0) {
677 LOG(ERROR, "input process returned %d", status);
678 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800679 }
680 }
681
682 return 0;
683}
684
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700685void input_put_event(struct input_key_event *event)
686{
687 free(event);
688}
David Sodmanbbcb0522014-09-19 10:34:07 -0700689
David Sodman8ef20062015-01-06 09:23:40 -0800690terminal_t* input_create_term(int vt)
691{
692 terminal_t* terminal;
693
694 if (vt == 0)
695 return input.terminals[input.current_terminal];
696
697 terminal = input.terminals[vt-1];
698 if (term_is_active(terminal))
699 return terminal;
700
701 if (terminal == NULL) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700702 input.terminals[vt-1] = term_init(false, NULL);
David Sodman8ef20062015-01-06 09:23:40 -0800703 terminal = input.terminals[vt-1];
704 if (!term_is_valid(terminal)) {
705 LOG(ERROR, "create_term: Term init failed");
706 }
707 }
708
709 return terminal;
710}
711
David Sodmanf0a925a2015-05-04 11:19:19 -0700712terminal_t* input_create_splash_term(video_t* video)
713{
714 input.terminals[SPLASH_TERMINAL] = term_init(false, video);
715 return input.terminals[SPLASH_TERMINAL];
716}
717
718void input_destroy_splash_term()
719{
720 input.terminals[SPLASH_TERMINAL] = NULL;
721}
722
David Sodman8ef20062015-01-06 09:23:40 -0800723void input_set_current(terminal_t* terminal)
724{
725 int i;
726
David Sodmanf0a925a2015-05-04 11:19:19 -0700727 if (!terminal) {
728 input.terminals[input.current_terminal] = NULL;
729 input.current_terminal = 0;
David Sodman8ef20062015-01-06 09:23:40 -0800730 return;
David Sodmanf0a925a2015-05-04 11:19:19 -0700731 }
David Sodman8ef20062015-01-06 09:23:40 -0800732
733 for (i = 0; i < MAX_TERMINALS; i++) {
734 if (terminal == input.terminals[i]) {
735 input.current_terminal = i;
736 return;
737 }
738 }
739}
740
741unsigned int input_get_maxterminals()
742{
David Sodmanf0a925a2015-05-04 11:19:19 -0700743 return MAX_STD_TERMINALS;
David Sodman8ef20062015-01-06 09:23:40 -0800744}