blob: 282b7963546cdb0a012f587f33e06743522c02e0 [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 {
Dominik Behr92a05072016-03-23 20:04:43 -070036 bool left_shift_state;
37 bool right_shift_state;
38 bool left_control_state;
39 bool right_control_state;
40 bool left_alt_state;
41 bool right_alt_state;
42 bool search_state;
David Sodmanbf3f2842014-11-12 08:26:58 -080043};
44
Dylan Reid342aed02015-06-18 12:15:52 -070045/*
46 * structure to keep input state:
Dylan Reid342aed02015-06-18 12:15:52 -070047 * ndevs - number of input devices.
48 * devs - input devices to listen to.
49 * kbd_state - tracks modifier keys that are pressed.
Dylan Reid342aed02015-06-18 12:15:52 -070050 */
Dominik Behr93899452014-08-18 22:16:21 -070051struct {
Dominik Behr93899452014-08-18 22:16:21 -070052 unsigned int ndevs;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -080053 struct input_dev* devs;
David Sodmanbf3f2842014-11-12 08:26:58 -080054 struct keyboard_state kbd_state;
Dominik Behr93899452014-08-18 22:16:21 -070055} input = {
Dominik Behr93899452014-08-18 22:16:21 -070056 .ndevs = 0,
57 .devs = NULL,
Dominik Behr93899452014-08-18 22:16:21 -070058};
59
Dominik Behr92a05072016-03-23 20:04:43 -070060static bool is_shift_pressed(struct keyboard_state* k)
61{
62 return k->left_shift_state || k->right_shift_state;
63}
64
65static bool is_control_pressed(struct keyboard_state* k)
66{
67 return k->left_control_state || k->right_control_state;
68}
69
70static bool is_alt_pressed(struct keyboard_state* k)
71{
72 return k->left_alt_state || k->right_alt_state;
73}
74
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
Dominik Behr92a05072016-03-23 20:04:43 -0700150 if (!(input.kbd_state.search_state ||
151 is_alt_pressed(&input.kbd_state) ||
152 is_control_pressed(&input.kbd_state)) &&
153 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
David Sodmanafba0d92015-01-27 19:07:46 -0800154 switch (ev->code) {
155 case KEY_F1:
156 case KEY_F2:
157 case KEY_F3:
158 case KEY_F4:
159 case KEY_F5:
160 break;
161 case KEY_F6:
162 case KEY_F7:
Dominik Behr797a3832016-01-11 15:53:11 -0800163 dbus_report_user_activity(USER_ACTIVITY_BRIGHTNESS_DOWN_KEY_PRESS -
164 (ev->code - KEY_F6));
David Sodmanafba0d92015-01-27 19:07:46 -0800165 break;
166 case KEY_F8:
167 case KEY_F9:
168 case KEY_F10:
169 break;
170 }
171 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800172 }
173 }
174
Dominik Behr46c567f2016-03-08 15:11:48 -0800175 if (command_flags.enable_vts &&
Dominik Behr92a05072016-03-23 20:04:43 -0700176 is_alt_pressed(&input.kbd_state) &&
177 is_control_pressed(&input.kbd_state) &&
178 ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700179 /*
180 * Special case for key sequence that is used by external program. Just
181 * explicitly ignore here and do nothing.
182 */
Dominik Behr92a05072016-03-23 20:04:43 -0700183 if (is_shift_pressed(&input.kbd_state))
David Sodman1d1c67f2015-03-12 11:01:08 -0700184 return 1;
185
Dominik Behrda6df412016-08-02 12:56:42 -0700186 if ((ev->code >= KEY_F1) && (ev->code < KEY_F1 + term_num_terminals)) {
187 term_switch_to(ev->code - KEY_F1);
David Sodmanbf3f2842014-11-12 08:26:58 -0800188 }
189
190 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800191 }
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 {
Dominik Behr92a05072016-03-23 20:04:43 -0700257 *keysym = keysym_table[event->code * 2 + is_shift_pressed(&input.kbd_state)];
258 if (is_control_pressed(&input.kbd_state) && isascii(*keysym))
David Sodmanbf3f2842014-11-12 08:26:58 -0800259 *keysym = tolower(*keysym) - 'a' + 1;
260 }
261
262 *unicode = *keysym;
263}
264
Dominik Behr5239cca2016-01-21 18:22:04 -0800265int 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
Dominik Behr5239cca2016-01-21 18:22:04 -0800323void 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 -0700343int input_init()
344{
Dominik Behr93899452014-08-18 22:16:21 -0700345 if (!isatty(fileno(stdout)))
346 setbuf(stdout, NULL);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700347 return 0;
348}
349
350void input_close()
351{
Dominik Behr93899452014-08-18 22:16:21 -0700352 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800353
Dominik Behr93899452014-08-18 22:16:21 -0700354 for (u = 0; u < input.ndevs; u++) {
355 free(input.devs[u].path);
356 close(input.devs[u].fd);
357 }
358 free(input.devs);
359 input.devs = NULL;
360 input.ndevs = 0;
David Sodmanbbcb0522014-09-19 10:34:07 -0700361}
362
Dominik Behrd7112672016-01-20 16:59:34 -0800363void input_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700364{
Dominik Behr93899452014-08-18 22:16:21 -0700365 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800366
Dominik Behr93899452014-08-18 22:16:21 -0700367 for (u = 0; u < input.ndevs; u++) {
368 FD_SET(input.devs[u].fd, read_set);
369 FD_SET(input.devs[u].fd, exception_set);
Dominik Behrd7112672016-01-20 16:59:34 -0800370 if (input.devs[u].fd > *maxfd)
371 *maxfd = input.devs[u].fd;
Dominik Behr93899452014-08-18 22:16:21 -0700372 }
Dominik Behr93899452014-08-18 22:16:21 -0700373}
374
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800375struct input_key_event* input_get_event(fd_set* read_set,
376 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700377{
378 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700379 struct input_event ev;
380 int ret;
381
Dominik Behr93899452014-08-18 22:16:21 -0700382 for (u = 0; u < input.ndevs; u++) {
383 if (FD_ISSET(input.devs[u].fd, read_set)
384 && !FD_ISSET(input.devs[u].fd, exception_set)) {
385 ret =
386 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400387 if (ret < 0) {
388 if (errno == EINTR || errno == EAGAIN)
389 continue;
390 if (errno != ENODEV) {
391 LOG(ERROR, "read: %s: %s", input.devs[u].path,
392 strerror(errno));
393 }
394 input_remove(input.devs[u].path);
395 return NULL;
396 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700397 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700398 (int) sizeof (struct input_event), ret);
399 return NULL;
400 }
401
402 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800403 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700404 malloc(sizeof (*event));
405 event->code = ev.code;
406 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700407 return event;
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800408 } else if (ev.type == EV_SW && ev.code == SW_LID) {
409 /* TODO(dbehr), abstract this in input_key_event if we ever parse more than one */
410 term_monitor_hotplug();
Dominik Behr93899452014-08-18 22:16:21 -0700411 }
412 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700413 }
414
415 return NULL;
416}
417
Dominik Behr4defb362016-01-13 12:36:14 -0800418void input_put_event(struct input_key_event* event)
419{
420 free(event);
421}
422
Dominik Behr44e07e62016-01-13 19:43:57 -0800423void input_dispatch_io(fd_set* read_set, fd_set* exception_set)
David Sodmanf0a925a2015-05-04 11:19:19 -0700424{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800425 terminal_t* terminal;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800426 struct input_key_event* event;
Dominik Behr44e07e62016-01-13 19:43:57 -0800427
428 event = input_get_event(read_set, exception_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700429 if (event) {
430 if (!input_special_key(event) && event->value) {
431 uint32_t keysym, unicode;
432 // current_terminal can possibly change during
433 // execution of input_special_key
Dominik Behr4defb362016-01-13 12:36:14 -0800434 terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700435 if (term_is_active(terminal)) {
436 // Only report user activity when the terminal is active
Dominik Behr797a3832016-01-11 15:53:11 -0800437 dbus_report_user_activity(USER_ACTIVITY_OTHER);
David Sodmanf0a925a2015-05-04 11:19:19 -0700438 input_get_keysym_and_unicode(
439 event, &keysym, &unicode);
440 term_key_event(terminal,
441 keysym, unicode);
442 }
443 }
444 input_put_event(event);
445 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800446}
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800447
448#define BITS_PER_LONG (sizeof(long) * 8)
449#define BITS_TO_LONGS(bits) (((bits) - 1) / BITS_PER_LONG + 1)
450#define BITMASK_GET_BIT(bitmask, bit) \
451 ((bitmask[bit / BITS_PER_LONG] >> (bit % BITS_PER_LONG)) & 1)
452
453static const int kMaxBit = MAX(MAX(EV_MAX, KEY_MAX), SW_MAX);
454
455static bool has_event_bit(int fd, int event_type, int bit)
456{
457 unsigned long bitmask[BITS_TO_LONGS(kMaxBit+1)];
458 memset(bitmask, 0, sizeof(bitmask));
459
460 if (ioctl(fd, EVIOCGBIT(event_type, sizeof(bitmask)), bitmask) < 0)
461 return false;
462
463 return BITMASK_GET_BIT(bitmask, bit);
464}
465
466static int get_switch_bit(int fd, int bit) {
467 unsigned long bitmask[BITS_TO_LONGS(SW_MAX+1)];
468 memset(bitmask, 0, sizeof(bitmask));
469 if (ioctl(fd, EVIOCGSW(sizeof(bitmask)), bitmask) < 0)
470 return -1;
471
472 return BITMASK_GET_BIT(bitmask, bit);
473}
474
475static bool is_lid_switch(int fd)
476{
477 return has_event_bit(fd, 0, EV_SW) && has_event_bit(fd, EV_SW, SW_LID);
478}
479
480int input_check_lid_state(void)
481{
482 unsigned int u;
483
484 for (u = 0; u < input.ndevs; u++) {
485 if (is_lid_switch(input.devs[u].fd)) {
486 return get_switch_bit(input.devs[u].fd, SW_LID);
487 }
488 }
489 return -ENODEV;
490}
491