blob: 75c0d422614cf2d46a9d7920d58ceb583f48c73f [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>
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070010#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
Dominik Behr93899452014-08-18 22:16:21 -070014#include <sys/select.h>
David Sodman8ef20062015-01-06 09:23:40 -080015#include <unistd.h>
16
David Sodmanbbcb0522014-09-19 10:34:07 -070017#include "dbus.h"
Stéphane Marchesin6cbb7332016-01-07 21:18:43 -080018#include "dbus_interface.h"
Stéphane Marchesin62561a12015-12-11 17:32:37 -080019#include "input.h"
David Sodmanbf3f2842014-11-12 08:26:58 -080020#include "keysym.h"
Dominik Behr46c567f2016-03-08 15:11:48 -080021#include "main.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070022#include "util.h"
David Sodman8ef20062015-01-06 09:23:40 -080023
Dominik Behr44e07e62016-01-13 19:43:57 -080024struct input_key_event {
25 uint16_t code;
26 unsigned char value;
27};
28
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 {
Dominik Behr92a05072016-03-23 20:04:43 -070035 bool left_shift_state;
36 bool right_shift_state;
37 bool left_control_state;
38 bool right_control_state;
39 bool left_alt_state;
40 bool right_alt_state;
41 bool search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080042};
43
Dylan Reid342aed02015-06-18 12:15:52 -070044/*
45 * structure to keep input state:
Dylan Reid342aed02015-06-18 12:15:52 -070046 * ndevs - number of input devices.
47 * devs - input devices to listen to.
48 * kbd_state - tracks modifier keys that are pressed.
Dylan Reid342aed02015-06-18 12:15:52 -070049 */
Dominik Behr93899452014-08-18 22:16:21 -070050struct {
Dominik Behr93899452014-08-18 22:16:21 -070051 unsigned int ndevs;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080052 struct input_dev* devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080053 struct keyboard_state kbd_state;
Dominik Behr93899452014-08-18 22:16:21 -070054} input = {
Dominik Behr93899452014-08-18 22:16:21 -070055 .ndevs = 0,
56 .devs = NULL,
Dominik Behr93899452014-08-18 22:16:21 -070057};
58
Dominik Behr92a05072016-03-23 20:04:43 -070059static bool is_shift_pressed(struct keyboard_state* k)
60{
61 return k->left_shift_state || k->right_shift_state;
62}
63
64static bool is_control_pressed(struct keyboard_state* k)
65{
66 return k->left_control_state || k->right_control_state;
67}
68
69static bool is_alt_pressed(struct keyboard_state* k)
70{
71 return k->left_alt_state || k->right_alt_state;
72}
73
Dominik Behrf8f8e462020-03-20 14:33:13 -070074/* Return 1 if event is handled. */
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080075static int input_special_key(struct input_key_event* ev)
David Sodmanbf3f2842014-11-12 08:26:58 -080076{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080077 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080078
79 uint32_t ignore_keys[] = {
80 BTN_TOUCH, // touchpad events
81 BTN_TOOL_FINGER,
82 BTN_TOOL_DOUBLETAP,
83 BTN_TOOL_TRIPLETAP,
84 BTN_TOOL_QUADTAP,
85 BTN_TOOL_QUINTTAP,
86 BTN_LEFT, // mouse buttons
87 BTN_RIGHT,
88 BTN_MIDDLE,
89 BTN_SIDE,
90 BTN_EXTRA,
91 BTN_FORWARD,
92 BTN_BACK,
93 BTN_TASK
94 };
95
Dominik Behr4defb362016-01-13 12:36:14 -080096 terminal = term_get_current_terminal();
David Sodmanafba0d92015-01-27 19:07:46 -080097
Stéphane Marchesinac14d292015-12-14 15:27:18 -080098 for (unsigned int i = 0; i < ARRAY_SIZE(ignore_keys); i++)
David Sodmanbf3f2842014-11-12 08:26:58 -080099 if (ev->code == ignore_keys[i])
100 return 1;
101
102 switch (ev->code) {
103 case KEY_LEFTSHIFT:
Dominik Behr92a05072016-03-23 20:04:43 -0700104 input.kbd_state.left_shift_state = ! !ev->value;
105 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800106 case KEY_RIGHTSHIFT:
Dominik Behr92a05072016-03-23 20:04:43 -0700107 input.kbd_state.right_shift_state = ! !ev->value;
David Sodmanbf3f2842014-11-12 08:26:58 -0800108 return 1;
109 case KEY_LEFTCTRL:
Dominik Behr92a05072016-03-23 20:04:43 -0700110 input.kbd_state.left_control_state = ! !ev->value;
111 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800112 case KEY_RIGHTCTRL:
Dominik Behr92a05072016-03-23 20:04:43 -0700113 input.kbd_state.right_control_state = ! !ev->value;
David Sodmanbf3f2842014-11-12 08:26:58 -0800114 return 1;
115 case KEY_LEFTALT:
Dominik Behr92a05072016-03-23 20:04:43 -0700116 input.kbd_state.left_alt_state = ! !ev->value;
117 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800118 case KEY_RIGHTALT:
Dominik Behr92a05072016-03-23 20:04:43 -0700119 input.kbd_state.right_alt_state = ! !ev->value;
David Sodmanbf3f2842014-11-12 08:26:58 -0800120 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800121 case KEY_LEFTMETA: // search key
122 input.kbd_state.search_state = ! !ev->value;
123 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800124 }
125
David Sodmanafba0d92015-01-27 19:07:46 -0800126 if (term_is_active(terminal)) {
Dominik Behr92a05072016-03-23 20:04:43 -0700127 if (is_shift_pressed(&input.kbd_state) && ev->value) {
David Sodmanafba0d92015-01-27 19:07:46 -0800128 switch (ev->code) {
129 case KEY_PAGEUP:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800130 term_page_up(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800131 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800132 case KEY_PAGEDOWN:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800133 term_page_down(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800134 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800135 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700136 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800137 term_page_up(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700138 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800139 term_line_up(terminal);
David Sodmanafba0d92015-01-27 19:07:46 -0800140 return 1;
141 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700142 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800143 term_page_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700144 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800145 term_line_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700146 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800147 }
148 }
149
Haixia Shi95285872016-11-08 15:26:35 -0800150 if (!is_alt_pressed(&input.kbd_state) &&
151 is_control_pressed(&input.kbd_state) &&
152 is_shift_pressed(&input.kbd_state) && ev->value) {
153 switch (ev->code) {
154 case KEY_MINUS:
155 term_zoom(false);
156 return 1;
157 case KEY_EQUAL:
158 term_zoom(true);
159 return 1;
160 }
161 }
162
Dominik Behr92a05072016-03-23 20:04:43 -0700163 if (!(input.kbd_state.search_state ||
164 is_alt_pressed(&input.kbd_state) ||
165 is_control_pressed(&input.kbd_state)) &&
Dominik Behrf8f8e462020-03-20 14:33:13 -0700166 ev->value) {
David Sodmanafba0d92015-01-27 19:07:46 -0800167 switch (ev->code) {
168 case KEY_F1:
169 case KEY_F2:
170 case KEY_F3:
171 case KEY_F4:
172 case KEY_F5:
173 break;
174 case KEY_F6:
175 case KEY_F7:
Dominik Behr797a3832016-01-11 15:53:11 -0800176 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
177 (ev->code - KEY_F6));
Dominik Behrf8f8e462020-03-20 14:33:13 -0700178 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800179 case KEY_F8:
180 case KEY_F9:
181 case KEY_F10:
182 break;
Dominik Behrf8f8e462020-03-20 14:33:13 -0700183 case KEY_BRIGHTNESSDOWN:
184 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS);
185 return 1;
186 case KEY_BRIGHTNESSUP:
187 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_UP_KEY_PRESS);
188 return 1;
189 case KEY_MUTE:
190 dbus_report_user_activity(USER_ACTIVITY_VOLUME_MUTE_KEY_PRESS);
191 return 1;
192 case KEY_VOLUMEDOWN:
193 dbus_report_user_activity(USER_ACTIVITY_VOLUME_DOWN_KEY_PRESS);
194 return 1;
195 case KEY_VOLUMEUP:
196 dbus_report_user_activity(USER_ACTIVITY_VOLUME_MUTE_KEY_PRESS);
197 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800198 }
David Sodmane0cc8312014-11-18 11:16:36 -0800199 }
200 }
201
Dominik Behrf8f8e462020-03-20 14:33:13 -0700202 /*
203 * Special case for key sequence that is used by Crouton.
204 * Just explicitly ignore here and do nothing.
205 * TODO(dbehr) remove it, when dnschneid is cool with it.
206 */
Dominik Behr46c567f2016-03-08 15:11:48 -0800207 if (command_flags.enable_vts &&
Dominik Behr92a05072016-03-23 20:04:43 -0700208 is_alt_pressed(&input.kbd_state) &&
209 is_control_pressed(&input.kbd_state) &&
Dominik Behrf8f8e462020-03-20 14:33:13 -0700210 is_shift_pressed(&input.kbd_state) &&
211 (ev->code >= KEY_F1) && (ev->code <= KEY_F10) &&
Dominik Behr92a05072016-03-23 20:04:43 -0700212 ev->value) {
Dominik Behrf8f8e462020-03-20 14:33:13 -0700213 return 1;
214 }
215
216 /* Console switching. */
217 if (command_flags.enable_vts &&
218 is_alt_pressed(&input.kbd_state) &&
219 is_control_pressed(&input.kbd_state) &&
220 !is_shift_pressed(&input.kbd_state) &&
221 ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700222
Dominik Behrda6df412016-08-02 12:56:42 -0700223 if ((ev->code >= KEY_F1) && (ev->code < KEY_F1 + term_num_terminals)) {
224 term_switch_to(ev->code - KEY_F1);
Dominik Behrf8f8e462020-03-20 14:33:13 -0700225 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800226 }
227
Dominik Behrf8f8e462020-03-20 14:33:13 -0700228 /* No F-keys on Vivaldi keyboards, use action codes that are
229 * guaranteed to be always there.
230 */
231 switch (ev->code) {
232 case KEY_BACK:
233 term_switch_to(0);
234 return 1;
Rajat Jainbc49d6e2020-05-13 23:05:47 -0700235 case KEY_FORWARD:
Dominik Behrf8f8e462020-03-20 14:33:13 -0700236 case KEY_REFRESH:
237 if (term_num_terminals >= 2) {
238 term_switch_to(1);
239 return 1;
240 }
241 break;
242 case KEY_ZOOM:
243 if (term_num_terminals >= 3) {
244 term_switch_to(2);
245 return 1;
246 }
247 break;
248 case KEY_SCALE:
249 if (term_num_terminals >= 4) {
250 term_switch_to(3);
251 return 1;
252 }
253 break;
254 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800255 }
256
257 return 0;
258}
259
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800260static void input_get_keysym_and_unicode(struct input_key_event* event,
261 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800262{
263 struct {
264 uint32_t code;
265 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700266 } search_keys[] = {
267 { KEY_F1, KEYSYM_F1},
268 { KEY_F2, KEYSYM_F2},
269 { KEY_F3, KEYSYM_F3},
270 { KEY_F4, KEYSYM_F4},
271 { KEY_F5, KEYSYM_F5},
272 { KEY_F6, KEYSYM_F6},
273 { KEY_F7, KEYSYM_F7},
274 { KEY_F8, KEYSYM_F8},
275 { KEY_F9, KEYSYM_F8},
276 { KEY_F10, KEYSYM_F10},
277 { KEY_UP, KEYSYM_PAGEUP},
278 { KEY_DOWN, KEYSYM_PAGEDOWN},
279 { KEY_LEFT, KEYSYM_HOME},
280 { KEY_RIGHT, KEYSYM_END},
281 };
282
283 struct {
284 uint32_t code;
285 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800286 } non_ascii_keys[] = {
287 { KEY_ESC, KEYSYM_ESC},
288 { KEY_HOME, KEYSYM_HOME},
289 { KEY_LEFT, KEYSYM_LEFT},
290 { KEY_UP, KEYSYM_UP},
291 { KEY_RIGHT, KEYSYM_RIGHT},
292 { KEY_DOWN, KEYSYM_DOWN},
293 { KEY_PAGEUP, KEYSYM_PAGEUP},
294 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
295 { KEY_END, KEYSYM_END},
296 { KEY_INSERT, KEYSYM_INSERT},
297 { KEY_DELETE, KEYSYM_DELETE},
298 };
299
Dominik Behr58bb8e12015-09-22 14:30:41 -0700300 if (input.kbd_state.search_state) {
301 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
302 if (search_keys[i].code == event->code) {
303 *keysym = search_keys[i].keysym;
304 *unicode = -1;
305 return;
306 }
307 }
308 }
309
David Sodmanbf3f2842014-11-12 08:26:58 -0800310 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
311 if (non_ascii_keys[i].code == event->code) {
312 *keysym = non_ascii_keys[i].keysym;
313 *unicode = -1;
314 return;
315 }
316 }
317
318 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
319 *keysym = '?';
320 } else {
Dominik Behr92a05072016-03-23 20:04:43 -0700321 *keysym = keysym_table[event->code * 2 + is_shift_pressed(&input.kbd_state)];
322 if (is_control_pressed(&input.kbd_state) && isascii(*keysym))
David Sodmanbf3f2842014-11-12 08:26:58 -0800323 *keysym = tolower(*keysym) - 'a' + 1;
324 }
325
326 *unicode = *keysym;
327}
328
Dominik Behr5239cca2016-01-21 18:22:04 -0800329int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700330{
Dominik Behr93899452014-08-18 22:16:21 -0700331 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800332
Dominik Behr93899452014-08-18 22:16:21 -0700333 /* for some reason every device has a null enumerations and notifications
334 of every device come with NULL string first */
335 if (!devname) {
336 ret = -EINVAL;
337 goto errorret;
338 }
Haixia Shid288e032015-09-14 18:33:11 -0700339 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800340 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700341 if (strcmp(devname, input.devs[i].path) == 0) {
Stéphane Marchesinc02260b2016-01-07 22:46:45 -0800342 LOG(INFO, "Skipping duplicate input device %s", devname);
Haixia Shid288e032015-09-14 18:33:11 -0700343 ret = -EINVAL;
344 goto errorret;
345 }
346 }
Dominik Behr93899452014-08-18 22:16:21 -0700347 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700348 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700349 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700350
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800351 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700352 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800353 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700354 if (ret)
355 LOG(ERROR,
356 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
357 } else {
358 LOG(ERROR, "Evdev device %s grabbed by another process",
359 devname);
360 ret = -EBUSY;
361 goto closefd;
362 }
363
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800364 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700365 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
366 if (!newdevs) {
367 ret = -ENOMEM;
368 goto closefd;
369 }
370 input.devs = newdevs;
371 input.devs[input.ndevs].fd = fd;
372 input.devs[input.ndevs].path = strdup(devname);
373 if (!input.devs[input.ndevs].path) {
374 ret = -ENOMEM;
375 goto closefd;
376 }
377 input.ndevs++;
378
379 return fd;
380
381closefd:
382 close(fd);
383errorret:
384 return ret;
385}
386
Dominik Behr5239cca2016-01-21 18:22:04 -0800387void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700388{
Dominik Behr93899452014-08-18 22:16:21 -0700389 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800390
391 if (!devname)
392 return;
393
Dominik Behr93899452014-08-18 22:16:21 -0700394 for (u = 0; u < input.ndevs; u++) {
395 if (!strcmp(devname, input.devs[u].path)) {
396 free(input.devs[u].path);
397 close(input.devs[u].fd);
398 input.ndevs--;
399 if (u != input.ndevs) {
400 input.devs[u] = input.devs[input.ndevs];
401 }
402 return;
403 }
404 }
405}
406
Dominik Behr93899452014-08-18 22:16:21 -0700407int input_init()
408{
Dominik Behr93899452014-08-18 22:16:21 -0700409 if (!isatty(fileno(stdout)))
410 setbuf(stdout, NULL);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700411 return 0;
412}
413
414void input_close()
415{
Dominik Behr93899452014-08-18 22:16:21 -0700416 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800417
Dominik Behr93899452014-08-18 22:16:21 -0700418 for (u = 0; u < input.ndevs; u++) {
419 free(input.devs[u].path);
420 close(input.devs[u].fd);
421 }
422 free(input.devs);
423 input.devs = NULL;
424 input.ndevs = 0;
David Sodmanbbcb0522014-09-19 10:34:07 -0700425}
426
Dominik Behrd7112672016-01-20 16:59:34 -0800427void input_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700428{
Dominik Behr93899452014-08-18 22:16:21 -0700429 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800430
Dominik Behr93899452014-08-18 22:16:21 -0700431 for (u = 0; u < input.ndevs; u++) {
432 FD_SET(input.devs[u].fd, read_set);
433 FD_SET(input.devs[u].fd, exception_set);
Dominik Behrd7112672016-01-20 16:59:34 -0800434 if (input.devs[u].fd > *maxfd)
435 *maxfd = input.devs[u].fd;
Dominik Behr93899452014-08-18 22:16:21 -0700436 }
Dominik Behr93899452014-08-18 22:16:21 -0700437}
438
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800439struct input_key_event* input_get_event(fd_set* read_set,
440 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700441{
442 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700443 struct input_event ev;
444 int ret;
445
Dominik Behr93899452014-08-18 22:16:21 -0700446 for (u = 0; u < input.ndevs; u++) {
447 if (FD_ISSET(input.devs[u].fd, read_set)
448 && !FD_ISSET(input.devs[u].fd, exception_set)) {
449 ret =
450 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400451 if (ret < 0) {
452 if (errno == EINTR || errno == EAGAIN)
453 continue;
454 if (errno != ENODEV) {
455 LOG(ERROR, "read: %s: %s", input.devs[u].path,
456 strerror(errno));
457 }
458 input_remove(input.devs[u].path);
459 return NULL;
460 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700461 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700462 (int) sizeof (struct input_event), ret);
463 return NULL;
464 }
465
466 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800467 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700468 malloc(sizeof (*event));
469 event->code = ev.code;
470 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700471 return event;
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800472 } else if (ev.type == EV_SW && ev.code == SW_LID) {
473 /* TODO(dbehr), abstract this in input_key_event if we ever parse more than one */
474 term_monitor_hotplug();
Dominik Behr93899452014-08-18 22:16:21 -0700475 }
476 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700477 }
478
479 return NULL;
480}
481
Dominik Behr4defb362016-01-13 12:36:14 -0800482void input_put_event(struct input_key_event* event)
483{
484 free(event);
485}
486
Dominik Behr44e07e62016-01-13 19:43:57 -0800487void input_dispatch_io(fd_set* read_set, fd_set* exception_set)
David Sodmanf0a925a2015-05-04 11:19:19 -0700488{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800489 terminal_t* terminal;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800490 struct input_key_event* event;
Dominik Behr44e07e62016-01-13 19:43:57 -0800491
492 event = input_get_event(read_set, exception_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700493 if (event) {
494 if (!input_special_key(event) && event->value) {
495 uint32_t keysym, unicode;
496 // current_terminal can possibly change during
497 // execution of input_special_key
Dominik Behr4defb362016-01-13 12:36:14 -0800498 terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700499 if (term_is_active(terminal)) {
500 // Only report user activity when the terminal is active
Dominik Behr797a3832016-01-11 15:53:11 -0800501 dbus_report_user_activity(USER_ACTIVITY_OTHER);
David Sodmanf0a925a2015-05-04 11:19:19 -0700502 input_get_keysym_and_unicode(
503 event, &keysym, &unicode);
504 term_key_event(terminal,
505 keysym, unicode);
506 }
507 }
508 input_put_event(event);
509 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800510}
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800511
512#define BITS_PER_LONG (sizeof(long) * 8)
513#define BITS_TO_LONGS(bits) (((bits) - 1) / BITS_PER_LONG + 1)
514#define BITMASK_GET_BIT(bitmask, bit) \
515 ((bitmask[bit / BITS_PER_LONG] >> (bit % BITS_PER_LONG)) & 1)
516
517static const int kMaxBit = MAX(MAX(EV_MAX, KEY_MAX), SW_MAX);
518
519static bool has_event_bit(int fd, int event_type, int bit)
520{
521 unsigned long bitmask[BITS_TO_LONGS(kMaxBit+1)];
522 memset(bitmask, 0, sizeof(bitmask));
523
524 if (ioctl(fd, EVIOCGBIT(event_type, sizeof(bitmask)), bitmask) < 0)
525 return false;
526
527 return BITMASK_GET_BIT(bitmask, bit);
528}
529
530static int get_switch_bit(int fd, int bit) {
531 unsigned long bitmask[BITS_TO_LONGS(SW_MAX+1)];
532 memset(bitmask, 0, sizeof(bitmask));
533 if (ioctl(fd, EVIOCGSW(sizeof(bitmask)), bitmask) < 0)
534 return -1;
535
536 return BITMASK_GET_BIT(bitmask, bit);
537}
538
539static bool is_lid_switch(int fd)
540{
541 return has_event_bit(fd, 0, EV_SW) && has_event_bit(fd, EV_SW, SW_LID);
542}
543
544int input_check_lid_state(void)
545{
546 unsigned int u;
547
548 for (u = 0; u < input.ndevs; u++) {
549 if (is_lid_switch(input.devs[u].fd)) {
550 return get_switch_bit(input.devs[u].fd, SW_LID);
551 }
552 }
553 return -ENODEV;
554}
555