blob: d67db88af78e6c3eaf92c66ecb6351b52a7571a3 [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
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)) &&
166 ev->value && (ev->code >= KEY_F1) && (ev->code <= KEY_F10)) {
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));
David Sodmanafba0d92015-01-27 19:07:46 -0800178 break;
179 case KEY_F8:
180 case KEY_F9:
181 case KEY_F10:
182 break;
183 }
184 return 1;
David Sodmane0cc8312014-11-18 11:16:36 -0800185 }
186 }
187
Dominik Behr46c567f2016-03-08 15:11:48 -0800188 if (command_flags.enable_vts &&
Dominik Behr92a05072016-03-23 20:04:43 -0700189 is_alt_pressed(&input.kbd_state) &&
190 is_control_pressed(&input.kbd_state) &&
191 ev->value) {
David Sodman1d1c67f2015-03-12 11:01:08 -0700192 /*
193 * Special case for key sequence that is used by external program. Just
194 * explicitly ignore here and do nothing.
195 */
Dominik Behr92a05072016-03-23 20:04:43 -0700196 if (is_shift_pressed(&input.kbd_state))
David Sodman1d1c67f2015-03-12 11:01:08 -0700197 return 1;
198
Dominik Behrda6df412016-08-02 12:56:42 -0700199 if ((ev->code >= KEY_F1) && (ev->code < KEY_F1 + term_num_terminals)) {
200 term_switch_to(ev->code - KEY_F1);
David Sodmanbf3f2842014-11-12 08:26:58 -0800201 }
202
203 return 1;
David Sodmanbf3f2842014-11-12 08:26:58 -0800204 }
205
206 return 0;
207}
208
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800209static void input_get_keysym_and_unicode(struct input_key_event* event,
210 uint32_t* keysym, uint32_t* unicode)
David Sodmanbf3f2842014-11-12 08:26:58 -0800211{
212 struct {
213 uint32_t code;
214 uint32_t keysym;
Dominik Behr58bb8e12015-09-22 14:30:41 -0700215 } search_keys[] = {
216 { KEY_F1, KEYSYM_F1},
217 { KEY_F2, KEYSYM_F2},
218 { KEY_F3, KEYSYM_F3},
219 { KEY_F4, KEYSYM_F4},
220 { KEY_F5, KEYSYM_F5},
221 { KEY_F6, KEYSYM_F6},
222 { KEY_F7, KEYSYM_F7},
223 { KEY_F8, KEYSYM_F8},
224 { KEY_F9, KEYSYM_F8},
225 { KEY_F10, KEYSYM_F10},
226 { KEY_UP, KEYSYM_PAGEUP},
227 { KEY_DOWN, KEYSYM_PAGEDOWN},
228 { KEY_LEFT, KEYSYM_HOME},
229 { KEY_RIGHT, KEYSYM_END},
230 };
231
232 struct {
233 uint32_t code;
234 uint32_t keysym;
David Sodmanbf3f2842014-11-12 08:26:58 -0800235 } non_ascii_keys[] = {
236 { KEY_ESC, KEYSYM_ESC},
237 { KEY_HOME, KEYSYM_HOME},
238 { KEY_LEFT, KEYSYM_LEFT},
239 { KEY_UP, KEYSYM_UP},
240 { KEY_RIGHT, KEYSYM_RIGHT},
241 { KEY_DOWN, KEYSYM_DOWN},
242 { KEY_PAGEUP, KEYSYM_PAGEUP},
243 { KEY_PAGEDOWN, KEYSYM_PAGEDOWN},
244 { KEY_END, KEYSYM_END},
245 { KEY_INSERT, KEYSYM_INSERT},
246 { KEY_DELETE, KEYSYM_DELETE},
247 };
248
Dominik Behr58bb8e12015-09-22 14:30:41 -0700249 if (input.kbd_state.search_state) {
250 for (unsigned i = 0; i < ARRAY_SIZE(search_keys); i++) {
251 if (search_keys[i].code == event->code) {
252 *keysym = search_keys[i].keysym;
253 *unicode = -1;
254 return;
255 }
256 }
257 }
258
David Sodmanbf3f2842014-11-12 08:26:58 -0800259 for (unsigned i = 0; i < ARRAY_SIZE(non_ascii_keys); i++) {
260 if (non_ascii_keys[i].code == event->code) {
261 *keysym = non_ascii_keys[i].keysym;
262 *unicode = -1;
263 return;
264 }
265 }
266
267 if (event->code >= ARRAY_SIZE(keysym_table) / 2) {
268 *keysym = '?';
269 } else {
Dominik Behr92a05072016-03-23 20:04:43 -0700270 *keysym = keysym_table[event->code * 2 + is_shift_pressed(&input.kbd_state)];
271 if (is_control_pressed(&input.kbd_state) && isascii(*keysym))
David Sodmanbf3f2842014-11-12 08:26:58 -0800272 *keysym = tolower(*keysym) - 'a' + 1;
273 }
274
275 *unicode = *keysym;
276}
277
Dominik Behr5239cca2016-01-21 18:22:04 -0800278int input_add(const char* devname)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700279{
Dominik Behr93899452014-08-18 22:16:21 -0700280 int ret = 0, fd = -1;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800281
Dominik Behr93899452014-08-18 22:16:21 -0700282 /* for some reason every device has a null enumerations and notifications
283 of every device come with NULL string first */
284 if (!devname) {
285 ret = -EINVAL;
286 goto errorret;
287 }
Haixia Shid288e032015-09-14 18:33:11 -0700288 /* check for duplicates */
Stéphane Marchesinac14d292015-12-14 15:27:18 -0800289 for (unsigned int i = 0; i < input.ndevs; ++i) {
Haixia Shid288e032015-09-14 18:33:11 -0700290 if (strcmp(devname, input.devs[i].path) == 0) {
Stéphane Marchesinc02260b2016-01-07 22:46:45 -0800291 LOG(INFO, "Skipping duplicate input device %s", devname);
Haixia Shid288e032015-09-14 18:33:11 -0700292 ret = -EINVAL;
293 goto errorret;
294 }
295 }
Dominik Behr93899452014-08-18 22:16:21 -0700296 ret = fd = open(devname, O_RDONLY);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700297 if (fd < 0)
Dominik Behr93899452014-08-18 22:16:21 -0700298 goto errorret;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700299
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800300 ret = ioctl(fd, EVIOCGRAB, (void*) 1);
David Sodmaneef3fd22015-08-20 15:08:52 -0700301 if (!ret) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800302 ret = ioctl(fd, EVIOCGRAB, (void*) 0);
David Sodmaneef3fd22015-08-20 15:08:52 -0700303 if (ret)
304 LOG(ERROR,
305 "EVIOCGRAB succeeded but the corresponding ungrab failed: %m");
306 } else {
307 LOG(ERROR, "Evdev device %s grabbed by another process",
308 devname);
309 ret = -EBUSY;
310 goto closefd;
311 }
312
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800313 struct input_dev* newdevs =
Dominik Behr93899452014-08-18 22:16:21 -0700314 realloc(input.devs, (input.ndevs + 1) * sizeof (struct input_dev));
315 if (!newdevs) {
316 ret = -ENOMEM;
317 goto closefd;
318 }
319 input.devs = newdevs;
320 input.devs[input.ndevs].fd = fd;
321 input.devs[input.ndevs].path = strdup(devname);
322 if (!input.devs[input.ndevs].path) {
323 ret = -ENOMEM;
324 goto closefd;
325 }
326 input.ndevs++;
327
328 return fd;
329
330closefd:
331 close(fd);
332errorret:
333 return ret;
334}
335
Dominik Behr5239cca2016-01-21 18:22:04 -0800336void input_remove(const char* devname)
Dominik Behr93899452014-08-18 22:16:21 -0700337{
Dominik Behr93899452014-08-18 22:16:21 -0700338 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800339
340 if (!devname)
341 return;
342
Dominik Behr93899452014-08-18 22:16:21 -0700343 for (u = 0; u < input.ndevs; u++) {
344 if (!strcmp(devname, input.devs[u].path)) {
345 free(input.devs[u].path);
346 close(input.devs[u].fd);
347 input.ndevs--;
348 if (u != input.ndevs) {
349 input.devs[u] = input.devs[input.ndevs];
350 }
351 return;
352 }
353 }
354}
355
Dominik Behr93899452014-08-18 22:16:21 -0700356int input_init()
357{
Dominik Behr93899452014-08-18 22:16:21 -0700358 if (!isatty(fileno(stdout)))
359 setbuf(stdout, NULL);
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700360 return 0;
361}
362
363void input_close()
364{
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 free(input.devs[u].path);
369 close(input.devs[u].fd);
370 }
371 free(input.devs);
372 input.devs = NULL;
373 input.ndevs = 0;
David Sodmanbbcb0522014-09-19 10:34:07 -0700374}
375
Dominik Behrd7112672016-01-20 16:59:34 -0800376void input_add_fds(fd_set* read_set, fd_set* exception_set, int *maxfd)
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700377{
Dominik Behr93899452014-08-18 22:16:21 -0700378 unsigned int u;
Stéphane Marchesinedece332015-12-14 15:10:58 -0800379
Dominik Behr93899452014-08-18 22:16:21 -0700380 for (u = 0; u < input.ndevs; u++) {
381 FD_SET(input.devs[u].fd, read_set);
382 FD_SET(input.devs[u].fd, exception_set);
Dominik Behrd7112672016-01-20 16:59:34 -0800383 if (input.devs[u].fd > *maxfd)
384 *maxfd = input.devs[u].fd;
Dominik Behr93899452014-08-18 22:16:21 -0700385 }
Dominik Behr93899452014-08-18 22:16:21 -0700386}
387
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800388struct input_key_event* input_get_event(fd_set* read_set,
389 fd_set* exception_set)
Dominik Behr93899452014-08-18 22:16:21 -0700390{
391 unsigned int u;
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700392 struct input_event ev;
393 int ret;
394
Dominik Behr93899452014-08-18 22:16:21 -0700395 for (u = 0; u < input.ndevs; u++) {
396 if (FD_ISSET(input.devs[u].fd, read_set)
397 && !FD_ISSET(input.devs[u].fd, exception_set)) {
398 ret =
399 read(input.devs[u].fd, &ev, sizeof (struct input_event));
Michael Spang24d20122015-04-22 13:58:16 -0400400 if (ret < 0) {
401 if (errno == EINTR || errno == EAGAIN)
402 continue;
403 if (errno != ENODEV) {
404 LOG(ERROR, "read: %s: %s", input.devs[u].path,
405 strerror(errno));
406 }
407 input_remove(input.devs[u].path);
408 return NULL;
409 } else if (ret < (int) sizeof (struct input_event)) {
David Sodmanbbcb0522014-09-19 10:34:07 -0700410 LOG(ERROR, "expected %d bytes, got %d",
Dominik Behr93899452014-08-18 22:16:21 -0700411 (int) sizeof (struct input_event), ret);
412 return NULL;
413 }
414
415 if (ev.type == EV_KEY) {
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800416 struct input_key_event* event =
Dominik Behr93899452014-08-18 22:16:21 -0700417 malloc(sizeof (*event));
418 event->code = ev.code;
419 event->value = ev.value;
Dominik Behr93899452014-08-18 22:16:21 -0700420 return event;
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800421 } else if (ev.type == EV_SW && ev.code == SW_LID) {
422 /* TODO(dbehr), abstract this in input_key_event if we ever parse more than one */
423 term_monitor_hotplug();
Dominik Behr93899452014-08-18 22:16:21 -0700424 }
425 }
Stéphane Marchesinae37e6c2014-08-08 18:19:40 -0700426 }
427
428 return NULL;
429}
430
Dominik Behr4defb362016-01-13 12:36:14 -0800431void input_put_event(struct input_key_event* event)
432{
433 free(event);
434}
435
Dominik Behr44e07e62016-01-13 19:43:57 -0800436void input_dispatch_io(fd_set* read_set, fd_set* exception_set)
David Sodmanf0a925a2015-05-04 11:19:19 -0700437{
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800438 terminal_t* terminal;
Stéphane Marchesin00ff1872015-12-14 13:40:09 -0800439 struct input_key_event* event;
Dominik Behr44e07e62016-01-13 19:43:57 -0800440
441 event = input_get_event(read_set, exception_set);
David Sodmanf0a925a2015-05-04 11:19:19 -0700442 if (event) {
443 if (!input_special_key(event) && event->value) {
444 uint32_t keysym, unicode;
445 // current_terminal can possibly change during
446 // execution of input_special_key
Dominik Behr4defb362016-01-13 12:36:14 -0800447 terminal = term_get_current_terminal();
David Sodmanf0a925a2015-05-04 11:19:19 -0700448 if (term_is_active(terminal)) {
449 // Only report user activity when the terminal is active
Dominik Behr797a3832016-01-11 15:53:11 -0800450 dbus_report_user_activity(USER_ACTIVITY_OTHER);
David Sodmanf0a925a2015-05-04 11:19:19 -0700451 input_get_keysym_and_unicode(
452 event, &keysym, &unicode);
453 term_key_event(terminal,
454 keysym, unicode);
455 }
456 }
457 input_put_event(event);
458 }
David Sodmanbf3f2842014-11-12 08:26:58 -0800459}
Dominik Behrd2cc4d22016-01-29 17:31:52 -0800460
461#define BITS_PER_LONG (sizeof(long) * 8)
462#define BITS_TO_LONGS(bits) (((bits) - 1) / BITS_PER_LONG + 1)
463#define BITMASK_GET_BIT(bitmask, bit) \
464 ((bitmask[bit / BITS_PER_LONG] >> (bit % BITS_PER_LONG)) & 1)
465
466static const int kMaxBit = MAX(MAX(EV_MAX, KEY_MAX), SW_MAX);
467
468static bool has_event_bit(int fd, int event_type, int bit)
469{
470 unsigned long bitmask[BITS_TO_LONGS(kMaxBit+1)];
471 memset(bitmask, 0, sizeof(bitmask));
472
473 if (ioctl(fd, EVIOCGBIT(event_type, sizeof(bitmask)), bitmask) < 0)
474 return false;
475
476 return BITMASK_GET_BIT(bitmask, bit);
477}
478
479static int get_switch_bit(int fd, int bit) {
480 unsigned long bitmask[BITS_TO_LONGS(SW_MAX+1)];
481 memset(bitmask, 0, sizeof(bitmask));
482 if (ioctl(fd, EVIOCGSW(sizeof(bitmask)), bitmask) < 0)
483 return -1;
484
485 return BITMASK_GET_BIT(bitmask, bit);
486}
487
488static bool is_lid_switch(int fd)
489{
490 return has_event_bit(fd, 0, EV_SW) && has_event_bit(fd, EV_SW, SW_LID);
491}
492
493int input_check_lid_state(void)
494{
495 unsigned int u;
496
497 for (u = 0; u < input.ndevs; u++) {
498 if (is_lid_switch(input.devs[u].fd)) {
499 return get_switch_bit(input.devs[u].fd, SW_LID);
500 }
501 }
502 return -ENODEV;
503}
504