keychords.cpp 8.5 KB

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