1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "v_input_device.h"
17
18 #include <fcntl.h>
19 #include <securec.h>
20 #include <sys/ioctl.h>
21 #include <unistd.h>
22
23 #include <cstring>
24 #include <fstream>
25 #include <iostream>
26 #include <map>
27 #include <regex>
28 #include <sstream>
29
30 #include "define_multimodal.h"
31
32 namespace OHOS {
33 namespace MMI {
34 struct Range {
35 size_t start = 0;
36 size_t end = 0;
37 };
38
39 namespace {
40 constexpr int32_t SLEEP_TIME { 500 };
41 const struct Range KEY_BLOCKS[] { { KEY_ESC, BTN_MISC },
42 { KEY_OK, BTN_DPAD_UP },
43 { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY } };
44 } // namespace
45
VInputDevice(const std::string & node)46 VInputDevice::VInputDevice(const std::string &node) : devPath_(node) {}
47
~VInputDevice()48 VInputDevice::~VInputDevice()
49 {
50 Close();
51 }
52
Open()53 int32_t VInputDevice::Open()
54 {
55 int32_t nRetries = 6;
56
57 for (;;) {
58 fd_ = open(devPath_.c_str(), O_RDWR | O_NONBLOCK | O_CLOEXEC);
59 if (fd_ < 0) {
60 std::cout << "Unable to open device '" << devPath_ << "': " << ::strerror(errno) << std::endl;
61 if (nRetries-- > 0) {
62 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
63 std::cout << "Retry opening device \'" << devPath_ << " \'" << std::endl;
64 } else {
65 return RET_ERR;
66 }
67 } else {
68 std::cout << "Opening \'" << devPath_ << "\' successfully" << std::endl;
69 break;
70 }
71 }
72 QueryDeviceInfo();
73 QuerySupportedEvents();
74 UpdateCapability();
75 return RET_OK;
76 }
77
Close()78 void VInputDevice::Close()
79 {
80 if (fd_ >= 0) {
81 if (close(fd_) != 0) {
82 std::cout << "Close error: " << ::strerror(errno) << std::endl;
83 }
84 fd_ = -1;
85 }
86 }
87
QueryAbsInfo(size_t abs,struct input_absinfo & absInfo)88 bool VInputDevice::QueryAbsInfo(size_t abs, struct input_absinfo &absInfo)
89 {
90 errno_t ret = memset_s(&absInfo, sizeof(absInfo), 0, sizeof(absInfo));
91 if (ret != EOK) {
92 std::cout << "Call memset_s failed" << std::endl;
93 return false;
94 }
95 return (ioctl(fd_, EVIOCGABS(abs), &absInfo) >= 0);
96 }
97
SendEvent(uint16_t type,uint16_t code,int32_t value)98 int32_t VInputDevice::SendEvent(uint16_t type, uint16_t code, int32_t value)
99 {
100 if (!IsActive()) {
101 std::cout << "No active device" << std::endl;
102 return RET_ERR;
103 }
104 struct input_event event {
105 .type = type,
106 .code = code,
107 .value = value
108 };
109 struct timeval tv;
110 if (gettimeofday(&tv, nullptr) != 0) {
111 std::cout << "Failed to get current time" << std::endl;
112 return RET_ERR;
113 }
114 event.input_event_sec = tv.tv_sec;
115 event.input_event_usec = tv.tv_usec;
116 ssize_t ret = ::write(fd_, &event, sizeof(struct input_event));
117 if (ret < 0) {
118 std::cout << "Failed to send event: " << ::strerror(errno) << std::endl;
119 return RET_ERR;
120 }
121 return RET_OK;
122 }
123
QueryDeviceInfo()124 void VInputDevice::QueryDeviceInfo()
125 {
126 char buffer[PATH_MAX] { 0 };
127
128 int32_t rc = ioctl(fd_, EVIOCGNAME(sizeof(buffer) - 1), &buffer);
129 if (rc < 0) {
130 std::cout << "Could not get device name: " << ::strerror(errno) << std::endl;
131 } else {
132 name_.assign(buffer);
133 }
134
135 rc = ioctl(fd_, EVIOCGID, &inputId_);
136 if (rc < 0) {
137 std::cout << "Couldn't not get device input id: " << ::strerror(errno) << std::endl;
138 }
139 errno_t ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
140 if (ret != EOK) {
141 std::cout << "Call memset_s was a failure" << std::endl;
142 return;
143 }
144 rc = ioctl(fd_, EVIOCGPHYS(sizeof(buffer) - 1), &buffer);
145 if (rc < 0) {
146 std::cout << "Couldn't get location: " << ::strerror(errno) << std::endl;
147 } else {
148 phys_.assign(buffer);
149 }
150 ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
151 if (ret != EOK) {
152 std::cout << "Call memset_s was a failure" << std::endl;
153 return;
154 }
155 rc = ioctl(fd_, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer);
156 if (rc < 0) {
157 std::cout << "Could not get uniq: " << ::strerror(errno) << std::endl;
158 } else {
159 uniq_.assign(buffer);
160 }
161 }
162
GetEventMask(const std::string & eventName,uint32_t type,std::size_t arrayLength,uint8_t * whichBitMask) const163 void VInputDevice::GetEventMask(const std::string &eventName, uint32_t type,
164 std::size_t arrayLength, uint8_t *whichBitMask) const
165 {
166 int32_t rc = ioctl(fd_, EVIOCGBIT(type, arrayLength), whichBitMask);
167 if (rc < 0) {
168 std::cout << "Could not get events " << eventName << " mask: " << ::strerror(errno) << std::endl;
169 }
170 }
171
GetPropMask(const std::string & eventName,std::size_t arrayLength,uint8_t * whichBitMask) const172 void VInputDevice::GetPropMask(const std::string &eventName, std::size_t arrayLength, uint8_t *whichBitMask) const
173 {
174 int32_t rc = ioctl(fd_, EVIOCGPROP(arrayLength), whichBitMask);
175 if (rc < 0) {
176 std::cout << "Could not get " << eventName << " mask: " << ::strerror(errno) << std::endl;
177 }
178 }
179
QuerySupportedEvents()180 void VInputDevice::QuerySupportedEvents()
181 {
182 // get events mask
183 GetEventMask("", 0, sizeof(evBitmask_), evBitmask_);
184
185 // get key events
186 GetEventMask("key", EV_KEY, sizeof(keyBitmask_), keyBitmask_);
187
188 // get abs events
189 GetEventMask("abs", EV_ABS, sizeof(absBitmask_), absBitmask_);
190
191 // get rel events
192 GetEventMask("rel", EV_REL, sizeof(relBitmask_), relBitmask_);
193
194 // get msc events
195 GetEventMask("msc", EV_MSC, sizeof(mscBitmask_), mscBitmask_);
196
197 // get led events
198 GetEventMask("led", EV_LED, sizeof(ledBitmask_), ledBitmask_);
199
200 // get rep events
201 GetEventMask("rep", EV_REP, sizeof(repBitmask_), repBitmask_);
202
203 // get properties mask
204 GetPropMask("properties", sizeof(propBitmask_), propBitmask_);
205 }
206
UpdateCapability()207 void VInputDevice::UpdateCapability()
208 {
209 CheckPointers();
210 CheckKeys();
211 }
212
HasAxesOrButton(size_t start,size_t end,const uint8_t * whichBitMask) const213 bool VInputDevice::HasAxesOrButton(size_t start, size_t end, const uint8_t* whichBitMask) const
214 {
215 for (size_t type = start; type < end; ++type) {
216 if (TestBit(type, whichBitMask)) {
217 return true;
218 }
219 }
220 return false;
221 }
222
HasJoystickAxesOrButtons() const223 bool VInputDevice::HasJoystickAxesOrButtons() const
224 {
225 if (!TestBit(BTN_JOYSTICK - 1, keyBitmask_)) {
226 if (HasAxesOrButton(BTN_JOYSTICK, BTN_DIGI, keyBitmask_) ||
227 // BTN_TRIGGER_HAPPY40 + 1 : Iteration limit
228 HasAxesOrButton(BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY40 + 1, keyBitmask_) ||
229 HasAxesOrButton(BTN_DPAD_UP, BTN_DPAD_RIGHT + 1, keyBitmask_)) { // BTN_DPAD_RIGHT + 1 : Iteration limit
230 return true;
231 }
232 }
233 return HasAxesOrButton(ABS_RX, ABS_PRESSURE, absBitmask_);
234 }
235
PrintCapsDevice() const236 void VInputDevice::PrintCapsDevice() const
237 {
238 std::map<std::size_t, std::string> deviceComparisonTable {
239 { DEVICE_CAP_KEYBOARD, "keyboard" },
240 { DEVICE_CAP_TOUCH, "touch device" },
241 { DEVICE_CAP_TABLET_TOOL, "tablet tool" },
242 { DEVICE_CAP_POINTER, "pointer" },
243 { DEVICE_CAP_TABLET_PAD, "pad" },
244 { DEVICE_CAP_GESTURE, "gesture" },
245 { DEVICE_CAP_SWITCH, "switch" },
246 { DEVICE_CAP_JOYSTICK, "joystick" }
247 };
248 for (const auto& [cap, name] : deviceComparisonTable) {
249 if (caps_.test(cap)) {
250 std::cout << "This is " << name << std::endl;
251 }
252 }
253 }
254
HasAbsCoord() const255 bool VInputDevice::HasAbsCoord() const
256 {
257 return HasAbs(ABS_X) && HasAbs(ABS_Y);
258 }
259
HasMtCoord() const260 bool VInputDevice::HasMtCoord() const
261 {
262 return HasAbs(ABS_MT_POSITION_X) && HasAbs(ABS_MT_POSITION_Y);
263 }
264
HasRelCoord() const265 bool VInputDevice::HasRelCoord() const
266 {
267 return HasRel(REL_X) && HasRel(REL_Y);
268 }
269
CheckAbs()270 void VInputDevice::CheckAbs()
271 {
272 if (HasKey(BTN_STYLUS) || HasKey(BTN_TOOL_PEN)) {
273 caps_.set(DEVICE_CAP_TABLET_TOOL);
274 } else if (HasKey(BTN_TOOL_FINGER) && !HasKey(BTN_TOOL_PEN) && !HasProperty(INPUT_PROP_DIRECT)) {
275 caps_.set(DEVICE_CAP_POINTER);
276 } else if (HasAxesOrButton(BTN_MOUSE, BTN_JOYSTICK, keyBitmask_)) {
277 caps_.set(DEVICE_CAP_POINTER);
278 } else if (HasKey(BTN_TOUCH) || HasProperty(INPUT_PROP_DIRECT)) {
279 caps_.set(DEVICE_CAP_TOUCH);
280 } else if (HasJoystickAxesOrButtons()) {
281 caps_.set(DEVICE_CAP_JOYSTICK);
282 }
283 }
284
CheckMt()285 void VInputDevice::CheckMt()
286 {
287 if (HasKey(BTN_STYLUS) || HasKey(BTN_TOOL_PEN)) {
288 caps_.set(DEVICE_CAP_TABLET_TOOL);
289 } else if (HasKey(BTN_TOOL_FINGER) && !HasKey(BTN_TOOL_PEN) && !HasProperty(INPUT_PROP_DIRECT)) {
290 caps_.set(DEVICE_CAP_POINTER);
291 } else if (HasKey(BTN_TOUCH) || HasProperty(INPUT_PROP_DIRECT)) {
292 caps_.set(DEVICE_CAP_TOUCH);
293 }
294 }
295
CheckAdditional()296 void VInputDevice::CheckAdditional()
297 {
298 if (!HasCapability(DEVICE_CAP_TABLET_TOOL) &&
299 !HasCapability(DEVICE_CAP_POINTER) &&
300 !HasCapability(DEVICE_CAP_JOYSTICK) &&
301 HasAxesOrButton(BTN_MOUSE, BTN_JOYSTICK, keyBitmask_) && (HasRelCoord() || !HasAbsCoord())) {
302 caps_.set(DEVICE_CAP_POINTER);
303 }
304 }
305
CheckPointers()306 void VInputDevice::CheckPointers()
307 {
308 if (HasAbsCoord()) {
309 CheckAbs();
310 } else if (HasJoystickAxesOrButtons()) {
311 caps_.set(DEVICE_CAP_JOYSTICK);
312 }
313 if (HasMtCoord()) {
314 CheckMt();
315 }
316 CheckAdditional();
317 PrintCapsDevice();
318 }
319
CheckKeys()320 void VInputDevice::CheckKeys()
321 {
322 if (!TestBit(EV_KEY, evBitmask_)) {
323 std::cout << "No EV_KEY capability" << std::endl;
324 return;
325 }
326 for (size_t block = 0U; block < (sizeof(KEY_BLOCKS) / sizeof(struct Range)); ++block) {
327 for (size_t key = KEY_BLOCKS[block].start; key < KEY_BLOCKS[block].end; ++key) {
328 if (TestBit(key, keyBitmask_)) {
329 std::cout << "Found key " << key << std::endl;
330 caps_.set(DEVICE_CAP_KEYBOARD);
331 return;
332 }
333 }
334 }
335 }
336 } // namespace MMI
337 } // namespace