• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include "keychords.h"
18 
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <linux/input.h>
22 #include <sys/cdefs.h>
23 #include <sys/inotify.h>
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include <algorithm>
29 #include <functional>
30 #include <map>
31 #include <memory>
32 #include <string>
33 #include <vector>
34 
35 #include <android-base/logging.h>
36 
37 namespace android {
38 namespace init {
39 
Keychords()40 Keychords::Keychords() : epoll_(nullptr), inotify_fd_(-1) {}
41 
~Keychords()42 Keychords::~Keychords() noexcept {
43     if (inotify_fd_ >= 0) {
44         epoll_->UnregisterHandler(inotify_fd_).IgnoreError();
45         ::close(inotify_fd_);
46     }
47     while (!registration_.empty()) GeteventCloseDevice(registration_.begin()->first);
48 }
49 
Mask(size_t bit)50 Keychords::Mask::Mask(size_t bit) : bits_((bit + sizeof(mask_t) - 1) / sizeof(mask_t), 0) {}
51 
SetBit(size_t bit,bool value)52 void Keychords::Mask::SetBit(size_t bit, bool value) {
53     auto idx = bit / (kBitsPerByte * sizeof(mask_t));
54     if (idx >= bits_.size()) return;
55     if (value) {
56         bits_[idx] |= mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t)));
57     } else {
58         bits_[idx] &= ~(mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t))));
59     }
60 }
61 
GetBit(size_t bit) const62 bool Keychords::Mask::GetBit(size_t bit) const {
63     auto idx = bit / (kBitsPerByte * sizeof(mask_t));
64     return bits_[idx] & (mask_t(1) << (bit % (kBitsPerByte * sizeof(mask_t))));
65 }
66 
bytesize() const67 size_t Keychords::Mask::bytesize() const {
68     return bits_.size() * sizeof(mask_t);
69 }
70 
data()71 void* Keychords::Mask::data() {
72     return bits_.data();
73 }
74 
size() const75 size_t Keychords::Mask::size() const {
76     return bits_.size() * sizeof(mask_t) * kBitsPerByte;
77 }
78 
resize(size_t bit)79 void Keychords::Mask::resize(size_t bit) {
80     auto idx = bit / (kBitsPerByte * sizeof(mask_t));
81     if (idx >= bits_.size()) {
82         bits_.resize(idx + 1, 0);
83     }
84 }
85 
operator bool() const86 Keychords::Mask::operator bool() const {
87     for (size_t i = 0; i < bits_.size(); ++i) {
88         if (bits_[i]) return true;
89     }
90     return false;
91 }
92 
operator &(const Keychords::Mask & rval) const93 Keychords::Mask Keychords::Mask::operator&(const Keychords::Mask& rval) const {
94     auto len = std::min(bits_.size(), rval.bits_.size());
95     Keychords::Mask ret;
96     ret.bits_.resize(len);
97     for (size_t i = 0; i < len; ++i) {
98         ret.bits_[i] = bits_[i] & rval.bits_[i];
99     }
100     return ret;
101 }
102 
operator |=(const Keychords::Mask & rval)103 void Keychords::Mask::operator|=(const Keychords::Mask& rval) {
104     auto len = rval.bits_.size();
105     bits_.resize(len);
106     for (size_t i = 0; i < len; ++i) {
107         bits_[i] |= rval.bits_[i];
108     }
109 }
110 
Entry()111 Keychords::Entry::Entry() : notified(false) {}
112 
LambdaCheck()113 void Keychords::LambdaCheck() {
114     for (auto& [keycodes, entry] : entries_) {
115         auto found = true;
116         for (auto& code : keycodes) {
117             if (!current_.GetBit(code)) {
118                 entry.notified = false;
119                 found = false;
120                 break;
121             }
122         }
123         if (!found) continue;
124         if (entry.notified) continue;
125         entry.notified = true;
126         handler_(keycodes);
127     }
128 }
129 
LambdaHandler(int fd)130 void Keychords::LambdaHandler(int fd) {
131     input_event event;
132     auto res = TEMP_FAILURE_RETRY(::read(fd, &event, sizeof(event)));
133     if ((res != sizeof(event)) || (event.type != EV_KEY)) return;
134     current_.SetBit(event.code, event.value);
135     LambdaCheck();
136 }
137 
GeteventEnable(int fd)138 bool Keychords::GeteventEnable(int fd) {
139     // Make sure it is an event channel, should pass this ioctl call
140     int version;
141     if (::ioctl(fd, EVIOCGVERSION, &version)) return false;
142 
143 #ifdef EVIOCSMASK
144     static auto EviocsmaskSupported = true;
145     if (EviocsmaskSupported) {
146         Keychords::Mask mask(EV_KEY);
147         mask.SetBit(EV_KEY);
148         input_mask msg = {};
149         msg.type = EV_SYN;
150         msg.codes_size = mask.bytesize();
151         msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
152         if (::ioctl(fd, EVIOCSMASK, &msg) == -1) {
153             PLOG(WARNING) << "EVIOCSMASK not supported";
154             EviocsmaskSupported = false;
155         }
156     }
157 #endif
158 
159     Keychords::Mask mask;
160     for (auto& [keycodes, entry] : entries_) {
161         for (auto& code : keycodes) {
162             mask.resize(code);
163             mask.SetBit(code);
164         }
165     }
166 
167     current_.resize(mask.size());
168     Keychords::Mask available(mask.size());
169     auto res = ::ioctl(fd, EVIOCGBIT(EV_KEY, available.bytesize()), available.data());
170     if (res == -1) return false;
171     if (!(available & mask)) return false;
172 
173 #ifdef EVIOCSMASK
174     if (EviocsmaskSupported) {
175         input_mask msg = {};
176         msg.type = EV_KEY;
177         msg.codes_size = mask.bytesize();
178         msg.codes_ptr = reinterpret_cast<uintptr_t>(mask.data());
179         ::ioctl(fd, EVIOCSMASK, &msg);
180     }
181 #endif
182 
183     Keychords::Mask set(mask.size());
184     res = ::ioctl(fd, EVIOCGKEY(res), set.data());
185     if (res > 0) {
186         current_ |= mask & available & set;
187         LambdaCheck();
188     }
189     if (auto result = epoll_->RegisterHandler(fd, [this, fd]() { this->LambdaHandler(fd); });
190         !result) {
191         LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
192         return false;
193     }
194     return true;
195 }
196 
GeteventOpenDevice(const std::string & device)197 void Keychords::GeteventOpenDevice(const std::string& device) {
198     if (registration_.count(device)) return;
199     auto fd = TEMP_FAILURE_RETRY(::open(device.c_str(), O_RDONLY | O_CLOEXEC));
200     if (fd == -1) {
201         PLOG(ERROR) << "Can not open " << device;
202         return;
203     }
204     if (!GeteventEnable(fd)) {
205         ::close(fd);
206     } else {
207         registration_.emplace(device, fd);
208     }
209 }
210 
GeteventCloseDevice(const std::string & device)211 void Keychords::GeteventCloseDevice(const std::string& device) {
212     auto it = registration_.find(device);
213     if (it == registration_.end()) return;
214     auto fd = (*it).second;
215     epoll_->UnregisterHandler(fd).IgnoreError();
216     registration_.erase(it);
217     ::close(fd);
218 }
219 
InotifyHandler()220 void Keychords::InotifyHandler() {
221     unsigned char buf[512];  // History shows 32-64 bytes typical
222 
223     auto res = TEMP_FAILURE_RETRY(::read(inotify_fd_, buf, sizeof(buf)));
224     if (res < 0) {
225         PLOG(WARNING) << "could not get event";
226         return;
227     }
228 
229     auto event_buf = buf;
230     while (static_cast<size_t>(res) >= sizeof(inotify_event)) {
231         auto event = reinterpret_cast<inotify_event*>(event_buf);
232         auto event_size = sizeof(inotify_event) + event->len;
233         if (static_cast<size_t>(res) < event_size) break;
234         if (event->len) {
235             std::string devname(kDevicePath);
236             devname += '/';
237             devname += event->name;
238             if (event->mask & IN_CREATE) {
239                 GeteventOpenDevice(devname);
240             } else {
241                 GeteventCloseDevice(devname);
242             }
243         }
244         res -= event_size;
245         event_buf += event_size;
246     }
247 }
248 
GeteventOpenDevice()249 void Keychords::GeteventOpenDevice() {
250     inotify_fd_ = ::inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
251     if (inotify_fd_ < 0) {
252         PLOG(WARNING) << "Could not instantiate inotify for " << kDevicePath;
253     } else if (::inotify_add_watch(inotify_fd_, kDevicePath, IN_DELETE | IN_CREATE | IN_ONLYDIR) <
254                0) {
255         PLOG(WARNING) << "Could not add watch for " << kDevicePath;
256         ::close(inotify_fd_);
257         inotify_fd_ = -1;
258     }
259 
260     std::unique_ptr<DIR, decltype(&closedir)> device(opendir(kDevicePath), closedir);
261     if (device) {
262         dirent* entry;
263         while ((entry = readdir(device.get()))) {
264             if (entry->d_name[0] == '.') continue;
265             std::string devname(kDevicePath);
266             devname += '/';
267             devname += entry->d_name;
268             GeteventOpenDevice(devname);
269         }
270     }
271 
272     if (inotify_fd_ >= 0) {
273         if (auto result =
274                     epoll_->RegisterHandler(inotify_fd_, [this]() { this->InotifyHandler(); });
275             !result) {
276             LOG(WARNING) << "Could not register keychord epoll handler: " << result.error();
277         }
278     }
279 }
280 
Register(const std::vector<int> & keycodes)281 void Keychords::Register(const std::vector<int>& keycodes) {
282     if (keycodes.empty()) return;
283     entries_.try_emplace(keycodes, Entry());
284 }
285 
Start(Epoll * epoll,std::function<void (const std::vector<int> &)> handler)286 void Keychords::Start(Epoll* epoll, std::function<void(const std::vector<int>&)> handler) {
287     epoll_ = epoll;
288     handler_ = handler;
289     if (entries_.size()) GeteventOpenDevice();
290 }
291 
292 }  // namespace init
293 }  // namespace android
294