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 <map>
26 #include <regex>
27 #include <sstream>
28
29 #include "devicestatus_define.h"
30 #include "devicestatus_errors.h"
31 #include "fi_log.h"
32 #include "napi_constants.h"
33 #include "utility.h"
34 #include "virtual_device_defines.h"
35
36 namespace OHOS {
37 namespace Msdp {
38 namespace DeviceStatus {
39 struct Range {
40 size_t start = 0;
41 size_t end = 0;
42 };
43
44 namespace {
45 constexpr ::OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "VInputDevice" };
46
47 const struct Range KEY_BLOCKS[] { { KEY_ESC, BTN_MISC },
48 { KEY_OK, BTN_DPAD_UP },
49 { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY } };
50 } // namespace
51
VInputDevice(const std::string & node)52 VInputDevice::VInputDevice(const std::string &node) : devPath_(node) {}
53
~VInputDevice()54 VInputDevice::~VInputDevice()
55 {
56 Close();
57 }
58
Open()59 int32_t VInputDevice::Open()
60 {
61 CALL_DEBUG_ENTER;
62 char buf[PATH_MAX] {};
63 if (realpath(devPath_.c_str(), buf) == nullptr) {
64 FI_HILOGE("Not real path:%{public}s", devPath_.c_str());
65 return RET_ERR;
66 }
67
68 int32_t nRetries = 6;
69 for (;;) {
70 Utility::ShowUserAndGroup();
71 Utility::ShowFileAttributes(buf);
72 fd_ = open(buf, O_RDWR | O_NONBLOCK | O_CLOEXEC);
73 if (fd_ < 0) {
74 FI_HILOGE("Unable to open device \'%{public}s\':%{public}s", buf, strerror(errno));
75 if (nRetries-- > 0) {
76 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
77 FI_HILOGI("Retry opening device \'%{public}s\'", buf);
78 } else {
79 return RET_ERR;
80 }
81 } else {
82 FI_HILOGD("Opening \'%{public}s\' successfully", buf);
83 break;
84 }
85 }
86 QueryDeviceInfo();
87 QuerySupportedEvents();
88 UpdateCapability();
89 return RET_OK;
90 }
91
Close()92 void VInputDevice::Close()
93 {
94 CALL_DEBUG_ENTER;
95 if (fd_ >= 0) {
96 if (close(fd_) != 0) {
97 FI_HILOGE("close error:%{public}s", strerror(errno));
98 }
99 fd_ = -1;
100 }
101 }
102
QueryAbsInfo(size_t abs,struct input_absinfo & absInfo)103 bool VInputDevice::QueryAbsInfo(size_t abs, struct input_absinfo &absInfo)
104 {
105 CALL_DEBUG_ENTER;
106 errno_t ret = memset_s(&absInfo, sizeof(absInfo), 0, sizeof(absInfo));
107 if (ret != EOK) {
108 FI_HILOGE("Call memset_s failed");
109 return false;
110 }
111 return (ioctl(fd_, EVIOCGABS(abs), &absInfo) >= 0);
112 }
113
SendEvent(uint16_t type,uint16_t code,int32_t value)114 int32_t VInputDevice::SendEvent(uint16_t type, uint16_t code, int32_t value)
115 {
116 CALL_DEBUG_ENTER;
117 if (!IsActive()) {
118 FI_HILOGE("No active device");
119 return RET_ERR;
120 }
121 struct input_event event {
122 .type = type,
123 .code = code,
124 .value = value
125 };
126 struct timeval tv;
127 if (gettimeofday(&tv, nullptr) != 0) {
128 FI_HILOGE("Failed to get current time");
129 return RET_ERR;
130 }
131 event.input_event_sec = tv.tv_sec;
132 event.input_event_usec = tv.tv_usec;
133 ssize_t ret = ::write(fd_, &event, sizeof(struct input_event));
134 if (ret < 0) {
135 FI_HILOGE("Failed to send event:%{public}s", strerror(errno));
136 return RET_ERR;
137 }
138 return RET_OK;
139 }
140
QueryDeviceInfo()141 void VInputDevice::QueryDeviceInfo()
142 {
143 CALL_DEBUG_ENTER;
144 char buffer[PATH_MAX] { 0 };
145
146 int32_t rc = ioctl(fd_, EVIOCGNAME(sizeof(buffer) - 1), &buffer);
147 if (rc < 0) {
148 FI_HILOGE("Could not get device name:%{public}s", strerror(errno));
149 } else {
150 name_.assign(buffer);
151 }
152
153 rc = ioctl(fd_, EVIOCGID, &inputId_);
154 if (rc < 0) {
155 FI_HILOGE("Could not get device input id:%{public}s", strerror(errno));
156 }
157 errno_t ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
158 if (ret != EOK) {
159 FI_HILOGE("Call memset_s failed");
160 return;
161 }
162 rc = ioctl(fd_, EVIOCGPHYS(sizeof(buffer) - 1), &buffer);
163 if (rc < 0) {
164 FI_HILOGE("Could not get location:%{public}s", strerror(errno));
165 } else {
166 phys_.assign(buffer);
167 }
168 ret = memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
169 if (ret != EOK) {
170 FI_HILOGE("Call memset_s failed");
171 return;
172 }
173 rc = ioctl(fd_, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer);
174 if (rc < 0) {
175 FI_HILOGE("Could not get uniq:%{public}s", strerror(errno));
176 } else {
177 uniq_.assign(buffer);
178 }
179 }
180
GetEventMask(const std::string & eventName,uint32_t type,std::size_t arrayLength,uint8_t * whichBitMask) const181 void VInputDevice::GetEventMask(const std::string &eventName, uint32_t type,
182 std::size_t arrayLength, uint8_t *whichBitMask) const
183 {
184 int32_t rc = ioctl(fd_, EVIOCGBIT(type, arrayLength), whichBitMask);
185 if (rc < 0) {
186 FI_HILOGE("Could not get events %{public}s mask:%{public}s", eventName.c_str(), strerror(errno));
187 }
188 }
189
GetPropMask(const std::string & eventName,std::size_t arrayLength,uint8_t * whichBitMask) const190 void VInputDevice::GetPropMask(const std::string &eventName, std::size_t arrayLength, uint8_t *whichBitMask) const
191 {
192 int32_t rc = ioctl(fd_, EVIOCGPROP(arrayLength), whichBitMask);
193 if (rc < 0) {
194 FI_HILOGE("Could not get %{public}s mask:%{public}s", eventName.c_str(), strerror(errno));
195 }
196 }
197
QuerySupportedEvents()198 void VInputDevice::QuerySupportedEvents()
199 {
200 CALL_DEBUG_ENTER;
201 // get events mask
202 GetEventMask("", 0, sizeof(evBitmask_), evBitmask_);
203
204 // get key events
205 GetEventMask("key", EV_KEY, sizeof(keyBitmask_), keyBitmask_);
206
207 // get abs events
208 GetEventMask("abs", EV_ABS, sizeof(absBitmask_), absBitmask_);
209
210 // get rel events
211 GetEventMask("rel", EV_REL, sizeof(relBitmask_), relBitmask_);
212
213 // get msc events
214 GetEventMask("msc", EV_MSC, sizeof(mscBitmask_), mscBitmask_);
215
216 // get led events
217 GetEventMask("led", EV_LED, sizeof(ledBitmask_), ledBitmask_);
218
219 // get rep events
220 GetEventMask("rep", EV_REP, sizeof(repBitmask_), repBitmask_);
221
222 // get properties mask
223 GetPropMask("properties", sizeof(propBitmask_), propBitmask_);
224 }
225
UpdateCapability()226 void VInputDevice::UpdateCapability()
227 {
228 CALL_DEBUG_ENTER;
229 CheckPointers();
230 CheckKeys();
231 }
232
HasMouseButton() const233 bool VInputDevice::HasMouseButton() const
234 {
235 for (size_t button = BTN_MOUSE; button < BTN_JOYSTICK; ++button) {
236 if (TestBit(button, keyBitmask_)) {
237 return true;
238 }
239 }
240 return false;
241 }
242
HasJoystickAxesOrButtons() const243 bool VInputDevice::HasJoystickAxesOrButtons() const
244 {
245 if (!TestBit(BTN_JOYSTICK - 1, keyBitmask_)) {
246 for (size_t button = BTN_JOYSTICK; button < BTN_DIGI; ++button) {
247 if (TestBit(button, keyBitmask_)) {
248 return true;
249 }
250 }
251 for (size_t button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40; ++button) {
252 if (TestBit(button, keyBitmask_)) {
253 return true;
254 }
255 }
256 for (size_t button = BTN_DPAD_UP; button <= BTN_DPAD_RIGHT; ++button) {
257 if (TestBit(button, keyBitmask_)) {
258 return true;
259 }
260 }
261 }
262 for (size_t axis = ABS_RX; axis < ABS_PRESSURE; ++axis) {
263 if (TestBit(axis, absBitmask_)) {
264 return true;
265 }
266 }
267 return false;
268 }
269
PrintCapsDevice() const270 void VInputDevice::PrintCapsDevice() const
271 {
272 std::map<int32_t, std::string> deviceComparisonTable {
273 {DEVICE_CAP_KEYBOARD, "keyboard"},
274 {DEVICE_CAP_TOUCH, "touch device"},
275 {DEVICE_CAP_POINTER, "pointer"},
276 {DEVICE_CAP_TABLET_TOOL, "tablet tool"},
277 {DEVICE_CAP_TABLET_PAD, "pad"},
278 {DEVICE_CAP_GESTURE, "gesture"},
279 {DEVICE_CAP_SWITCH, "switch"},
280 {DEVICE_CAP_JOYSTICK, "joystick"}};
281 for (int32_t i = 0; i < DEVICE_CAP_MAX; ++i) {
282 if (caps_[i] == 1) {
283 FI_HILOGD("This is %{public}s", deviceComparisonTable[i].c_str());
284 }
285 }
286 }
287
CheckPointers()288 void VInputDevice::CheckPointers()
289 {
290 CALL_DEBUG_ENTER;
291 bool hasAbsCoords { TestBit(ABS_X, absBitmask_) && TestBit(ABS_Y, absBitmask_) };
292 bool hasMtCoords { TestBit(ABS_MT_POSITION_X, absBitmask_) && TestBit(ABS_MT_POSITION_Y, absBitmask_) };
293 bool isDirect { TestBit(INPUT_PROP_DIRECT, propBitmask_) };
294 bool hasTouch { TestBit(BTN_TOUCH, keyBitmask_) };
295 bool hasRelCoords { TestBit(REL_X, relBitmask_) && TestBit(REL_Y, relBitmask_) };
296 bool stylusOrPen { TestBit(BTN_STYLUS, keyBitmask_) || TestBit(BTN_TOOL_PEN, keyBitmask_) };
297 bool fingerButNoPen { TestBit(BTN_TOOL_FINGER, keyBitmask_) && !TestBit(BTN_TOOL_PEN, keyBitmask_) };
298 bool hasMouseBtn { HasMouseButton() };
299 bool hasJoystickFeature { HasJoystickAxesOrButtons() };
300
301 if (hasAbsCoords) {
302 if (stylusOrPen) {
303 caps_.set(DEVICE_CAP_TABLET_TOOL);
304 } else if (fingerButNoPen && !isDirect) {
305 caps_.set(DEVICE_CAP_POINTER);
306 } else if (hasMouseBtn) {
307 caps_.set(DEVICE_CAP_POINTER);
308 } else if (hasTouch || isDirect) {
309 caps_.set(DEVICE_CAP_TOUCH);
310 } else if (hasJoystickFeature) {
311 caps_.set(DEVICE_CAP_JOYSTICK);
312 }
313 } else if (hasJoystickFeature) {
314 caps_.set(DEVICE_CAP_JOYSTICK);
315 }
316 if (hasMtCoords) {
317 if (stylusOrPen) {
318 caps_.set(DEVICE_CAP_TABLET_TOOL);
319 } else if (fingerButNoPen && !isDirect) {
320 caps_.set(DEVICE_CAP_POINTER);
321 } else if (hasTouch || isDirect) {
322 caps_.set(DEVICE_CAP_TOUCH);
323 }
324 }
325 if (!caps_.test(DEVICE_CAP_TABLET_TOOL) && !caps_.test(DEVICE_CAP_POINTER) &&
326 !caps_.test(DEVICE_CAP_JOYSTICK) && hasMouseBtn && (hasRelCoords || !hasAbsCoords)) {
327 caps_.set(DEVICE_CAP_POINTER);
328 }
329 PrintCapsDevice();
330 }
331
CheckKeys()332 void VInputDevice::CheckKeys()
333 {
334 CALL_DEBUG_ENTER;
335 if (!TestBit(EV_KEY, evBitmask_)) {
336 FI_HILOGD("No EV_KEY capability");
337 return;
338 }
339 for (size_t block = 0U; block < (sizeof(KEY_BLOCKS) / sizeof(struct Range)); ++block) {
340 for (size_t key = KEY_BLOCKS[block].start; key < KEY_BLOCKS[block].end; ++key) {
341 if (TestBit(key, keyBitmask_)) {
342 FI_HILOGD("Found key %{public}zx", key);
343 caps_.set(DEVICE_CAP_KEYBOARD);
344 return;
345 }
346 }
347 }
348 }
349 } // namespace DeviceStatus
350 } // namespace Msdp
351 } // namespace