blob: 1a8f2aea3252ab12514dff94e0f595be4c54e1ab [file] [log] [blame]
Colin Crossa8666952010-04-13 19:20:44 -07001/*
2 * Copyright (C) 2010 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
Tom Cherry81f5d3e2017-06-22 12:53:17 -070017#include "keychords.h"
18
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070019#include <dirent.h>
Colin Crossa8666952010-04-13 19:20:44 -070020#include <fcntl.h>
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070021#include <linux/input.h>
22#include <sys/cdefs.h>
Mark Salyzyn44692de2018-05-02 11:22:15 -070023#include <sys/inotify.h>
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070024#include <sys/ioctl.h>
Colin Crossa8666952010-04-13 19:20:44 -070025#include <sys/types.h>
Olivier Baillyb93e5812010-11-17 11:47:23 -080026#include <unistd.h>
Colin Crossa8666952010-04-13 19:20:44 -070027
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070028#include <algorithm>
29#include <functional>
Mark Salyzyn44692de2018-05-02 11:22:15 -070030#include <map>
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070031#include <memory>
32#include <string>
33#include <vector>
34
Tom Cherry3f5eaae52017-04-06 16:30:22 -070035#include <android-base/logging.h>
Tom Cherry81f5d3e2017-06-22 12:53:17 -070036
37namespace android {
38namespace init {
Colin Crossa8666952010-04-13 19:20:44 -070039
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070040namespace {
Colin Crossa8666952010-04-13 19:20:44 -070041
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070042int keychords_count;
Mark Salyzyn6c6ec722015-10-24 16:20:18 -070043Epoll* epoll;
Mark Salyzyneca25072018-05-16 15:10:24 -070044std::function<void(int)> handle_keychord;
Colin Crossa8666952010-04-13 19:20:44 -070045
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070046struct KeychordEntry {
47 const std::vector<int> keycodes;
48 bool notified;
49 int id;
50
51 KeychordEntry(const std::vector<int>& keycodes, int id)
52 : keycodes(keycodes), notified(false), id(id) {}
53};
54
55std::vector<KeychordEntry> keychord_entries;
56
57// Bit management
58class KeychordMask {
59 private:
60 typedef unsigned int mask_t;
61 std::vector<mask_t> bits;
62 static constexpr size_t bits_per_byte = 8;
63
64 public:
65 explicit KeychordMask(size_t bit = 0) : bits((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
66
67 void SetBit(size_t bit, bool value = true) {
68 auto idx = bit / (bits_per_byte * sizeof(mask_t));
69 if (idx >= bits.size()) return;
70 if (value) {
71 bits[idx] |= mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t)));
72 } else {
73 bits[idx] &= ~(mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
Colin Crossa8666952010-04-13 19:20:44 -070074 }
Colin Crossf7ca6042011-01-04 18:18:45 -080075 }
76
Mark Salyzyn353bf1f2018-04-30 07:33:31 -070077 bool GetBit(size_t bit) const {
78 auto idx = bit / (bits_per_byte * sizeof(mask_t));
79 return bits[idx] & (mask_t(1) << (bit % (bits_per_byte * sizeof(mask_t))));
80 }
81
82 size_t bytesize() const { return bits.size() * sizeof(mask_t); }
83 void* data() { return bits.data(); }
84 size_t size() const { return bits.size() * sizeof(mask_t) * bits_per_byte; }
85 void resize(size_t bit) {
86 auto idx = bit / (bits_per_byte * sizeof(mask_t));
87 if (idx >= bits.size()) {
88 bits.resize(idx + 1, 0);
89 }
90 }
91
92 operator bool() const {
93 for (size_t i = 0; i < bits.size(); ++i) {
94 if (bits[i]) return true;
95 }
96 return false;
97 }
98
99 KeychordMask operator&(const KeychordMask& rval) const {
100 auto len = std::min(bits.size(), rval.bits.size());
101 KeychordMask ret;
102 ret.bits.resize(len);
103 for (size_t i = 0; i < len; ++i) {
104 ret.bits[i] = bits[i] & rval.bits[i];
105 }
106 return ret;
107 }
108
109 void operator|=(const KeychordMask& rval) {
110 size_t len = rval.bits.size();
111 bits.resize(len);
112 for (size_t i = 0; i < len; ++i) {
113 bits[i] |= rval.bits[i];
114 }
115 }
116};
117
118KeychordMask keychord_current;
119
120constexpr char kDevicePath[] = "/dev/input";
121
Mark Salyzyn44692de2018-05-02 11:22:15 -0700122std::map<std::string, int> keychord_registration;
123
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700124void KeychordLambdaCheck() {
125 for (auto& e : keychord_entries) {
126 bool found = true;
127 for (auto& code : e.keycodes) {
128 if (!keychord_current.GetBit(code)) {
129 e.notified = false;
130 found = false;
131 break;
132 }
133 }
134 if (!found) continue;
135 if (e.notified) continue;
136 e.notified = true;
Mark Salyzyneca25072018-05-16 15:10:24 -0700137 handle_keychord(e.id);
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700138 }
139}
140
141void KeychordLambdaHandler(int fd) {
142 input_event event;
143 auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
144 if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
145 keychord_current.SetBit(event.code, event.value);
146 KeychordLambdaCheck();
147}
148
149bool KeychordGeteventEnable(int fd) {
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700150 // Make sure it is an event channel, should pass this ioctl call
151 int version;
152 if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
153
Mark Salyzyneca25072018-05-16 15:10:24 -0700154#ifdef EVIOCSMASK
155 static auto EviocsmaskSupported = true;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700156 if (EviocsmaskSupported) {
157 KeychordMask mask(EV_KEY);
158 mask.SetBit(EV_KEY);
159 input_mask msg = {};
160 msg.type = EV_SYN;
161 msg.codes_size = mask.bytesize();
162 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
163 if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
164 PLOG(WARNING) << "EVIOCSMASK not supported";
165 EviocsmaskSupported = false;
166 }
167 }
Mark Salyzyneca25072018-05-16 15:10:24 -0700168#endif
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700169
170 KeychordMask mask;
171 for (auto& e : keychord_entries) {
172 for (auto& code : e.keycodes) {
173 mask.resize(code);
174 mask.SetBit(code);
175 }
176 }
177
178 keychord_current.resize(mask.size());
179 KeychordMask available(mask.size());
180 auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
181 if (res == -1) return false;
182 if (!(available & mask)) return false;
183
Mark Salyzyneca25072018-05-16 15:10:24 -0700184#ifdef EVIOCSMASK
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700185 if (EviocsmaskSupported) {
186 input_mask msg = {};
187 msg.type = EV_KEY;
188 msg.codes_size = mask.bytesize();
189 msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
190 ::ioctl(fd, EVIOCSMASK, &msg);
191 }
Mark Salyzyneca25072018-05-16 15:10:24 -0700192#endif
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700193
194 KeychordMask set(mask.size());
195 res = ::ioctl(fd, EVIOCGKEY(res), set.data());
196 if (res > 0) {
197 keychord_current |= mask & available & set;
198 KeychordLambdaCheck();
199 }
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700200 epoll->RegisterHandler(fd, [fd]() { KeychordLambdaHandler(fd); });
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700201 return true;
202}
203
204void GeteventOpenDevice(const std::string& device) {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700205 if (keychord_registration.count(device)) return;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700206 auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDWR | O_CLOEXEC));
207 if (fd == -1) {
208 PLOG(ERROR) << "Can not open " << device;
209 return;
210 }
211 if (!KeychordGeteventEnable(fd)) {
212 ::close(fd);
Mark Salyzyn44692de2018-05-02 11:22:15 -0700213 } else {
214 keychord_registration.emplace(device, fd);
215 }
216}
217
218void GeteventCloseDevice(const std::string& device) {
219 auto it = keychord_registration.find(device);
220 if (it == keychord_registration.end()) return;
221 auto fd = (*it).second;
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700222 epoll->UnregisterHandler(fd);
Mark Salyzyn44692de2018-05-02 11:22:15 -0700223 keychord_registration.erase(it);
224 ::close(fd);
225}
226
227int inotify_fd = -1;
228
229void InotifyHandler() {
230 unsigned char buf[512];
231
232 auto res = TEMP_FAILURE_RETRY(::read(inotify_fd, buf, sizeof(buf)));
233 if (res < 0) {
234 PLOG(WARNING) << "could not get event";
235 return;
236 }
237
238 auto event_buf = buf;
239 while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
240 auto event = reinterpret_cast<inotify_event*>(event_buf);
241 auto event_size = sizeof(inotify_event) + event->len;
242 if (static_cast<size_t>(res) < event_size) break;
243 if (event->len) {
244 std::string devname(kDevicePath);
245 devname += '/';
246 devname += event->name;
247 if (event->mask & IN_CREATE) {
248 GeteventOpenDevice(devname);
249 } else {
250 GeteventCloseDevice(devname);
251 }
252 }
253 res -= event_size;
254 event_buf += event_size;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700255 }
256}
257
258void GeteventOpenDevice() {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700259 inotify_fd = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
260 if (inotify_fd < 0) {
261 PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
Mark Salyzynf1877152018-05-11 08:25:28 -0700262 } else if (::inotify_add_watch(inotify_fd, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) < 0) {
Mark Salyzyn44692de2018-05-02 11:22:15 -0700263 PLOG(WARNING) << "Could not add watch for " << kDevicePath;
264 ::close(inotify_fd);
265 inotify_fd = -1;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700266 }
Mark Salyzyn44692de2018-05-02 11:22:15 -0700267
268 std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
269 if (device) {
270 dirent* entry;
271 while ((entry = readdir(device.get()))) {
272 if (entry->d_name[0] == '.') continue;
273 std::string devname(kDevicePath);
274 devname += '/';
275 devname += entry->d_name;
276 GeteventOpenDevice(devname);
277 }
278 }
279
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700280 if (inotify_fd >= 0) epoll->RegisterHandler(inotify_fd, InotifyHandler);
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700281}
282
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700283} // namespace
284
Mark Salyzyneca25072018-05-16 15:10:24 -0700285int GetKeychordId(const std::vector<int>& keycodes) {
286 if (keycodes.empty()) return 0;
287 ++keychords_count;
288 keychord_entries.emplace_back(KeychordEntry(keycodes, keychords_count));
289 return keychords_count;
290}
291
292void KeychordInit(Epoll* init_epoll, std::function<void(int)> handler) {
Mark Salyzyn6c6ec722015-10-24 16:20:18 -0700293 epoll = init_epoll;
Mark Salyzyneca25072018-05-16 15:10:24 -0700294 handle_keychord = handler;
Mark Salyzyn353bf1f2018-04-30 07:33:31 -0700295 if (keychords_count) GeteventOpenDevice();
Colin Crossa8666952010-04-13 19:20:44 -0700296}
Tom Cherry81f5d3e2017-06-22 12:53:17 -0700297
298} // namespace init
299} // namespace android