blob: a04ee7f616dc43cb0f4e5d6b7d3dbebaa11004b0 [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
25#define MAX_TERMINALS (3)
David Sodmanbf3f2842014-11-12 08:26:58 -080026
Dominik Behr93899452014-08-18 22:16:21 -070027struct input_dev {
28 int fd;
29 char *path;
30};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070031
David Sodmanbf3f2842014-11-12 08:26:58 -080032struct keyboard_state {
33 int shift_state;
34 int control_state;
35 int alt_state;
David Sodmane0cc8312014-11-18 11:16:36 -080036 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080037};
38
Dominik Behr93899452014-08-18 22:16:21 -070039struct {
40 struct udev *udev;
41 struct udev_monitor *udev_monitor;
42 int udev_fd;
43 unsigned int ndevs;
44 struct input_dev *devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080045 struct keyboard_state kbd_state;
David Sodmanbbcb0522014-09-19 10:34:07 -070046 dbus_t *dbus;
David Sodmanbf3f2842014-11-12 08:26:58 -080047 uint32_t current_terminal;
48 terminal_t *terminals[MAX_TERMINALS];
Dominik Behr93899452014-08-18 22:16:21 -070049} input = {
50 .udev = NULL,
51 .udev_monitor = NULL,
52 .udev_fd = -1,
53 .ndevs = 0,
54 .devs = NULL,
David Sodmanbf3f2842014-11-12 08:26:58 -080055 .dbus = NULL,
56 .current_terminal = 0
Dominik Behr93899452014-08-18 22:16:21 -070057};
58
David Sodmane0cc8312014-11-18 11:16:36 -080059static void report_user_activity(int activity_type)
60{
David Sodman19e4f9d2015-03-10 11:11:09 -070061 dbus_bool_t allow_off = false;
David Sodman8ef20062015-01-06 09:23:40 -080062 if (!input.dbus)
63 return;
64
David Sodmane0cc8312014-11-18 11:16:36 -080065 dbus_method_call1(input.dbus, kPowerManagerServiceName,
66 kPowerManagerServicePath,
67 kPowerManagerInterface,
68 kHandleUserActivityMethod,
David Sodman19e4f9d2015-03-10 11:11:09 -070069 DBUS_TYPE_INT32, &activity_type);
David Sodmane0cc8312014-11-18 11:16:36 -080070
71 switch (activity_type) {
72 case USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS:
73 (void)dbus_method_call0(input.dbus,
74 kPowerManagerServiceName,
75 kPowerManagerServicePath,
76 kPowerManagerInterface,
77 kIncreaseScreenBrightnessMethod);
78 break;
79 case USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS:
David Sodman19e4f9d2015-03-10 11:11:09 -070080 /*
81 * Shouldn't allow the screen to go
82 * completely off while frecon is active
83 * so passing false to allow_off
84 */
85 (void)dbus_method_call1(input.dbus,
David Sodmane0cc8312014-11-18 11:16:36 -080086 kPowerManagerServiceName,
87 kPowerManagerServicePath,
88 kPowerManagerInterface,
David Sodman19e4f9d2015-03-10 11:11:09 -070089 kDecreaseScreenBrightnessMethod,
90 DBUS_TYPE_BOOLEAN, &allow_off);
David Sodmane0cc8312014-11-18 11:16:36 -080091 break;
92 }
93}
94
David Sodmanbf3f2842014-11-12 08:26:58 -080095static int input_special_key(struct input_key_event *ev)
96{
97 unsigned int i;
David Sodmanb0697c22014-12-12 10:29:25 -080098 terminal_t *terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080099
100 uint32_t ignore_keys[] = {
101 BTN_TOUCH, // touchpad events
102 BTN_TOOL_FINGER,
103 BTN_TOOL_DOUBLETAP,
104 BTN_TOOL_TRIPLETAP,
105 BTN_TOOL_QUADTAP,
106 BTN_TOOL_QUINTTAP,
107 BTN_LEFT, // mouse buttons
108 BTN_RIGHT,
109 BTN_MIDDLE,
110 BTN_SIDE,
111 BTN_EXTRA,
112 BTN_FORWARD,
113 BTN_BACK,
114 BTN_TASK
115 };
116
David Sodmanafba0d92015-01-27 19:07:46 -0800117 terminal = input.terminals[input.current_terminal];
118
David Sodmanbf3f2842014-11-12 08:26:58 -0800119 for (i = 0; i < ARRAY_SIZE(ignore_keys); i++)
120 if (ev->code == ignore_keys[i])
121 return 1;
122
123 switch (ev->code) {
124 case KEY_LEFTSHIFT:
125 case KEY_RIGHTSHIFT:
126 input.kbd_state.shift_state = ! !ev->value;
127 return 1;
128 case KEY_LEFTCTRL:
129 case KEY_RIGHTCTRL:
130 input.kbd_state.control_state = ! !ev->value;
131 return 1;
132 case KEY_LEFTALT:
133 case KEY_RIGHTALT:
134 input.kbd_state.alt_state = ! !ev->value;
135 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800136 case KEY_LEFTMETA: // search key
137 input.kbd_state.search_state = ! !ev->value;
138 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800139 }
140
David Sodmanafba0d92015-01-27 19:07:46 -0800141 if (term_is_active(terminal)) {
142 if (input.kbd_state.shift_state && ev->value) {
143 switch (ev->code) {
144 case KEY_PAGEUP:
David Sodmane0cc8312014-11-18 11:16:36 -0800145 term_page_up(input.terminals[input.current_terminal]);
146 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800147 case KEY_PAGEDOWN:
David Sodmane0cc8312014-11-18 11:16:36 -0800148 term_page_down(input.terminals[input.current_terminal]);
149 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800150 case KEY_UP:
151 term_line_up(input.terminals[input.current_terminal]);
152 return 1;
153 case KEY_DOWN:
154 term_line_down(input.terminals[input.current_terminal]);
155 return 1;
156 }
157 }
158
159 if (input.kbd_state.search_state && ev->value) {
160 switch (ev->code) {
161 case KEY_UP:
162 term_page_up(input.terminals[input.current_terminal]);
163 return 1;
164 case KEY_DOWN:
165 term_page_down(input.terminals[input.current_terminal]);
166 return 1;
167 }
168 }
169
170 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
171 input.kbd_state.control_state) &&
172 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
173 switch (ev->code) {
174 case KEY_F1:
175 case KEY_F2:
176 case KEY_F3:
177 case KEY_F4:
178 case KEY_F5:
179 break;
180 case KEY_F6:
181 case KEY_F7:
182 report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
183 (ev->code - KEY_F6));
184 break;
185 case KEY_F8:
186 case KEY_F9:
187 case KEY_F10:
188 break;
189 }
190 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800191 }
192 }
193
David Sodmanbf3f2842014-11-12 08:26:58 -0800194 if (input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700195 /*
196 * Special case for key sequence that is used by external program. Just
197 * explicitly ignore here and do nothing.
198 */
199 if (input.kbd_state.shift_state)
200 return 1;
201
David Sodmanb0697c22014-12-12 10:29:25 -0800202 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800203 if (term_is_active(terminal)) {
David Sodmanbf3f2842014-11-12 08:26:58 -0800204 input_ungrab();
David Sodmanb0697c22014-12-12 10:29:25 -0800205 terminal->active = false;
David Sodman35d6bd82014-11-24 08:23:00 -0800206 video_release(input.terminals[input.current_terminal]->video);
David Sodman8ef20062015-01-06 09:23:40 -0800207 if (input.dbus != NULL)
208 (void)dbus_method_call0(input.dbus,
209 kLibCrosServiceName,
210 kLibCrosServicePath,
211 kLibCrosServiceInterface,
212 kTakeDisplayOwnership);
213 }
214 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_TERMINALS)) {
215 if (input.dbus != NULL)
David Sodmanbf3f2842014-11-12 08:26:58 -0800216 (void)dbus_method_call0(input.dbus,
217 kLibCrosServiceName,
218 kLibCrosServicePath,
219 kLibCrosServiceInterface,
David Sodman8ef20062015-01-06 09:23:40 -0800220 kReleaseDisplayOwnership);
David Sodmanbf3f2842014-11-12 08:26:58 -0800221 if (term_is_active(terminal))
222 terminal->active = false;
223 input.current_terminal = ev->code - KEY_F2;
224 terminal = input.terminals[input.current_terminal];
225 if (terminal == NULL) {
226 input.terminals[input.current_terminal] =
David Sodman8ef20062015-01-06 09:23:40 -0800227 term_init(true);
David Sodmanbf3f2842014-11-12 08:26:58 -0800228 terminal =
229 input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800230 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800231 if (!term_is_valid(terminal)) {
232 LOG(ERROR, "Term init failed");
233 return 1;
234 }
235 }
236 input.terminals[input.current_terminal]->active = true;
237 input_grab();
238 video_setmode(terminal->video);
239 term_redraw(terminal);
240 }
241
242 return 1;
243
244 }
245
246 return 0;
247}
248
249static void input_get_keysym_and_unicode(struct input_key_event *event,
250 uint32_t *keysym, uint32_t *unicode)
251{
252 struct {
253 uint32_t code;
254 uint32_t keysym;
255 } non_ascii_keys[] = {
256 { KEY_ESC, KEYSYM_ESC},
257 { KEY_HOME, KEYSYM_HOME},
258 { KEY_LEFT, KEYSYM_LEFT},
259 { KEY_UP, KEYSYM_UP},
260 { KEY_RIGHT, KEYSYM_RIGHT},
261 { KEY_DOWN, KEYSYM_DOWN},
262 { KEY_PAGEUP, KEYSYM_PAGEUP},
263 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
264 { KEY_END, KEYSYM_END},
265 { KEY_INSERT, KEYSYM_INSERT},
266 { KEY_DELETE, KEYSYM_DELETE},
267 };
268
269 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
270 if (non_ascii_keys[i].code == event->code) {
271 *keysym = non_ascii_keys[i].keysym;
272 *unicode = -1;
273 return;
274 }
275 }
276
277 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
278 *keysym = '?';
279 } else {
280 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
281 if ((input.kbd_state.control_state) && isascii(*keysym))
282 *keysym = tolower(*keysym) - 'a' + 1;
283 }
284
285 *unicode = *keysym;
286}
287
Dominik Behr93899452014-08-18 22:16:21 -0700288static int input_add(const char *devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700289{
Dominik Behr93899452014-08-18 22:16:21 -0700290 int ret = 0, fd = -1;
291 /* for some reason every device has a null enumerations and notifications
292 of every device come with NULL string first */
293 if (!devname) {
294 ret = -EINVAL;
295 goto errorret;
296 }
297 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700298 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700299 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700300
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700301 ret = ioctl(fd, EVIOCGRAB, (void *) 1);
302
303 if (!ret) {
304 ioctl(fd, EVIOCGRAB, (void *) 0);
305 } else {
David Sodmanbbcb0522014-09-19 10:34:07 -0700306 LOG(ERROR, "Evdev device %s grabbed by another process",
Dominik Behr93899452014-08-18 22:16:21 -0700307 devname);
308 ret = -EBUSY;
309 goto closefd;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700310 }
311
Dominik Behr93899452014-08-18 22:16:21 -0700312 struct input_dev *newdevs =
313 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
314 if (!newdevs) {
315 ret = -ENOMEM;
316 goto closefd;
317 }
318 input.devs = newdevs;
319 input.devs[input.ndevs].fd = fd;
320 input.devs[input.ndevs].path = strdup(devname);
321 if (!input.devs[input.ndevs].path) {
322 ret = -ENOMEM;
323 goto closefd;
324 }
325 input.ndevs++;
326
327 return fd;
328
329closefd:
330 close(fd);
331errorret:
332 return ret;
333}
334
335static void input_remove(const char *devname)
336{
337 if (!devname) {
338 return;
339 }
340 unsigned int u;
341 for (u = 0; u < input.ndevs; u++) {
342 if (!strcmp(devname, input.devs[u].path)) {
343 free(input.devs[u].path);
344 close(input.devs[u].fd);
345 input.ndevs--;
346 if (u != input.ndevs) {
347 input.devs[u] = input.devs[input.ndevs];
348 }
349 return;
350 }
351 }
352}
353
Dominik Behr93899452014-08-18 22:16:21 -0700354
355int input_init()
356{
357 input.udev = udev_new();
358 if (!input.udev)
359 return -ENOENT;
360 input.udev_monitor = udev_monitor_new_from_netlink(input.udev, "udev");
361 if (!input.udev_monitor) {
362 udev_unref(input.udev);
363 return -ENOENT;
364 }
365 udev_monitor_filter_add_match_subsystem_devtype(input.udev_monitor, "input",
366 NULL);
367 udev_monitor_enable_receiving(input.udev_monitor);
368 input.udev_fd = udev_monitor_get_fd(input.udev_monitor);
369
370 struct udev_enumerate *udev_enum;
371 struct udev_list_entry *devices, *deventry;
372 udev_enum = udev_enumerate_new(input.udev);
373 udev_enumerate_add_match_subsystem(udev_enum, "input");
374 udev_enumerate_scan_devices(udev_enum);
375 devices = udev_enumerate_get_list_entry(udev_enum);
376 udev_list_entry_foreach(deventry, devices) {
377 const char *syspath;
378 struct udev_device *dev;
379 syspath = udev_list_entry_get_name(deventry);
380 dev = udev_device_new_from_syspath(input.udev, syspath);
381 input_add(udev_device_get_devnode(dev));
382 udev_device_unref(dev);
383 }
384 udev_enumerate_unref(udev_enum);
385
386 if (!isatty(fileno(stdout)))
387 setbuf(stdout, NULL);
388
David Sodmanbbcb0522014-09-19 10:34:07 -0700389 if (input.ndevs == 0) {
390 LOG(ERROR, "No valid inputs for terminal");
391 exit(EXIT_SUCCESS);
392 }
393
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700394 return 0;
395}
396
397void input_close()
398{
Dominik Behr93899452014-08-18 22:16:21 -0700399 unsigned int u;
400 for (u = 0; u < input.ndevs; u++) {
401 free(input.devs[u].path);
402 close(input.devs[u].fd);
403 }
404 free(input.devs);
405 input.devs = NULL;
406 input.ndevs = 0;
407
408 udev_monitor_unref(input.udev_monitor);
409 input.udev_monitor = NULL;
410 udev_unref(input.udev);
411 input.udev = NULL;
412 input.udev_fd = -1;
413
David Sodmanbbcb0522014-09-19 10:34:07 -0700414 dbus_destroy(input.dbus);
415
416}
417
418void input_set_dbus(dbus_t* dbus)
419{
420 input.dbus = dbus;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700421}
422
Dominik Behr93899452014-08-18 22:16:21 -0700423int input_setfds(fd_set * read_set, fd_set * exception_set)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700424{
Dominik Behr93899452014-08-18 22:16:21 -0700425 unsigned int u;
426 int max = -1;
427 for (u = 0; u < input.ndevs; u++) {
428 FD_SET(input.devs[u].fd, read_set);
429 FD_SET(input.devs[u].fd, exception_set);
430 if (input.devs[u].fd > max)
431 max = input.devs[u].fd;
432 }
433
434 FD_SET(input.udev_fd, read_set);
435 FD_SET(input.udev_fd, exception_set);
436 if (input.udev_fd > max)
437 max = input.udev_fd;
438 return max;
439}
440
Dominik Behr93899452014-08-18 22:16:21 -0700441struct input_key_event *input_get_event(fd_set * read_set,
442 fd_set * exception_set)
443{
444 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700445 struct input_event ev;
446 int ret;
447
Dominik Behr93899452014-08-18 22:16:21 -0700448 if (FD_ISSET(input.udev_fd, exception_set)) {
449 /* udev died on us? */
David Sodmanbbcb0522014-09-19 10:34:07 -0700450 LOG(ERROR, "Exception on udev fd");
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700451 }
452
Dominik Behr93899452014-08-18 22:16:21 -0700453 if (FD_ISSET(input.udev_fd, read_set)
454 && !FD_ISSET(input.udev_fd, exception_set)) {
455 /* we got an udev notification */
456 struct udev_device *dev =
457 udev_monitor_receive_device(input.udev_monitor);
458 if (dev) {
459 if (!strcmp("add", udev_device_get_action(dev))) {
460 input_add(udev_device_get_devnode(dev));
461 } else
462 if (!strcmp("remove", udev_device_get_action(dev)))
463 {
464 input_remove(udev_device_get_devnode(dev));
465 }
466 udev_device_unref(dev);
467 }
468 }
469
470 for (u = 0; u < input.ndevs; u++) {
471 if (FD_ISSET(input.devs[u].fd, read_set)
472 && !FD_ISSET(input.devs[u].fd, exception_set)) {
473 ret =
474 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400475 if (ret < 0) {
476 if (errno == EINTR || errno == EAGAIN)
477 continue;
478 if (errno != ENODEV) {
479 LOG(ERROR, "read: %s: %s", input.devs[u].path,
480 strerror(errno));
481 }
482 input_remove(input.devs[u].path);
483 return NULL;
484 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700485 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700486 (int) sizeof (struct input_event), ret);
487 return NULL;
488 }
489
490 if (ev.type == EV_KEY) {
491 struct input_key_event *event =
492 malloc(sizeof (*event));
493 event->code = ev.code;
494 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700495 return event;
496 }
497 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700498 }
499
500 return NULL;
501}
502
David Sodmanbf3f2842014-11-12 08:26:58 -0800503int input_run(bool standalone)
504{
505 fd_set read_set, exception_set;
506 terminal_t* terminal;
David Sodman8ef20062015-01-06 09:23:40 -0800507 int sstat;
David Sodmanbf3f2842014-11-12 08:26:58 -0800508
509 if (standalone) {
David Sodman8ef20062015-01-06 09:23:40 -0800510 if (input.dbus) {
511 (void)dbus_method_call0(input.dbus,
512 kLibCrosServiceName,
513 kLibCrosServicePath,
514 kLibCrosServiceInterface,
515 kReleaseDisplayOwnership);
516 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800517
David Sodman8ef20062015-01-06 09:23:40 -0800518 input.terminals[input.current_terminal] = term_init(true);
David Sodmanbf3f2842014-11-12 08:26:58 -0800519 terminal = input.terminals[input.current_terminal];
David Sodman8ef20062015-01-06 09:23:40 -0800520 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800521 if (term_is_valid(terminal)) {
522 input_grab();
523 }
524 }
525
526 while (1) {
David Sodman8ef20062015-01-06 09:23:40 -0800527 int maxfd;
David Sodmanbf3f2842014-11-12 08:26:58 -0800528 terminal = input.terminals[input.current_terminal];
529
530 FD_ZERO(&read_set);
531 FD_ZERO(&exception_set);
David Sodmanbf3f2842014-11-12 08:26:58 -0800532
David Sodman8ef20062015-01-06 09:23:40 -0800533 if (input.dbus) {
534 dbus_add_fd(input.dbus, &read_set, &exception_set);
535 maxfd = dbus_get_fd(input.dbus) + 1;
536 } else {
537 maxfd = 0;
538 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800539
David Sodman8ef20062015-01-06 09:23:40 -0800540 maxfd = MAX(maxfd, input_setfds(&read_set, &exception_set)) + 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800541
David Sodman8ef20062015-01-06 09:23:40 -0800542 for (int i = 0; i < MAX_TERMINALS; i++) {
543 if (term_is_valid(input.terminals[i])) {
544 term_add_fd(input.terminals[i], &read_set, &exception_set);
545 maxfd = MAX(maxfd, term_fd(input.terminals[i])) + 1;
546 term_dispatch_io(input.terminals[i], &read_set);
547 }
548 }
549
550 sstat = select(maxfd, &read_set, NULL, &exception_set, NULL);
551 if (sstat == 0)
552 continue;
553
554 if (input.dbus)
555 dbus_dispatch_io(input.dbus);
David Sodmanbf3f2842014-11-12 08:26:58 -0800556
557 if (term_exception(terminal, &exception_set))
558 return -1;
559
David Sodmanafba0d92015-01-27 19:07:46 -0800560 struct input_key_event *event;
561 event = input_get_event(&read_set, &exception_set);
562 if (event) {
563 if (!input_special_key(event) && event->value) {
564 uint32_t keysym, unicode;
565 // current_terminal can possibly change during
566 // execution of input_special_key
567 terminal = input.terminals[input.current_terminal];
568 if (term_is_active(terminal)) {
569 // Only report user activity when the terminal is active
570 report_user_activity(USER_ACTIVITY_OTHER);
571 input_get_keysym_and_unicode(
572 event, &keysym, &unicode);
573 term_key_event(terminal,
574 keysym, unicode);
David Sodmanbf3f2842014-11-12 08:26:58 -0800575 }
576 }
David Sodmanafba0d92015-01-27 19:07:46 -0800577 input_put_event(event);
David Sodmanbf3f2842014-11-12 08:26:58 -0800578 }
579
David Sodman8ef20062015-01-06 09:23:40 -0800580 for (int i = 0; i < MAX_TERMINALS; i++) {
581 if (term_is_valid(input.terminals[i])) {
582 term_add_fd(input.terminals[i], &read_set, &exception_set);
583 term_dispatch_io(input.terminals[i], &read_set);
584 }
585 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800586
587 if (term_is_valid(terminal)) {
588 if (term_is_child_done(terminal)) {
David Sodman5e5c37e2014-12-19 14:14:46 -0800589 if (terminal->video) {
590 // necessary in case chrome is playing full screen
591 // video or graphics
592 //TODO: This is still a race with Chrome. This
593 //needs to be fixed with bug 444209
594 video_setmode(terminal->video);
595 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800596 term_close(terminal);
David Sodman8ef20062015-01-06 09:23:40 -0800597 input.terminals[input.current_terminal] = term_init(true);
David Sodmanbf3f2842014-11-12 08:26:58 -0800598 terminal = input.terminals[input.current_terminal];
599 if (!term_is_valid(terminal)) {
600 return -1;
601 }
David Sodman8ef20062015-01-06 09:23:40 -0800602 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800603 }
604 }
605 }
606
607 return 0;
608}
609
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700610void input_put_event(struct input_key_event *event)
611{
612 free(event);
613}
David Sodmanbbcb0522014-09-19 10:34:07 -0700614
615void input_grab()
616{
617 unsigned int i;
618 for (i = 0; i < input.ndevs; i++) {
619 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void *) 1);
620 }
621}
622
623void input_ungrab()
624{
625 unsigned int i;
626 for (i = 0; i < input.ndevs; i++) {
627 (void)ioctl(input.devs[i].fd, EVIOCGRAB, (void*) 0);
628 }
629}
David Sodman8ef20062015-01-06 09:23:40 -0800630
631terminal_t* input_create_term(int vt)
632{
633 terminal_t* terminal;
634
635 if (vt == 0)
636 return input.terminals[input.current_terminal];
637
638 terminal = input.terminals[vt-1];
639 if (term_is_active(terminal))
640 return terminal;
641
642 if (terminal == NULL) {
643 input.terminals[vt-1] = term_init(false);
644 terminal = input.terminals[vt-1];
645 if (!term_is_valid(terminal)) {
646 LOG(ERROR, "create_term: Term init failed");
647 }
648 }
649
650 return terminal;
651}
652
653void input_set_current(terminal_t* terminal)
654{
655 int i;
656
657 if (!terminal)
658 return;
659
660 for (i = 0; i < MAX_TERMINALS; i++) {
661 if (terminal == input.terminals[i]) {
662 input.current_terminal = i;
663 return;
664 }
665 }
666}
667
668unsigned int input_get_maxterminals()
669{
670 return MAX_TERMINALS;
671}