blob: 7e803c488cdd20a9f5aad4c4001c83b039abf037 [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{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800111 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -0800112
113 uint32_t ignore_keys[] = {
114 BTN_TOUCH, // touchpad events
115 BTN_TOOL_FINGER,
116 BTN_TOOL_DOUBLETAP,
117 BTN_TOOL_TRIPLETAP,
118 BTN_TOOL_QUADTAP,
119 BTN_TOOL_QUINTTAP,
120 BTN_LEFT, // mouse buttons
121 BTN_RIGHT,
122 BTN_MIDDLE,
123 BTN_SIDE,
124 BTN_EXTRA,
125 BTN_FORWARD,
126 BTN_BACK,
127 BTN_TASK
128 };
129
David Sodmanafba0d92015-01-27 19:07:46 -0800130 terminal = input.terminals[input.current_terminal];
131
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800132 for (unsigned int i = 0; i < ARRAY_SIZE(ignore_keys); i++)
David Sodmanbf3f2842014-11-12 08:26:58 -0800133 if (ev->code == ignore_keys[i])
134 return 1;
135
136 switch (ev->code) {
137 case KEY_LEFTSHIFT:
138 case KEY_RIGHTSHIFT:
139 input.kbd_state.shift_state = ! !ev->value;
140 return 1;
141 case KEY_LEFTCTRL:
142 case KEY_RIGHTCTRL:
143 input.kbd_state.control_state = ! !ev->value;
144 return 1;
145 case KEY_LEFTALT:
146 case KEY_RIGHTALT:
147 input.kbd_state.alt_state = ! !ev->value;
148 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800149 case KEY_LEFTMETA: // search key
150 input.kbd_state.search_state = ! !ev->value;
151 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800152 }
153
David Sodmanafba0d92015-01-27 19:07:46 -0800154 if (term_is_active(terminal)) {
155 if (input.kbd_state.shift_state && ev->value) {
156 switch (ev->code) {
157 case KEY_PAGEUP:
David Sodmane0cc8312014-11-18 11:16:36 -0800158 term_page_up(input.terminals[input.current_terminal]);
159 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800160 case KEY_PAGEDOWN:
David Sodmane0cc8312014-11-18 11:16:36 -0800161 term_page_down(input.terminals[input.current_terminal]);
162 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800163 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700164 if (input.kbd_state.search_state)
165 term_page_up(input.terminals[input.current_terminal]);
166 else
167 term_line_up(input.terminals[input.current_terminal]);
David Sodmanafba0d92015-01-27 19:07:46 -0800168 return 1;
169 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700170 if (input.kbd_state.search_state)
David Sodmanafba0d92015-01-27 19:07:46 -0800171 term_page_down(input.terminals[input.current_terminal]);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700172 else
173 term_line_down(input.terminals[input.current_terminal]);
174 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800175 }
176 }
177
178 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
179 input.kbd_state.control_state) &&
180 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
181 switch (ev->code) {
182 case KEY_F1:
183 case KEY_F2:
184 case KEY_F3:
185 case KEY_F4:
186 case KEY_F5:
187 break;
188 case KEY_F6:
189 case KEY_F7:
190 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
191 (ev->code - KEY_F6));
192 break;
193 case KEY_F8:
194 case KEY_F9:
195 case KEY_F10:
196 break;
197 }
198 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800199 }
200 }
201
David Sodmanbf3f2842014-11-12 08:26:58 -0800202 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700203 /*
204 * Special case for key sequence that is used by external program. Just
205 * explicitly ignore here and do nothing.
206 */
207 if (input.kbd_state.shift_state)
208 return 1;
209
David Sodmanb0697c22014-12-12 10:29:25 -0800210 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800211 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700212 term_deactivate(terminal);
213 if (input.terminals[SPLASH_TERMINAL] != NULL) {
214 term_activate(input.terminals[SPLASH_TERMINAL]);
215 } else {
216 if (input.dbus != NULL)
217 (void)dbus_method_call0(input.dbus,
218 kLibCrosServiceName,
219 kLibCrosServicePath,
220 kLibCrosServiceInterface,
221 kTakeDisplayOwnership);
222 }
David Sodman8ef20062015-01-06 09:23:40 -0800223 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700224 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
David Sodman8ef20062015-01-06 09:23:40 -0800225 if (input.dbus != NULL)
David Sodmanbf3f2842014-11-12 08:26:58 -0800226 (void)dbus_method_call0(input.dbus,
227 kLibCrosServiceName,
228 kLibCrosServicePath,
229 kLibCrosServiceInterface,
David Sodman8ef20062015-01-06 09:23:40 -0800230 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800231 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700232 term_deactivate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800233 input.current_terminal = ev->code - KEY_F2;
234 terminal = input.terminals[input.current_terminal];
235 if (terminal == NULL) {
236 input.terminals[input.current_terminal] =
David Sodmanf0a925a2015-05-04 11:19:19 -0700237 term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800238 terminal =
239 input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800240 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800241 if (!term_is_valid(terminal)) {
242 LOG(ERROR, "Term init failed");
243 return 1;
244 }
245 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700246 term_activate(input.terminals[input.current_terminal]);
David Sodmanbf3f2842014-11-12 08:26:58 -0800247 }
248
249 return 1;
250
251 }
252
253 return 0;
254}
255
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800256static void input_get_keysym_and_unicode(struct input_key_event* event,
257 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800258{
259 struct {
260 uint32_t code;
261 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700262 } search_keys[] = {
263 { KEY_F1, KEYSYM_F1},
264 { KEY_F2, KEYSYM_F2},
265 { KEY_F3, KEYSYM_F3},
266 { KEY_F4, KEYSYM_F4},
267 { KEY_F5, KEYSYM_F5},
268 { KEY_F6, KEYSYM_F6},
269 { KEY_F7, KEYSYM_F7},
270 { KEY_F8, KEYSYM_F8},
271 { KEY_F9, KEYSYM_F8},
272 { KEY_F10, KEYSYM_F10},
273 { KEY_UP, KEYSYM_PAGEUP},
274 { KEY_DOWN, KEYSYM_PAGEDOWN},
275 { KEY_LEFT, KEYSYM_HOME},
276 { KEY_RIGHT, KEYSYM_END},
277 };
278
279 struct {
280 uint32_t code;
281 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800282 } non_ascii_keys[] = {
283 { KEY_ESC, KEYSYM_ESC},
284 { KEY_HOME, KEYSYM_HOME},
285 { KEY_LEFT, KEYSYM_LEFT},
286 { KEY_UP, KEYSYM_UP},
287 { KEY_RIGHT, KEYSYM_RIGHT},
288 { KEY_DOWN, KEYSYM_DOWN},
289 { KEY_PAGEUP, KEYSYM_PAGEUP},
290 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
291 { KEY_END, KEYSYM_END},
292 { KEY_INSERT, KEYSYM_INSERT},
293 { KEY_DELETE, KEYSYM_DELETE},
294 };
295
Dominik Behr58bb8e12015-09-22 14:30:41 -0700296 if (input.kbd_state.search_state) {
297 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
298 if (search_keys[i].code == event->code) {
299 *keysym = search_keys[i].keysym;
300 *unicode = -1;
301 return;
302 }
303 }
304 }
305
David Sodmanbf3f2842014-11-12 08:26:58 -0800306 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
307 if (non_ascii_keys[i].code == event->code) {
308 *keysym = non_ascii_keys[i].keysym;
309 *unicode = -1;
310 return;
311 }
312 }
313
314 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
315 *keysym = '?';
316 } else {
317 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
318 if ((input.kbd_state.control_state) && isascii(*keysym))
319 *keysym = tolower(*keysym) - 'a' + 1;
320 }
321
322 *unicode = *keysym;
323}
324
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800325static int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700326{
Dominik Behr93899452014-08-18 22:16:21 -0700327 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800328
Dominik Behr93899452014-08-18 22:16:21 -0700329 /* for some reason every device has a null enumerations and notifications
330 of every device come with NULL string first */
331 if (!devname) {
332 ret = -EINVAL;
333 goto errorret;
334 }
Haixia Shid288e032015-09-14 18:33:11 -0700335 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800336 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700337 if (strcmp(devname, input.devs[i].path) == 0) {
338 LOG(WARNING, "Skipping duplicate input device %s", devname);
339 ret = -EINVAL;
340 goto errorret;
341 }
342 }
Dominik Behr93899452014-08-18 22:16:21 -0700343 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700344 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700345 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700346
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800347 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700348 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800349 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700350 if (ret)
351 LOG(ERROR,
352 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
353 } else {
354 LOG(ERROR, "Evdev device %s grabbed by another process",
355 devname);
356 ret = -EBUSY;
357 goto closefd;
358 }
359
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800360 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700361 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
362 if (!newdevs) {
363 ret = -ENOMEM;
364 goto closefd;
365 }
366 input.devs = newdevs;
367 input.devs[input.ndevs].fd = fd;
368 input.devs[input.ndevs].path = strdup(devname);
369 if (!input.devs[input.ndevs].path) {
370 ret = -ENOMEM;
371 goto closefd;
372 }
373 input.ndevs++;
374
375 return fd;
376
377closefd:
378 close(fd);
379errorret:
380 return ret;
381}
382
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800383static void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700384{
Dominik Behr93899452014-08-18 22:16:21 -0700385 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800386
387 if (!devname)
388 return;
389
Dominik Behr93899452014-08-18 22:16:21 -0700390 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;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800409
Dominik Behr93899452014-08-18 22:16:21 -0700410 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
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800420 struct udev_enumerate* udev_enum;
421 struct udev_list_entry* devices, *deventry;
Dominik Behr93899452014-08-18 22:16:21 -0700422 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) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800427 const char* syspath;
428 struct udev_device* dev;
Dominik Behr93899452014-08-18 22:16:21 -0700429 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;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800450
Dominik Behr93899452014-08-18 22:16:21 -0700451 for (u = 0; u < input.ndevs; u++) {
452 free(input.devs[u].path);
453 close(input.devs[u].fd);
454 }
455 free(input.devs);
456 input.devs = NULL;
457 input.ndevs = 0;
458
459 udev_monitor_unref(input.udev_monitor);
460 input.udev_monitor = NULL;
461 udev_unref(input.udev);
462 input.udev = NULL;
463 input.udev_fd = -1;
464
David Sodmanbbcb0522014-09-19 10:34:07 -0700465 dbus_destroy(input.dbus);
466
467}
468
469void input_set_dbus(dbus_t* dbus)
470{
471 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700472}
473
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800474int input_setfds(fd_set* read_set, fd_set* exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700475{
Dominik Behr93899452014-08-18 22:16:21 -0700476 unsigned int u;
477 int max = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800478
Dominik Behr93899452014-08-18 22:16:21 -0700479 for (u = 0; u < input.ndevs; u++) {
480 FD_SET(input.devs[u].fd, read_set);
481 FD_SET(input.devs[u].fd, exception_set);
482 if (input.devs[u].fd > max)
483 max = input.devs[u].fd;
484 }
485
486 FD_SET(input.udev_fd, read_set);
487 FD_SET(input.udev_fd, exception_set);
488 if (input.udev_fd > max)
489 max = input.udev_fd;
490 return max;
491}
492
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800493struct input_key_event* input_get_event(fd_set* read_set,
494 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700495{
496 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700497 struct input_event ev;
498 int ret;
499
Dominik Behr93899452014-08-18 22:16:21 -0700500 if (FD_ISSET(input.udev_fd, exception_set)) {
501 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700502 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700503 }
504
Dominik Behr93899452014-08-18 22:16:21 -0700505 if (FD_ISSET(input.udev_fd, read_set)
506 && !FD_ISSET(input.udev_fd, exception_set)) {
507 /* we got an udev notification */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800508 struct udev_device* dev =
Dominik Behr93899452014-08-18 22:16:21 -0700509 udev_monitor_receive_device(input.udev_monitor);
510 if (dev) {
511 if (!strcmp("add", udev_device_get_action(dev))) {
512 input_add(udev_device_get_devnode(dev));
513 } else
514 if (!strcmp("remove", udev_device_get_action(dev)))
515 {
516 input_remove(udev_device_get_devnode(dev));
517 }
518 udev_device_unref(dev);
519 }
520 }
521
522 for (u = 0; u < input.ndevs; u++) {
523 if (FD_ISSET(input.devs[u].fd, read_set)
524 && !FD_ISSET(input.devs[u].fd, exception_set)) {
525 ret =
526 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400527 if (ret < 0) {
528 if (errno == EINTR || errno == EAGAIN)
529 continue;
530 if (errno != ENODEV) {
531 LOG(ERROR, "read: %s: %s", input.devs[u].path,
532 strerror(errno));
533 }
534 input_remove(input.devs[u].path);
535 return NULL;
536 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700537 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700538 (int) sizeof (struct input_event), ret);
539 return NULL;
540 }
541
542 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800543 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700544 malloc(sizeof (*event));
545 event->code = ev.code;
546 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700547 return event;
548 }
549 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700550 }
551
552 return NULL;
553}
554
David Sodmanf0a925a2015-05-04 11:19:19 -0700555int input_process(terminal_t* splash_term, uint32_t usec)
556{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800557 terminal_t* terminal;
558 terminal_t* new_terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700559 fd_set read_set, exception_set;
560 int maxfd;
561 int sstat;
562 struct timeval tm;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800563 struct timeval* ptm;
David Sodmanf0a925a2015-05-04 11:19:19 -0700564
565 terminal = input.terminals[input.current_terminal];
566
567 FD_ZERO(&read_set);
568 FD_ZERO(&exception_set);
569
570 if (input.dbus) {
571 dbus_add_fd(input.dbus, &read_set, &exception_set);
572 maxfd = dbus_get_fd(input.dbus) + 1;
573 } else {
574 maxfd = 0;
575 }
576
577 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
578
579 for (int i = 0; i < MAX_TERMINALS; i++) {
580 if (term_is_valid(input.terminals[i])) {
581 term_add_fd(input.terminals[i], &read_set, &exception_set);
582 maxfd = MAX(maxfd, term_fd(input.terminals[i])) + 1;
583 term_dispatch_io(input.terminals[i], &read_set);
584 }
585 }
586
587 if (usec) {
588 ptm = &tm;
589 tm.tv_sec = 0;
590 tm.tv_usec = usec;
591 } else
592 ptm = NULL;
593
594 sstat = select(maxfd, &read_set, NULL, &exception_set, ptm);
595 if (sstat == 0)
596 return 0;
597
David Sodmanf0a925a2015-05-04 11:19:19 -0700598 if (input.dbus)
599 dbus_dispatch_io(input.dbus);
600
601 if (term_exception(terminal, &exception_set))
602 return -1;
603
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800604 struct input_key_event* event;
David Sodmanf0a925a2015-05-04 11:19:19 -0700605 event = input_get_event(&read_set, &exception_set);
606 if (event) {
607 if (!input_special_key(event) && event->value) {
608 uint32_t keysym, unicode;
609 // current_terminal can possibly change during
610 // execution of input_special_key
611 terminal = input.terminals[input.current_terminal];
612 if (term_is_active(terminal)) {
613 // Only report user activity when the terminal is active
614 report_user_activity(USER_ACTIVITY_OTHER);
615 input_get_keysym_and_unicode(
616 event, &keysym, &unicode);
617 term_key_event(terminal,
618 keysym, unicode);
619 }
620 }
621 input_put_event(event);
622 }
623
624 for (int i = 0; i < MAX_TERMINALS; i++) {
625 if (term_is_valid(input.terminals[i])) {
626 term_add_fd(input.terminals[i], &read_set, &exception_set);
627 term_dispatch_io(input.terminals[i], &read_set);
628 }
629 }
630
631 if (term_is_valid(terminal)) {
632 if (term_is_child_done(terminal)) {
633 if (terminal == input.terminals[SPLASH_TERMINAL]) {
634 /*
635 * Note: reference is not lost because it is still referenced
636 * by the splash_t structure which will ultimately destroy
637 * it, once it's safe to do so
638 */
639 input.terminals[SPLASH_TERMINAL] = NULL;
640 return -1;
641 }
David Sodman30a94ef2015-07-26 17:37:12 -0700642 input.terminals[input.current_terminal] =
643 term_init(true, term_getvideo(terminal));
David Sodmanf0a925a2015-05-04 11:19:19 -0700644 new_terminal = input.terminals[input.current_terminal];
645 if (!term_is_valid(new_terminal)) {
646 return -1;
647 }
648 term_activate(new_terminal);
649 term_close(terminal);
650 }
651 }
652
653 return 0;
654}
655
David Sodmanbf3f2842014-11-12 08:26:58 -0800656int input_run(bool standalone)
657{
David Sodmanbf3f2842014-11-12 08:26:58 -0800658 terminal_t* terminal;
David Sodmanf0a925a2015-05-04 11:19:19 -0700659 int status;
David Sodmanbf3f2842014-11-12 08:26:58 -0800660
661 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800662 if (input.dbus) {
663 (void)dbus_method_call0(input.dbus,
664 kLibCrosServiceName,
665 kLibCrosServicePath,
666 kLibCrosServiceInterface,
667 kReleaseDisplayOwnership);
668 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800669
David Sodmanf0a925a2015-05-04 11:19:19 -0700670 input.terminals[input.current_terminal] = term_init(true, NULL);
David Sodmanbf3f2842014-11-12 08:26:58 -0800671 terminal = input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800672 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800673 }
674
675 while (1) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700676 status = input_process(NULL, 0);
677 if (status != 0) {
678 LOG(ERROR, "input process returned %d", status);
679 break;
David Sodmanbf3f2842014-11-12 08:26:58 -0800680 }
681 }
682
683 return 0;
684}
685
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800686void input_put_event(struct input_key_event* event)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700687{
688 free(event);
689}
David Sodmanbbcb0522014-09-19 10:34:07 -0700690
David Sodman8ef20062015-01-06 09:23:40 -0800691terminal_t* input_create_term(int vt)
692{
693 terminal_t* terminal;
694
695 if (vt == 0)
696 return input.terminals[input.current_terminal];
697
698 terminal = input.terminals[vt-1];
699 if (term_is_active(terminal))
700 return terminal;
701
702 if (terminal == NULL) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700703 input.terminals[vt-1] = term_init(false, NULL);
David Sodman8ef20062015-01-06 09:23:40 -0800704 terminal = input.terminals[vt-1];
705 if (!term_is_valid(terminal)) {
706 LOG(ERROR, "create_term: Term init failed");
707 }
708 }
709
710 return terminal;
711}
712
David Sodmanf0a925a2015-05-04 11:19:19 -0700713terminal_t* input_create_splash_term(video_t* video)
714{
715 input.terminals[SPLASH_TERMINAL] = term_init(false, video);
716 return input.terminals[SPLASH_TERMINAL];
717}
718
719void input_destroy_splash_term()
720{
721 input.terminals[SPLASH_TERMINAL] = NULL;
722}
723
David Sodman8ef20062015-01-06 09:23:40 -0800724void input_set_current(terminal_t* terminal)
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
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800732 for (int i = 0; i < MAX_TERMINALS; i++) {
David Sodman8ef20062015-01-06 09:23:40 -0800733 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}