blob: cee4d73d6b3356fc33437fc92e0ffa7a3a371a70 [file] [log] [blame]
Elliott Hughes07138192015-04-10 09:40:53 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <dirent.h>
Dan Albertc8686b42017-10-11 11:47:54 -070018#include <errno.h>
Elliott Hughes07138192015-04-10 09:40:53 -070019#include <fcntl.h>
Tao Bao0b1118d2017-01-14 07:46:10 -080020#include <linux/input.h>
Elliott Hughes07138192015-04-10 09:40:53 -070021#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/epoll.h>
Xihua Chena7952ac2018-01-12 13:42:18 +080025#include <sys/inotify.h>
Tao Bao0b1118d2017-01-14 07:46:10 -080026#include <sys/ioctl.h>
Tao Bao835bf092019-03-11 14:13:21 -070027#include <sys/types.h>
Elliott Hughes07138192015-04-10 09:40:53 -070028#include <unistd.h>
29
Tao Bao9468fc02017-03-17 00:57:37 -070030#include <functional>
Tao Bao835bf092019-03-11 14:13:21 -070031#include <memory>
32
33#include <android-base/unique_fd.h>
Elliott Hughes07138192015-04-10 09:40:53 -070034
Tao Bao0ecbd762017-01-16 21:16:58 -080035#include "minui/minui.h"
Elliott Hughes07138192015-04-10 09:40:53 -070036
Xihua Chena7952ac2018-01-12 13:42:18 +080037constexpr const char* INPUT_DEV_DIR = "/dev/input";
38
Tao Bao835bf092019-03-11 14:13:21 -070039constexpr size_t MAX_DEVICES = 16;
40constexpr size_t MAX_MISC_FDS = 16;
Elliott Hughes07138192015-04-10 09:40:53 -070041
Tao Bao835bf092019-03-11 14:13:21 -070042constexpr size_t BITS_PER_LONG = sizeof(unsigned long) * 8;
43constexpr size_t BITS_TO_LONGS(size_t bits) {
44 return ((bits + BITS_PER_LONG - 1) / BITS_PER_LONG);
45}
Elliott Hughes07138192015-04-10 09:40:53 -070046
Tao Bao835bf092019-03-11 14:13:21 -070047struct FdInfo {
48 android::base::unique_fd fd;
Tao Bao0b1118d2017-01-14 07:46:10 -080049 ev_callback cb;
Ethan Yonker8373cfe2017-09-08 06:50:54 -050050#ifdef TW_USE_MINUI_WITH_DATA
51 void* data;
52#endif
Elliott Hughes07138192015-04-10 09:40:53 -070053};
54
Xihua Chena7952ac2018-01-12 13:42:18 +080055static bool g_allow_touch_inputs = true;
56static ev_callback g_saved_input_cb;
Tao Bao835bf092019-03-11 14:13:21 -070057static android::base::unique_fd g_epoll_fd;
58static epoll_event g_polled_events[MAX_DEVICES + MAX_MISC_FDS];
59static int g_polled_events_count;
Elliott Hughes07138192015-04-10 09:40:53 -070060
Tao Bao835bf092019-03-11 14:13:21 -070061static FdInfo ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
Elliott Hughes07138192015-04-10 09:40:53 -070062
Tao Bao835bf092019-03-11 14:13:21 -070063static size_t g_ev_count = 0;
64static size_t g_ev_dev_count = 0;
65static size_t g_ev_misc_count = 0;
Elliott Hughes07138192015-04-10 09:40:53 -070066
Chih-Hung Hsieh54a27472016-04-18 11:30:55 -070067static bool test_bit(size_t bit, unsigned long* array) { // NOLINT
Tao Bao835bf092019-03-11 14:13:21 -070068 return (array[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
Elliott Hughes07138192015-04-10 09:40:53 -070069}
70
Ethan Yonkerecbd3e82017-12-14 14:43:59 -060071#ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
Xihua Chena7952ac2018-01-12 13:42:18 +080072static bool should_add_input_device(int fd, bool allow_touch_inputs) {
73 // Use unsigned long to match ioctl's parameter type.
74 unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
75
76 // Read the evbits of the input device.
77 if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
78 return false;
79 }
80
81 // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also
82 // allowed if allow_touch_inputs is set.
83 if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
84 if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) {
85 return false;
86 }
87 }
88
89 return true;
90}
91
92static int inotify_cb(int fd, __unused uint32_t epevents) {
93 if (g_saved_input_cb == nullptr) return -1;
94
95 // The inotify will put one or several complete events.
96 // Should not read part of one event.
Stephane Lee12952cd2020-01-13 15:46:36 -080097 int event_len_int;
98 int ret = ioctl(fd, FIONREAD, &event_len_int);
Xihua Chena7952ac2018-01-12 13:42:18 +080099 if (ret != 0) return -1;
Stephane Lee12952cd2020-01-13 15:46:36 -0800100 if (event_len_int < 0) return -1;
101 size_t event_len = event_len_int;
Xihua Chena7952ac2018-01-12 13:42:18 +0800102
103 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir);
104 if (!dir) {
105 return -1;
106 }
107
108 std::vector<int8_t> buf(event_len);
109
110 ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf.data(), event_len));
111 if (r != event_len) {
112 return -1;
113 }
114
115 size_t offset = 0;
116 while (offset < event_len) {
117 struct inotify_event* pevent = reinterpret_cast<struct inotify_event*>(buf.data() + offset);
118 if (offset + sizeof(inotify_event) + pevent->len > event_len) {
119 // The pevent->len is too large and buffer will over flow.
120 // In general, should not happen, just make more stable.
121 return -1;
122 }
123 offset += sizeof(inotify_event) + pevent->len;
124
125 pevent->name[pevent->len] = '\0';
126 if (strncmp(pevent->name, "event", 5)) {
127 continue;
128 }
129
130 android::base::unique_fd dfd(openat(dirfd(dir.get()), pevent->name, O_RDONLY));
131 if (dfd == -1) {
132 break;
133 }
134
135 if (!should_add_input_device(dfd, g_allow_touch_inputs)) {
136 continue;
137 }
138
139 // Only add, we assume the user will not plug out and plug in USB device again and again :)
140 ev_add_fd(std::move(dfd), g_saved_input_cb);
141 }
142
143 return 0;
144}
145
Tao Baoaf9f8b42017-07-28 00:05:40 -0700146int ev_init(ev_callback input_cb, bool allow_touch_inputs) {
bigbiff20edca82020-07-03 09:55:28 -0400147#else
148#ifdef TW_USE_MINUI_WITH_DATA
149int ev_init(ev_callback input_cb, void* data) {
150#else
151int ev_init(ev_callback input_cb) {
152#endif
153 bool allow_touch_inputs = false;
154#endif
Tao Bao835bf092019-03-11 14:13:21 -0700155 g_epoll_fd.reset();
156
157 android::base::unique_fd epoll_fd(epoll_create1(EPOLL_CLOEXEC));
158 if (epoll_fd == -1) {
Tao Bao0b1118d2017-01-14 07:46:10 -0800159 return -1;
160 }
161
Xihua Chena7952ac2018-01-12 13:42:18 +0800162 android::base::unique_fd inotify_fd(inotify_init1(IN_CLOEXEC));
163 if (inotify_fd.get() == -1) {
164 return -1;
165 }
166
167 if (inotify_add_watch(inotify_fd, INPUT_DEV_DIR, IN_CREATE) < 0) {
168 return -1;
169 }
170
171 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir);
Tao Bao835bf092019-03-11 14:13:21 -0700172 if (!dir) {
173 return -1;
174 }
Tao Bao0b1118d2017-01-14 07:46:10 -0800175
Tao Bao835bf092019-03-11 14:13:21 -0700176 bool epoll_ctl_failed = false;
177 dirent* de;
178 while ((de = readdir(dir.get())) != nullptr) {
179 if (strncmp(de->d_name, "event", 5)) continue;
180 android::base::unique_fd fd(openat(dirfd(dir.get()), de->d_name, O_RDONLY | O_CLOEXEC));
181 if (fd == -1) continue;
Tao Baoaf9f8b42017-07-28 00:05:40 -0700182
bigbiff673c7ae2020-12-02 19:44:56 -0500183#ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
Xihua Chena7952ac2018-01-12 13:42:18 +0800184 if (!should_add_input_device(fd, allow_touch_inputs)) {
Tao Bao835bf092019-03-11 14:13:21 -0700185 continue;
Elliott Hughes07138192015-04-10 09:40:53 -0700186 }
bigbiff673c7ae2020-12-02 19:44:56 -0500187#endif
Elliott Hughes07138192015-04-10 09:40:53 -0700188
Tao Bao835bf092019-03-11 14:13:21 -0700189 epoll_event ev;
190 ev.events = EPOLLIN | EPOLLWAKEUP;
191 ev.data.ptr = &ev_fdinfo[g_ev_count];
192 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
193 epoll_ctl_failed = true;
194 continue;
Elliott Hughes07138192015-04-10 09:40:53 -0700195 }
196
Tao Bao835bf092019-03-11 14:13:21 -0700197 ev_fdinfo[g_ev_count].fd.reset(fd.release());
198 ev_fdinfo[g_ev_count].cb = input_cb;
199 g_ev_count++;
200 g_ev_dev_count++;
201 if (g_ev_dev_count == MAX_DEVICES) break;
Tao Bao0b1118d2017-01-14 07:46:10 -0800202 }
Elliott Hughes07138192015-04-10 09:40:53 -0700203
Tao Bao835bf092019-03-11 14:13:21 -0700204 if (epoll_ctl_failed && !g_ev_count) {
Tao Bao0b1118d2017-01-14 07:46:10 -0800205 return -1;
206 }
Elliott Hughes07138192015-04-10 09:40:53 -0700207
Tao Bao835bf092019-03-11 14:13:21 -0700208 g_epoll_fd.reset(epoll_fd.release());
Xihua Chena7952ac2018-01-12 13:42:18 +0800209
210 g_saved_input_cb = input_cb;
211 g_allow_touch_inputs = allow_touch_inputs;
bigbiff673c7ae2020-12-02 19:44:56 -0500212#ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
Xihua Chena7952ac2018-01-12 13:42:18 +0800213 ev_add_fd(std::move(inotify_fd), inotify_cb);
bigbiff673c7ae2020-12-02 19:44:56 -0500214#endif
Xihua Chena7952ac2018-01-12 13:42:18 +0800215
Tao Bao0b1118d2017-01-14 07:46:10 -0800216 return 0;
Elliott Hughes07138192015-04-10 09:40:53 -0700217}
218
219int ev_get_epollfd(void) {
Tao Bao835bf092019-03-11 14:13:21 -0700220 return g_epoll_fd.get();
Elliott Hughes07138192015-04-10 09:40:53 -0700221}
222
Tao Bao835bf092019-03-11 14:13:21 -0700223int ev_add_fd(android::base::unique_fd&& fd, ev_callback cb) {
224 if (g_ev_misc_count == MAX_MISC_FDS || cb == nullptr) {
Tao Bao0b1118d2017-01-14 07:46:10 -0800225 return -1;
226 }
Elliott Hughes07138192015-04-10 09:40:53 -0700227
Tao Bao0b1118d2017-01-14 07:46:10 -0800228 epoll_event ev;
229 ev.events = EPOLLIN | EPOLLWAKEUP;
Tao Bao835bf092019-03-11 14:13:21 -0700230 ev.data.ptr = static_cast<void*>(&ev_fdinfo[g_ev_count]);
Tao Bao0b1118d2017-01-14 07:46:10 -0800231 int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
232 if (!ret) {
Tao Bao835bf092019-03-11 14:13:21 -0700233 ev_fdinfo[g_ev_count].fd.reset(fd.release());
234 ev_fdinfo[g_ev_count].cb = std::move(cb);
235 g_ev_count++;
236 g_ev_misc_count++;
Tao Bao0b1118d2017-01-14 07:46:10 -0800237 }
Elliott Hughes07138192015-04-10 09:40:53 -0700238
Tao Bao0b1118d2017-01-14 07:46:10 -0800239 return ret;
Elliott Hughes07138192015-04-10 09:40:53 -0700240}
241
242void ev_exit(void) {
Tao Bao835bf092019-03-11 14:13:21 -0700243 while (g_ev_count > 0) {
244 ev_fdinfo[--g_ev_count].fd.reset();
245 }
246 g_ev_misc_count = 0;
247 g_ev_dev_count = 0;
Xihua Chena7952ac2018-01-12 13:42:18 +0800248 g_saved_input_cb = nullptr;
Tao Bao835bf092019-03-11 14:13:21 -0700249 g_epoll_fd.reset();
Elliott Hughes07138192015-04-10 09:40:53 -0700250}
251
252int ev_wait(int timeout) {
Tao Bao835bf092019-03-11 14:13:21 -0700253 g_polled_events_count = epoll_wait(g_epoll_fd, g_polled_events, g_ev_count, timeout);
254 if (g_polled_events_count <= 0) {
255 return -1;
256 }
257 return 0;
Elliott Hughes07138192015-04-10 09:40:53 -0700258}
259
260void ev_dispatch(void) {
Tao Bao835bf092019-03-11 14:13:21 -0700261 for (int n = 0; n < g_polled_events_count; n++) {
262 FdInfo* fdi = static_cast<FdInfo*>(g_polled_events[n].data.ptr);
Tao Bao0b1118d2017-01-14 07:46:10 -0800263 const ev_callback& cb = fdi->cb;
264 if (cb) {
Tao Bao835bf092019-03-11 14:13:21 -0700265 cb(fdi->fd, g_polled_events[n].events);
Elliott Hughes07138192015-04-10 09:40:53 -0700266 }
Tao Bao0b1118d2017-01-14 07:46:10 -0800267 }
Elliott Hughes07138192015-04-10 09:40:53 -0700268}
269
Elliott Hughes07cfb8f2015-04-10 13:12:05 -0700270int ev_get_input(int fd, uint32_t epevents, input_event* ev) {
Xihua Chena7952ac2018-01-12 13:42:18 +0800271 if (epevents & EPOLLIN) {
272 ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev)));
273 if (r == sizeof(*ev)) {
274 return 0;
Elliott Hughes07138192015-04-10 09:40:53 -0700275 }
Xihua Chena7952ac2018-01-12 13:42:18 +0800276 }
277 if (epevents & EPOLLHUP) {
278 // Delete this watch
279 epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
280 }
281 return -1;
Elliott Hughes07138192015-04-10 09:40:53 -0700282}
283
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500284#ifdef TW_USE_MINUI_WITH_DATA
Elliott Hughes07138192015-04-10 09:40:53 -0700285int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500286#else
Tao Bao0b1118d2017-01-14 07:46:10 -0800287int ev_sync_key_state(const ev_set_key_callback& set_key_cb) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500288#endif
Tao Bao0b1118d2017-01-14 07:46:10 -0800289 // Use unsigned long to match ioctl's parameter type.
290 unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
291 unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT
Elliott Hughes07138192015-04-10 09:40:53 -0700292
Tao Bao835bf092019-03-11 14:13:21 -0700293 for (size_t i = 0; i < g_ev_dev_count; ++i) {
Tao Bao0b1118d2017-01-14 07:46:10 -0800294 memset(ev_bits, 0, sizeof(ev_bits));
295 memset(key_bits, 0, sizeof(key_bits));
Elliott Hughes07138192015-04-10 09:40:53 -0700296
Tao Bao0b1118d2017-01-14 07:46:10 -0800297 if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
298 continue;
299 }
300 if (!test_bit(EV_KEY, ev_bits)) {
301 continue;
302 }
303 if (ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits) == -1) {
304 continue;
Elliott Hughes07138192015-04-10 09:40:53 -0700305 }
306
Tao Bao0b1118d2017-01-14 07:46:10 -0800307 for (int code = 0; code <= KEY_MAX; code++) {
308 if (test_bit(code, key_bits)) {
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500309#ifdef TW_USE_MINUI_WITH_DATA
310 set_key_cb(code, 1, data);
311#else
Tao Bao0b1118d2017-01-14 07:46:10 -0800312 set_key_cb(code, 1);
Ethan Yonker8373cfe2017-09-08 06:50:54 -0500313#endif
Tao Bao0b1118d2017-01-14 07:46:10 -0800314 }
315 }
316 }
317
318 return 0;
Elliott Hughes07138192015-04-10 09:40:53 -0700319}
320
Chih-Hung Hsieh23abfd32016-07-27 10:19:47 -0700321void ev_iterate_available_keys(const std::function<void(int)>& f) {
Tao Bao835bf092019-03-11 14:13:21 -0700322 // Use unsigned long to match ioctl's parameter type.
323 unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT
324 unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)]; // NOLINT
Elliott Hughes07138192015-04-10 09:40:53 -0700325
Tao Bao835bf092019-03-11 14:13:21 -0700326 for (size_t i = 0; i < g_ev_dev_count; ++i) {
327 memset(ev_bits, 0, sizeof(ev_bits));
328 memset(key_bits, 0, sizeof(key_bits));
Elliott Hughes07138192015-04-10 09:40:53 -0700329
Tao Bao835bf092019-03-11 14:13:21 -0700330 // Does this device even have keys?
331 if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
332 continue;
Elliott Hughes07138192015-04-10 09:40:53 -0700333 }
Tao Bao835bf092019-03-11 14:13:21 -0700334 if (!test_bit(EV_KEY, ev_bits)) {
335 continue;
336 }
337
338 if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits) == -1) {
339 continue;
340 }
341
342 for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
343 if (test_bit(key_code, key_bits)) {
344 f(key_code);
345 }
346 }
347 }
Elliott Hughes07138192015-04-10 09:40:53 -0700348}
Tao Baoaf9f8b42017-07-28 00:05:40 -0700349
Ethan Yonkerecbd3e82017-12-14 14:43:59 -0600350#ifdef TW_USE_MINUI_WITH_OPTIONAL_TOUCH_EVENTS
Tao Baoaf9f8b42017-07-28 00:05:40 -0700351void ev_iterate_touch_inputs(const std::function<void(int)>& action) {
Tao Bao835bf092019-03-11 14:13:21 -0700352 for (size_t i = 0; i < g_ev_dev_count; ++i) {
Tao Baoaf9f8b42017-07-28 00:05:40 -0700353 // Use unsigned long to match ioctl's parameter type.
354 unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)] = {}; // NOLINT
355 if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
356 continue;
357 }
358 if (!test_bit(EV_ABS, ev_bits)) {
359 continue;
360 }
361
362 unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)] = {}; // NOLINT
363 if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_ABS, KEY_MAX), key_bits) == -1) {
364 continue;
365 }
366
367 for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
368 if (test_bit(key_code, key_bits)) {
369 action(key_code);
370 }
371 }
372 }
373}
Ethan Yonkerecbd3e82017-12-14 14:43:59 -0600374#endif