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