blob: a8aea0756efca97b420a7fe86b7e258f1ab242dc [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"
Dominik Behr46c567f2016-03-08 15:11:48 -080022#include "main.h"
David Sodmanbbcb0522014-09-19 10:34:07 -070023#include "util.h"
David Sodman8ef20062015-01-06 09:23:40 -080024
Dominik Behr44e07e62016-01-13 19:43:57 -080025struct input_key_event {
26 uint16_t code;
27 unsigned char value;
28};
29
Dominik Behr93899452014-08-18 22:16:21 -070030struct input_dev {
31 int fd;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080032 char* path;
Dominik Behr93899452014-08-18 22:16:21 -070033};
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -070034
David Sodmanbf3f2842014-11-12 08:26:58 -080035struct keyboard_state {
36 int shift_state;
37 int control_state;
38 int alt_state;
David Sodmane0cc8312014-11-18 11:16:36 -080039 int search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080040};
41
Dylan Reid342aed02015-06-18 12:15:52 -070042/*
43 * structure to keep input state:
Dylan Reid342aed02015-06-18 12:15:52 -070044 * ndevs - number of input devices.
45 * devs - input devices to listen to.
46 * kbd_state - tracks modifier keys that are pressed.
Dylan Reid342aed02015-06-18 12:15:52 -070047 */
Dominik Behr93899452014-08-18 22:16:21 -070048struct {
Dominik Behr93899452014-08-18 22:16:21 -070049 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 = {
Dominik Behr93899452014-08-18 22:16:21 -070053 .ndevs = 0,
54 .devs = NULL,
Dominik Behr93899452014-08-18 22:16:21 -070055};
56
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080057static int input_special_key(struct input_key_event* ev)
David Sodmanbf3f2842014-11-12 08:26:58 -080058{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080059 terminal_t* terminal;
David Sodmanbf3f2842014-11-12 08:26:58 -080060
61 uint32_t ignore_keys[] = {
62 BTN_TOUCH, // touchpad events
63 BTN_TOOL_FINGER,
64 BTN_TOOL_DOUBLETAP,
65 BTN_TOOL_TRIPLETAP,
66 BTN_TOOL_QUADTAP,
67 BTN_TOOL_QUINTTAP,
68 BTN_LEFT, // mouse buttons
69 BTN_RIGHT,
70 BTN_MIDDLE,
71 BTN_SIDE,
72 BTN_EXTRA,
73 BTN_FORWARD,
74 BTN_BACK,
75 BTN_TASK
76 };
77
Dominik Behr4defb362016-01-13 12:36:14 -080078 terminal = term_get_current_terminal();
David Sodmanafba0d92015-01-27 19:07:46 -080079
Stéphane Marchesinac14d292015-12-14 15:27:18 -080080 for (unsigned int i = 0; i < ARRAY_SIZE(ignore_keys); i++)
David Sodmanbf3f2842014-11-12 08:26:58 -080081 if (ev->code == ignore_keys[i])
82 return 1;
83
84 switch (ev->code) {
85 case KEY_LEFTSHIFT:
86 case KEY_RIGHTSHIFT:
87 input.kbd_state.shift_state = ! !ev->value;
88 return 1;
89 case KEY_LEFTCTRL:
90 case KEY_RIGHTCTRL:
91 input.kbd_state.control_state = ! !ev->value;
92 return 1;
93 case KEY_LEFTALT:
94 case KEY_RIGHTALT:
95 input.kbd_state.alt_state = ! !ev->value;
96 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -080097 case KEY_LEFTMETA: // search key
98 input.kbd_state.search_state = ! !ev->value;
99 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800100 }
101
David Sodmanafba0d92015-01-27 19:07:46 -0800102 if (term_is_active(terminal)) {
103 if (input.kbd_state.shift_state && ev->value) {
104 switch (ev->code) {
105 case KEY_PAGEUP:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800106 term_page_up(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800107 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800108 case KEY_PAGEDOWN:
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800109 term_page_down(terminal);
David Sodmane0cc8312014-11-18 11:16:36 -0800110 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800111 case KEY_UP:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700112 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800113 term_page_up(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700114 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800115 term_line_up(terminal);
David Sodmanafba0d92015-01-27 19:07:46 -0800116 return 1;
117 case KEY_DOWN:
Dominik Behr58bb8e12015-09-22 14:30:41 -0700118 if (input.kbd_state.search_state)
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800119 term_page_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700120 else
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800121 term_line_down(terminal);
Dominik Behr58bb8e12015-09-22 14:30:41 -0700122 return 1;
David Sodmanafba0d92015-01-27 19:07:46 -0800123 }
124 }
125
126 if (!(input.kbd_state.search_state || input.kbd_state.alt_state ||
127 input.kbd_state.control_state) &&
128 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
129 switch (ev->code) {
130 case KEY_F1:
131 case KEY_F2:
132 case KEY_F3:
133 case KEY_F4:
134 case KEY_F5:
135 break;
136 case KEY_F6:
137 case KEY_F7:
Dominik Behr797a3832016-01-11 15:53:11 -0800138 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
139 (ev->code - KEY_F6));
David Sodmanafba0d92015-01-27 19:07:46 -0800140 break;
141 case KEY_F8:
142 case KEY_F9:
143 case KEY_F10:
144 break;
145 }
146 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800147 }
148 }
149
Dominik Behr46c567f2016-03-08 15:11:48 -0800150 if (command_flags.enable_vts &&
151 input.kbd_state.alt_state && input.kbd_state.control_state && ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700152 /*
153 * Special case for key sequence that is used by external program. Just
154 * explicitly ignore here and do nothing.
155 */
156 if (input.kbd_state.shift_state)
157 return 1;
158
David Sodmanb0697c22014-12-12 10:29:25 -0800159 if (ev->code == KEY_F1) {
David Sodmanb0697c22014-12-12 10:29:25 -0800160 if (term_is_active(terminal)) {
David Sodmanf0a925a2015-05-04 11:19:19 -0700161 term_deactivate(terminal);
Stéphane Marchesin08c08e72016-01-07 16:44:08 -0800162 if (term_get_terminal(SPLASH_TERMINAL) != NULL) {
163 term_activate(term_get_terminal(SPLASH_TERMINAL));
David Sodmanf0a925a2015-05-04 11:19:19 -0700164 } else {
Dominik Behr797a3832016-01-11 15:53:11 -0800165 dbus_take_display_ownership();
David Sodmanf0a925a2015-05-04 11:19:19 -0700166 }
David Sodman8ef20062015-01-06 09:23:40 -0800167 }
David Sodmanf0a925a2015-05-04 11:19:19 -0700168 } else if ((ev->code >= KEY_F2) && (ev->code < KEY_F2 + MAX_STD_TERMINALS)) {
Dominik Behr797a3832016-01-11 15:53:11 -0800169 dbus_release_display_ownership();
David Sodmanbf3f2842014-11-12 08:26:58 -0800170 if (term_is_active(terminal))
David Sodmanf0a925a2015-05-04 11:19:19 -0700171 term_deactivate(terminal);
Dominik Behr4defb362016-01-13 12:36:14 -0800172 term_set_current(ev->code - KEY_F2);
173 terminal = term_get_current_terminal();
David Sodmanbf3f2842014-11-12 08:26:58 -0800174 if (terminal == NULL) {
Dominik Behr83010f82016-03-18 18:43:08 -0700175 term_set_current_terminal(term_init(true));
David Sodmanbf3f2842014-11-12 08:26:58 -0800176 terminal =
Dominik Behr4defb362016-01-13 12:36:14 -0800177 term_get_current_terminal();
David Sodman8ef20062015-01-06 09:23:40 -0800178 term_activate(terminal);
David Sodmanbf3f2842014-11-12 08:26:58 -0800179 if (!term_is_valid(terminal)) {
180 LOG(ERROR, "Term init failed");
181 return 1;
182 }
183 }
Dominik Behr4defb362016-01-13 12:36:14 -0800184 term_activate(term_get_current_terminal());
David Sodmanbf3f2842014-11-12 08:26:58 -0800185 }
186
187 return 1;
188
189 }
190
191 return 0;
192}
193
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800194static void input_get_keysym_and_unicode(struct input_key_event* event,
195 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800196{
197 struct {
198 uint32_t code;
199 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700200 } search_keys[] = {
201 { KEY_F1, KEYSYM_F1},
202 { KEY_F2, KEYSYM_F2},
203 { KEY_F3, KEYSYM_F3},
204 { KEY_F4, KEYSYM_F4},
205 { KEY_F5, KEYSYM_F5},
206 { KEY_F6, KEYSYM_F6},
207 { KEY_F7, KEYSYM_F7},
208 { KEY_F8, KEYSYM_F8},
209 { KEY_F9, KEYSYM_F8},
210 { KEY_F10, KEYSYM_F10},
211 { KEY_UP, KEYSYM_PAGEUP},
212 { KEY_DOWN, KEYSYM_PAGEDOWN},
213 { KEY_LEFT, KEYSYM_HOME},
214 { KEY_RIGHT, KEYSYM_END},
215 };
216
217 struct {
218 uint32_t code;
219 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800220 } non_ascii_keys[] = {
221 { KEY_ESC, KEYSYM_ESC},
222 { KEY_HOME, KEYSYM_HOME},
223 { KEY_LEFT, KEYSYM_LEFT},
224 { KEY_UP, KEYSYM_UP},
225 { KEY_RIGHT, KEYSYM_RIGHT},
226 { KEY_DOWN, KEYSYM_DOWN},
227 { KEY_PAGEUP, KEYSYM_PAGEUP},
228 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
229 { KEY_END, KEYSYM_END},
230 { KEY_INSERT, KEYSYM_INSERT},
231 { KEY_DELETE, KEYSYM_DELETE},
232 };
233
Dominik Behr58bb8e12015-09-22 14:30:41 -0700234 if (input.kbd_state.search_state) {
235 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
236 if (search_keys[i].code == event->code) {
237 *keysym = search_keys[i].keysym;
238 *unicode = -1;
239 return;
240 }
241 }
242 }
243
David Sodmanbf3f2842014-11-12 08:26:58 -0800244 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
245 if (non_ascii_keys[i].code == event->code) {
246 *keysym = non_ascii_keys[i].keysym;
247 *unicode = -1;
248 return;
249 }
250 }
251
252 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
253 *keysym = '?';
254 } else {
255 *keysym = keysym_table[event->code * 2 + input.kbd_state.shift_state];
256 if ((input.kbd_state.control_state) && isascii(*keysym))
257 *keysym = tolower(*keysym) - 'a' + 1;
258 }
259
260 *unicode = *keysym;
261}
262
Dominik Behr5239cca2016-01-21 18:22:04 -0800263int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700264{
Dominik Behr93899452014-08-18 22:16:21 -0700265 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800266
Dominik Behr93899452014-08-18 22:16:21 -0700267 /* for some reason every device has a null enumerations and notifications
268 of every device come with NULL string first */
269 if (!devname) {
270 ret = -EINVAL;
271 goto errorret;
272 }
Haixia Shid288e032015-09-14 18:33:11 -0700273 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800274 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700275 if (strcmp(devname, input.devs[i].path) == 0) {
Stéphane Marchesinc02260b2016-01-07 22:46:45 -0800276 LOG(INFO, "Skipping duplicate input device %s", devname);
Haixia Shid288e032015-09-14 18:33:11 -0700277 ret = -EINVAL;
278 goto errorret;
279 }
280 }
Dominik Behr93899452014-08-18 22:16:21 -0700281 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700282 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700283 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700284
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800285 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700286 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800287 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700288 if (ret)
289 LOG(ERROR,
290 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
291 } else {
292 LOG(ERROR, "Evdev device %s grabbed by another process",
293 devname);
294 ret = -EBUSY;
295 goto closefd;
296 }
297
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800298 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700299 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
300 if (!newdevs) {
301 ret = -ENOMEM;
302 goto closefd;
303 }
304 input.devs = newdevs;
305 input.devs[input.ndevs].fd = fd;
306 input.devs[input.ndevs].path = strdup(devname);
307 if (!input.devs[input.ndevs].path) {
308 ret = -ENOMEM;
309 goto closefd;
310 }
311 input.ndevs++;
312
313 return fd;
314
315closefd:
316 close(fd);
317errorret:
318 return ret;
319}
320
Dominik Behr5239cca2016-01-21 18:22:04 -0800321void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700322{
Dominik Behr93899452014-08-18 22:16:21 -0700323 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800324
325 if (!devname)
326 return;
327
Dominik Behr93899452014-08-18 22:16:21 -0700328 for (u = 0; u < input.ndevs; u++) {
329 if (!strcmp(devname, input.devs[u].path)) {
330 free(input.devs[u].path);
331 close(input.devs[u].fd);
332 input.ndevs--;
333 if (u != input.ndevs) {
334 input.devs[u] = input.devs[input.ndevs];
335 }
336 return;
337 }
338 }
339}
340
Dominik Behr93899452014-08-18 22:16:21 -0700341int input_init()
342{
Dominik Behr93899452014-08-18 22:16:21 -0700343 if (!isatty(fileno(stdout)))
344 setbuf(stdout, NULL);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700345 return 0;
346}
347
348void input_close()
349{
Dominik Behr93899452014-08-18 22:16:21 -0700350 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800351
Dominik Behr93899452014-08-18 22:16:21 -0700352 for (u = 0; u < input.ndevs; u++) {
353 free(input.devs[u].path);
354 close(input.devs[u].fd);
355 }
356 free(input.devs);
357 input.devs = NULL;
358 input.ndevs = 0;
David Sodmanbbcb0522014-09-19 10:34:07 -0700359}
360
Dominik Behrd7112672016-01-20 16:59:34 -0800361void input_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700362{
Dominik Behr93899452014-08-18 22:16:21 -0700363 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800364
Dominik Behr93899452014-08-18 22:16:21 -0700365 for (u = 0; u < input.ndevs; u++) {
366 FD_SET(input.devs[u].fd, read_set);
367 FD_SET(input.devs[u].fd, exception_set);
Dominik Behrd7112672016-01-20 16:59:34 -0800368 if (input.devs[u].fd > *maxfd)
369 *maxfd = input.devs[u].fd;
Dominik Behr93899452014-08-18 22:16:21 -0700370 }
Dominik Behr93899452014-08-18 22:16:21 -0700371}
372
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800373struct input_key_event* input_get_event(fd_set* read_set,
374 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700375{
376 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700377 struct input_event ev;
378 int ret;
379
Dominik Behr93899452014-08-18 22:16:21 -0700380 for (u = 0; u < input.ndevs; u++) {
381 if (FD_ISSET(input.devs[u].fd, read_set)
382 && !FD_ISSET(input.devs[u].fd, exception_set)) {
383 ret =
384 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400385 if (ret < 0) {
386 if (errno == EINTR || errno == EAGAIN)
387 continue;
388 if (errno != ENODEV) {
389 LOG(ERROR, "read: %s: %s", input.devs[u].path,
390 strerror(errno));
391 }
392 input_remove(input.devs[u].path);
393 return NULL;
394 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700395 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700396 (int) sizeof (struct input_event), ret);
397 return NULL;
398 }
399
400 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800401 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700402 malloc(sizeof (*event));
403 event->code = ev.code;
404 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700405 return event;
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800406 } else if (ev.type == EV_SW && ev.code == SW_LID) {
407 /* TODO(dbehr), abstract this in input_key_event if we ever parse more than one */
408 term_monitor_hotplug();
Dominik Behr93899452014-08-18 22:16:21 -0700409 }
410 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700411 }
412
413 return NULL;
414}
415
Dominik Behr4defb362016-01-13 12:36:14 -0800416void input_put_event(struct input_key_event* event)
417{
418 free(event);
419}
420
Dominik Behr44e07e62016-01-13 19:43:57 -0800421void input_dispatch_io(fd_set* read_set, fd_set* exception_set)
David Sodmanf0a925a2015-05-04 11:19:19 -0700422{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800423 terminal_t* terminal;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800424 struct input_key_event* event;
Dominik Behr44e07e62016-01-13 19:43:57 -0800425
426 event = input_get_event(read_set, exception_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700427 if (event) {
428 if (!input_special_key(event) && event->value) {
429 uint32_t keysym, unicode;
430 // current_terminal can possibly change during
431 // execution of input_special_key
Dominik Behr4defb362016-01-13 12:36:14 -0800432 terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700433 if (term_is_active(terminal)) {
434 // Only report user activity when the terminal is active
Dominik Behr797a3832016-01-11 15:53:11 -0800435 dbus_report_user_activity(USER_ACTIVITY_OTHER);
David Sodmanf0a925a2015-05-04 11:19:19 -0700436 input_get_keysym_and_unicode(
437 event, &keysym, &unicode);
438 term_key_event(terminal,
439 keysym, unicode);
440 }
441 }
442 input_put_event(event);
443 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800444}
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800445
446#define BITS_PER_LONG (sizeof(long) * 8)
447#define BITS_TO_LONGS(bits) (((bits) - 1) / BITS_PER_LONG + 1)
448#define BITMASK_GET_BIT(bitmask, bit) \
449 ((bitmask[bit / BITS_PER_LONG] >> (bit % BITS_PER_LONG)) & 1)
450
451static const int kMaxBit = MAX(MAX(EV_MAX, KEY_MAX), SW_MAX);
452
453static bool has_event_bit(int fd, int event_type, int bit)
454{
455 unsigned long bitmask[BITS_TO_LONGS(kMaxBit+1)];
456 memset(bitmask, 0, sizeof(bitmask));
457
458 if (ioctl(fd, EVIOCGBIT(event_type, sizeof(bitmask)), bitmask) < 0)
459 return false;
460
461 return BITMASK_GET_BIT(bitmask, bit);
462}
463
464static int get_switch_bit(int fd, int bit) {
465 unsigned long bitmask[BITS_TO_LONGS(SW_MAX+1)];
466 memset(bitmask, 0, sizeof(bitmask));
467 if (ioctl(fd, EVIOCGSW(sizeof(bitmask)), bitmask) < 0)
468 return -1;
469
470 return BITMASK_GET_BIT(bitmask, bit);
471}
472
473static bool is_lid_switch(int fd)
474{
475 return has_event_bit(fd, 0, EV_SW) && has_event_bit(fd, EV_SW, SW_LID);
476}
477
478int input_check_lid_state(void)
479{
480 unsigned int u;
481
482 for (u = 0; u < input.ndevs; u++) {
483 if (is_lid_switch(input.devs[u].fd)) {
484 return get_switch_bit(input.devs[u].fd, SW_LID);
485 }
486 }
487 return -ENODEV;
488}
489