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