blob: 78027df80741f68608b6094fae5159b4062526b0 [file] [log] [blame]
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07001/*
2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
David Sodmanbf3f2842014-11-12 08:26:58 -08007#include <ctype.h>
David Sodman8ef20062015-01-06 09:23:40 -08008#include <errno.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -07009#include <fcntl.h>
David Sodman8ef20062015-01-06 09:23:40 -080010#include <libudev.h>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070011#include <stdint.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
Dominik Behr93899452014-08-18 22:16:21 -070015#include <sys/select.h>
David Sodman8ef20062015-01-06 09:23:40 -080016#include <unistd.h>
17
David Sodmanbbcb0522014-09-19 10:34:07 -070018#include "dbus.h"
Stéphane Marchesin6cbb7332016-01-07 21:18:43 -080019#include "dbus_interface.h"
Stéphane Marchesin62561a12015-12-11 17:32:37 -080020#include "input.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080021#include "keysym.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022#include "util.h"
David Sodman8ef20062015-01-06 09:23:40 -080023
Dominik Behr93899452014-08-18 22:16:21 -070024struct input_dev {
25 int fd;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080026 char* path;
Dominik Behr93899452014-08-18 22:16:21 -070027};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070028
David Sodmanbf3f2842014-11-12 08:26:58 -080029struct keyboard_state {
30 int shift_state;
31 int control_state;
32 int alt_state;
David Sodmane0cc8312014-11-18 11:16:36 -080033 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080034};
35
Dylan Reid342aed02015-06-18 12:15:52 -070036/*
37 * structure to keep input state:
38 * udev - for udev events.
39 * udev_monitor - used to listen for udev events.
40 * udev_fd - to poll for udev messages.
41 * ndevs - number of input devices.
42 * devs - input devices to listen to.
43 * kbd_state - tracks modifier keys that are pressed.
Dylan Reid342aed02015-06-18 12:15:52 -070044 */
Dominik Behr93899452014-08-18 22:16:21 -070045struct {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080046 struct udev* udev;
47 struct udev_monitor* udev_monitor;
Dominik Behr93899452014-08-18 22:16:21 -070048 int udev_fd;
49 unsigned int ndevs;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080050 struct input_dev* devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080051 struct keyboard_state kbd_state;
Dominik Behr93899452014-08-18 22:16:21 -070052} input = {
53 .udev = NULL,
54 .udev_monitor = NULL,
55 .udev_fd = -1,
56 .ndevs = 0,
57 .devs = NULL,
Dominik Behr93899452014-08-18 22:16:21 -070058};
59
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080060static int input_special_key(struct input_key_event* ev)
David Sodmanbf3f2842014-11-12 08:26:58 -080061{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080062 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080063
64 uint32_t ignore_keys[] = {
65 BTN_TOUCH, // touchpad events
66 BTN_TOOL_FINGER,
67 BTN_TOOL_DOUBLETAP,
68 BTN_TOOL_TRIPLETAP,
69 BTN_TOOL_QUADTAP,
70 BTN_TOOL_QUINTTAP,
71 BTN_LEFT, // mouse buttons
72 BTN_RIGHT,
73 BTN_MIDDLE,
74 BTN_SIDE,
75 BTN_EXTRA,
76 BTN_FORWARD,
77 BTN_BACK,
78 BTN_TASK
79 };
80
Dominik Behr4defb362016-01-13 12:36:14 -080081 terminal = term_get_current_terminal();
David Sodmanafba0d92015-01-27 19:07:46 -080082
Stéphane Marchesinac14d292015-12-14 15:27:18 -080083 for (unsigned int i = 0; i < ARRAY_SIZE(ignore_keys); i++)
David Sodmanbf3f2842014-11-12 08:26:58 -080084 if (ev->code == ignore_keys[i])
85 return 1;
86
87 switch (ev->code) {
88 case KEY_LEFTSHIFT:
89 case KEY_RIGHTSHIFT:
90 input.kbd_state.shift_state = ! !ev->value;
91 return 1;
92 case KEY_LEFTCTRL:
93 case KEY_RIGHTCTRL:
94 input.kbd_state.control_state = ! !ev->value;
95 return 1;
96 case KEY_LEFTALT:
97 case KEY_RIGHTALT:
98 input.kbd_state.alt_state = ! !ev->value;
99 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800100 case KEY_LEFTMETA: // search key
101 input.kbd_state.search_state = ! !ev->value;
102 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800103 }
104
David Sodmanafba0d92015-01-27 19:07:46 -0800105 if (term_is_active(terminal)) {
106 if (input.kbd_state.shift_state && ev->value) {
107 switch (ev->code) {
108 case KEY_PAGEUP:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800109 term_page_up(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800110 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800111 case KEY_PAGEDOWN:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800112 term_page_down(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800113 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800114 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700115 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800116 term_page_up(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700117 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800118 term_line_up(terminal);
David Sodmanafba0d92015-01-27 19:07:46 -0800119 return 1;
120 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700121 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800122 term_page_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700123 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800124 term_line_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700125 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800126 }
127 }
128
129 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
130 input.kbd_state.control_state) &&
131 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
132 switch (ev->code) {
133 case KEY_F1:
134 case KEY_F2:
135 case KEY_F3:
136 case KEY_F4:
137 case KEY_F5:
138 break;
139 case KEY_F6:
140 case KEY_F7:
Dominik Behr797a3832016-01-11 15:53:11 -0800141 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
142 (ev->code - KEY_F6));
David Sodmanafba0d92015-01-27 19:07:46 -0800143 break;
144 case KEY_F8:
145 case KEY_F9:
146 case KEY_F10:
147 break;
148 }
149 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800150 }
151 }
152
David Sodmanbf3f2842014-11-12 08:26:58 -0800153 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700154 /*
155 * Special case for key sequence that is used by external program. Just
156 * explicitly ignore here and do nothing.
157 */
158 if (input.kbd_state.shift_state)
159 return 1;
160
David Sodmanb0697c22014-12-12 10:29:25 -0800161 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800162 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700163 term_deactivate(terminal);
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800164 if (term_get_terminal(SPLASH_TERMINAL) != NULL) {
165 term_activate(term_get_terminal(SPLASH_TERMINAL));
David Sodmanf0a925a2015-05-04 11:19:19 -0700166 } else {
Dominik Behr797a3832016-01-11 15:53:11 -0800167 dbus_take_display_ownership();
David Sodmanf0a925a2015-05-04 11:19:19 -0700168 }
David Sodman8ef20062015-01-06 09:23:40 -0800169 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700170 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
Dominik Behr797a3832016-01-11 15:53:11 -0800171 dbus_release_display_ownership();
David Sodmanbf3f2842014-11-12 08:26:58 -0800172 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700173 term_deactivate(terminal);
Dominik Behr4defb362016-01-13 12:36:14 -0800174 term_set_current(ev->code - KEY_F2);
175 terminal = term_get_current_terminal();
David Sodmanbf3f2842014-11-12 08:26:58 -0800176 if (terminal == NULL) {
Dominik Behr4defb362016-01-13 12:36:14 -0800177 term_set_current_terminal(term_init(true, NULL));
David Sodmanbf3f2842014-11-12 08:26:58 -0800178 terminal =
Dominik Behr4defb362016-01-13 12:36:14 -0800179 term_get_current_terminal();
David Sodman8ef20062015-01-06 09:23:40 -0800180 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800181 if (!term_is_valid(terminal)) {
182 LOG(ERROR, "Term init failed");
183 return 1;
184 }
185 }
Dominik Behr4defb362016-01-13 12:36:14 -0800186 term_activate(term_get_current_terminal());
David Sodmanbf3f2842014-11-12 08:26:58 -0800187 }
188
189 return 1;
190
191 }
192
193 return 0;
194}
195
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800196static void input_get_keysym_and_unicode(struct input_key_event* event,
197 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800198{
199 struct {
200 uint32_t code;
201 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700202 } search_keys[] = {
203 { KEY_F1, KEYSYM_F1},
204 { KEY_F2, KEYSYM_F2},
205 { KEY_F3, KEYSYM_F3},
206 { KEY_F4, KEYSYM_F4},
207 { KEY_F5, KEYSYM_F5},
208 { KEY_F6, KEYSYM_F6},
209 { KEY_F7, KEYSYM_F7},
210 { KEY_F8, KEYSYM_F8},
211 { KEY_F9, KEYSYM_F8},
212 { KEY_F10, KEYSYM_F10},
213 { KEY_UP, KEYSYM_PAGEUP},
214 { KEY_DOWN, KEYSYM_PAGEDOWN},
215 { KEY_LEFT, KEYSYM_HOME},
216 { KEY_RIGHT, KEYSYM_END},
217 };
218
219 struct {
220 uint32_t code;
221 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800222 } non_ascii_keys[] = {
223 { KEY_ESC, KEYSYM_ESC},
224 { KEY_HOME, KEYSYM_HOME},
225 { KEY_LEFT, KEYSYM_LEFT},
226 { KEY_UP, KEYSYM_UP},
227 { KEY_RIGHT, KEYSYM_RIGHT},
228 { KEY_DOWN, KEYSYM_DOWN},
229 { KEY_PAGEUP, KEYSYM_PAGEUP},
230 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
231 { KEY_END, KEYSYM_END},
232 { KEY_INSERT, KEYSYM_INSERT},
233 { KEY_DELETE, KEYSYM_DELETE},
234 };
235
Dominik Behr58bb8e12015-09-22 14:30:41 -0700236 if (input.kbd_state.search_state) {
237 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
238 if (search_keys[i].code == event->code) {
239 *keysym = search_keys[i].keysym;
240 *unicode = -1;
241 return;
242 }
243 }
244 }
245
David Sodmanbf3f2842014-11-12 08:26:58 -0800246 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
247 if (non_ascii_keys[i].code == event->code) {
248 *keysym = non_ascii_keys[i].keysym;
249 *unicode = -1;
250 return;
251 }
252 }
253
254 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
255 *keysym = '?';
256 } else {
257 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
258 if ((input.kbd_state.control_state) && isascii(*keysym))
259 *keysym = tolower(*keysym) - 'a' + 1;
260 }
261
262 *unicode = *keysym;
263}
264
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800265static int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700266{
Dominik Behr93899452014-08-18 22:16:21 -0700267 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800268
Dominik Behr93899452014-08-18 22:16:21 -0700269 /* for some reason every device has a null enumerations and notifications
270 of every device come with NULL string first */
271 if (!devname) {
272 ret = -EINVAL;
273 goto errorret;
274 }
Haixia Shid288e032015-09-14 18:33:11 -0700275 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800276 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700277 if (strcmp(devname, input.devs[i].path) == 0) {
Stéphane Marchesinc02260b2016-01-07 22:46:45 -0800278 LOG(INFO, "Skipping duplicate input device %s", devname);
Haixia Shid288e032015-09-14 18:33:11 -0700279 ret = -EINVAL;
280 goto errorret;
281 }
282 }
Dominik Behr93899452014-08-18 22:16:21 -0700283 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700284 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700285 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700286
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800287 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700288 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800289 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700290 if (ret)
291 LOG(ERROR,
292 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
293 } else {
294 LOG(ERROR, "Evdev device %s grabbed by another process",
295 devname);
296 ret = -EBUSY;
297 goto closefd;
298 }
299
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800300 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700301 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
302 if (!newdevs) {
303 ret = -ENOMEM;
304 goto closefd;
305 }
306 input.devs = newdevs;
307 input.devs[input.ndevs].fd = fd;
308 input.devs[input.ndevs].path = strdup(devname);
309 if (!input.devs[input.ndevs].path) {
310 ret = -ENOMEM;
311 goto closefd;
312 }
313 input.ndevs++;
314
315 return fd;
316
317closefd:
318 close(fd);
319errorret:
320 return ret;
321}
322
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800323static void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700324{
Dominik Behr93899452014-08-18 22:16:21 -0700325 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800326
327 if (!devname)
328 return;
329
Dominik Behr93899452014-08-18 22:16:21 -0700330 for (u = 0; u < input.ndevs; u++) {
331 if (!strcmp(devname, input.devs[u].path)) {
332 free(input.devs[u].path);
333 close(input.devs[u].fd);
334 input.ndevs--;
335 if (u != input.ndevs) {
336 input.devs[u] = input.devs[input.ndevs];
337 }
338 return;
339 }
340 }
341}
342
Dominik Behr93899452014-08-18 22:16:21 -0700343
344int input_init()
345{
346 input.udev = udev_new();
347 if (!input.udev)
348 return -ENOENT;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800349
Dominik Behr93899452014-08-18 22:16:21 -0700350 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
351 if (!input.udev_monitor) {
352 udev_unref(input.udev);
353 return -ENOENT;
354 }
355 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
356 NULL);
357 udev_monitor_enable_receiving(input.udev_monitor);
358 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
359
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800360 struct udev_enumerate* udev_enum;
361 struct udev_list_entry* devices, *deventry;
Dominik Behr93899452014-08-18 22:16:21 -0700362 udev_enum = udev_enumerate_new(input.udev);
363 udev_enumerate_add_match_subsystem(udev_enum, "input");
364 udev_enumerate_scan_devices(udev_enum);
365 devices = udev_enumerate_get_list_entry(udev_enum);
366 udev_list_entry_foreach(deventry, devices) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800367 const char* syspath;
368 struct udev_device* dev;
Dominik Behr93899452014-08-18 22:16:21 -0700369 syspath = udev_list_entry_get_name(deventry);
370 dev = udev_device_new_from_syspath(input.udev, syspath);
371 input_add(udev_device_get_devnode(dev));
372 udev_device_unref(dev);
373 }
374 udev_enumerate_unref(udev_enum);
375
376 if (!isatty(fileno(stdout)))
377 setbuf(stdout, NULL);
378
David Sodmanbbcb0522014-09-19 10:34:07 -0700379 if (input.ndevs == 0) {
380 LOG(ERROR, "No valid inputs for terminal");
381 exit(EXIT_SUCCESS);
382 }
383
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700384 return 0;
385}
386
387void input_close()
388{
Dominik Behr93899452014-08-18 22:16:21 -0700389 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800390
Dominik Behr93899452014-08-18 22:16:21 -0700391 for (u = 0; u < input.ndevs; u++) {
392 free(input.devs[u].path);
393 close(input.devs[u].fd);
394 }
395 free(input.devs);
396 input.devs = NULL;
397 input.ndevs = 0;
398
399 udev_monitor_unref(input.udev_monitor);
400 input.udev_monitor = NULL;
401 udev_unref(input.udev);
402 input.udev = NULL;
403 input.udev_fd = -1;
404
Dominik Behr797a3832016-01-11 15:53:11 -0800405 dbus_destroy();
David Sodmanbbcb0522014-09-19 10:34:07 -0700406
407}
408
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800409int input_add_fds(fd_set* read_set, fd_set* exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700410{
Dominik Behr93899452014-08-18 22:16:21 -0700411 unsigned int u;
412 int max = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800413
Dominik Behr93899452014-08-18 22:16:21 -0700414 for (u = 0; u < input.ndevs; u++) {
415 FD_SET(input.devs[u].fd, read_set);
416 FD_SET(input.devs[u].fd, exception_set);
417 if (input.devs[u].fd > max)
418 max = input.devs[u].fd;
419 }
420
421 FD_SET(input.udev_fd, read_set);
422 FD_SET(input.udev_fd, exception_set);
423 if (input.udev_fd > max)
424 max = input.udev_fd;
425 return max;
426}
427
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800428struct input_key_event* input_get_event(fd_set* read_set,
429 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700430{
431 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700432 struct input_event ev;
433 int ret;
434
Dominik Behr93899452014-08-18 22:16:21 -0700435 if (FD_ISSET(input.udev_fd, exception_set)) {
436 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700437 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700438 }
439
Dominik Behr93899452014-08-18 22:16:21 -0700440 if (FD_ISSET(input.udev_fd, read_set)
441 && !FD_ISSET(input.udev_fd, exception_set)) {
442 /* we got an udev notification */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800443 struct udev_device* dev =
Dominik Behr93899452014-08-18 22:16:21 -0700444 udev_monitor_receive_device(input.udev_monitor);
445 if (dev) {
446 if (!strcmp("add", udev_device_get_action(dev))) {
447 input_add(udev_device_get_devnode(dev));
448 } else
449 if (!strcmp("remove", udev_device_get_action(dev)))
450 {
451 input_remove(udev_device_get_devnode(dev));
452 }
453 udev_device_unref(dev);
454 }
455 }
456
457 for (u = 0; u < input.ndevs; u++) {
458 if (FD_ISSET(input.devs[u].fd, read_set)
459 && !FD_ISSET(input.devs[u].fd, exception_set)) {
460 ret =
461 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400462 if (ret < 0) {
463 if (errno == EINTR || errno == EAGAIN)
464 continue;
465 if (errno != ENODEV) {
466 LOG(ERROR, "read: %s: %s", input.devs[u].path,
467 strerror(errno));
468 }
469 input_remove(input.devs[u].path);
470 return NULL;
471 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700472 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700473 (int) sizeof (struct input_event), ret);
474 return NULL;
475 }
476
477 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800478 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700479 malloc(sizeof (*event));
480 event->code = ev.code;
481 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700482 return event;
483 }
484 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700485 }
486
487 return NULL;
488}
489
Dominik Behr4defb362016-01-13 12:36:14 -0800490void input_put_event(struct input_key_event* event)
491{
492 free(event);
493}
494
495int input_process(uint32_t usec)
David Sodmanf0a925a2015-05-04 11:19:19 -0700496{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800497 terminal_t* terminal;
498 terminal_t* new_terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700499 fd_set read_set, exception_set;
500 int maxfd;
501 int sstat;
502 struct timeval tm;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800503 struct timeval* ptm;
David Sodmanf0a925a2015-05-04 11:19:19 -0700504
Dominik Behr4defb362016-01-13 12:36:14 -0800505 terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700506
507 FD_ZERO(&read_set);
508 FD_ZERO(&exception_set);
509
Dominik Behr797a3832016-01-11 15:53:11 -0800510 maxfd = dbus_add_fds(&read_set, &exception_set) + 1;
David Sodmanf0a925a2015-05-04 11:19:19 -0700511
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800512 maxfd = MAX(maxfd, input_add_fds(&read_set, &exception_set)) + 1;
David Sodmanf0a925a2015-05-04 11:19:19 -0700513
514 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800515 if (term_is_valid(term_get_terminal(i))) {
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800516 terminal_t* current_term = term_get_terminal(i);
517 maxfd = MAX(maxfd, term_add_fds(current_term, &read_set, &exception_set)) + 1;
David Sodmanf0a925a2015-05-04 11:19:19 -0700518 }
519 }
520
521 if (usec) {
522 ptm = &tm;
523 tm.tv_sec = 0;
524 tm.tv_usec = usec;
525 } else
526 ptm = NULL;
527
528 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
529 if (sstat == 0)
530 return 0;
531
Dominik Behr797a3832016-01-11 15:53:11 -0800532 dbus_dispatch_io();
David Sodmanf0a925a2015-05-04 11:19:19 -0700533
534 if (term_exception(terminal, &exception_set))
535 return -1;
536
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800537 struct input_key_event* event;
David Sodmanf0a925a2015-05-04 11:19:19 -0700538 event = input_get_event(&read_set, &exception_set);
539 if (event) {
540 if (!input_special_key(event) && event->value) {
541 uint32_t keysym, unicode;
542 // current_terminal can possibly change during
543 // execution of input_special_key
Dominik Behr4defb362016-01-13 12:36:14 -0800544 terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700545 if (term_is_active(terminal)) {
546 // Only report user activity when the terminal is active
Dominik Behr797a3832016-01-11 15:53:11 -0800547 dbus_report_user_activity(USER_ACTIVITY_OTHER);
David Sodmanf0a925a2015-05-04 11:19:19 -0700548 input_get_keysym_and_unicode(
549 event, &keysym, &unicode);
550 term_key_event(terminal,
551 keysym, unicode);
552 }
553 }
554 input_put_event(event);
555 }
556
557 for (int i = 0; i < MAX_TERMINALS; i++) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800558 if (term_is_valid(term_get_terminal(i))) {
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800559 terminal_t* current_term = term_get_terminal(i);
Stéphane Marchesin905a6f22016-01-07 22:02:07 -0800560 term_dispatch_io(current_term, &read_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700561 }
562 }
563
564 if (term_is_valid(terminal)) {
565 if (term_is_child_done(terminal)) {
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800566 if (terminal == term_get_terminal(SPLASH_TERMINAL)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700567 /*
568 * Note: reference is not lost because it is still referenced
569 * by the splash_t structure which will ultimately destroy
570 * it, once it's safe to do so
571 */
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800572 term_set_terminal(SPLASH_TERMINAL, NULL);
David Sodmanf0a925a2015-05-04 11:19:19 -0700573 return -1;
574 }
Dominik Behr4defb362016-01-13 12:36:14 -0800575 term_set_current_terminal(term_init(true, term_getvideo(terminal)));
576 new_terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700577 if (!term_is_valid(new_terminal)) {
578 return -1;
579 }
580 term_activate(new_terminal);
581 term_close(terminal);
582 }
583 }
584
585 return 0;
586}
587
David Sodmanbf3f2842014-11-12 08:26:58 -0800588int input_run(bool standalone)
589{
David Sodmanbf3f2842014-11-12 08:26:58 -0800590 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700591 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800592
593 if (standalone) {
Dominik Behr797a3832016-01-11 15:53:11 -0800594 dbus_take_display_ownership();
Dominik Behr4defb362016-01-13 12:36:14 -0800595 term_set_current_terminal(term_init(true, NULL));
596 terminal = term_get_current_terminal();
David Sodman8ef20062015-01-06 09:23:40 -0800597 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800598 }
599
600 while (1) {
Dominik Behr4defb362016-01-13 12:36:14 -0800601 status = input_process(0);
David Sodmanf0a925a2015-05-04 11:19:19 -0700602 if (status != 0) {
603 LOG(ERROR, "input process returned %d", status);
604 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800605 }
606 }
607
608 return 0;
609}