1/*
2 * Copyright (c) 2021-2024 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 "get_device_node.h"
17
18#undef MMI_LOG_TAG
19#define MMI_LOG_TAG "GetDeviceNode"
20
21namespace OHOS {
22namespace MMI {
23namespace {
24const std::string DEVICES_INFO_PATH = "/proc/bus/input/devices";
25constexpr int32_t READ_CMD_BUFF_SIZE { 1024 };
26} // namespace
27
28GetDeviceNode::GetDeviceNode()
29{
30    InitDeviceInfo();
31}
32
33int32_t GetDeviceNode::GetDeviceNodeName(const std::string &targetName, uint16_t devIndex, std::string &deviceNode)
34{
35    std::vector<std::string> devices = ReadDeviceFile();
36    if (devices.empty()) {
37        MMI_HILOGE("Devices is empty");
38        return RET_ERR;
39    }
40    std::map<std::string, std::vector<std::string>> deviceList;
41    AnalyseDevices(devices, deviceList);
42    if (deviceList.empty()) {
43        MMI_HILOGE("Device list is empty");
44        return RET_ERR;
45    }
46    std::string deviceName = deviceList_[targetName];
47    auto iter = deviceList.find(deviceName);
48    if (iter == deviceList.end()) {
49        MMI_HILOGE("Failed to find deviceName:%{public}s", deviceName.c_str());
50        return RET_ERR;
51    }
52    size_t targetSize = iter->second.size();
53    if (devIndex > targetSize) {
54        MMI_HILOGE("Failed to devIndex:%{public}d > targetSize:%{public}zu", devIndex, targetSize);
55        return RET_ERR;
56    }
57    std::string nodeRootPath = "/dev/input/";
58    deviceNode = nodeRootPath + iter->second[devIndex];
59    MMI_HILOGI("%{public}s[%{public}d] --> %{public}s", targetName.c_str(), devIndex,
60               deviceNode.c_str());
61
62    return RET_OK;
63}
64
65void GetDeviceNode::InitDeviceInfo()
66{
67    deviceList_["mouse"] = "Virtual Mouse";
68    deviceList_["touch"] = "Virtual TouchScreen";
69    deviceList_["finger"] = "Virtual Finger";
70    deviceList_["pad"] = "Virtual Touchpad";
71    deviceList_["pen"] = "Virtual Stylus";
72    deviceList_["gamePad"] = "Virtual GamePad";
73    deviceList_["joystick"] = "Virtual Joystick";
74    deviceList_["remoteControl"] = "Virtual RemoteControl";
75    deviceList_["knob model1"] = "Virtual KnobConsumerCtrl";
76    deviceList_["knob model2"] = "Virtual Knob";
77    deviceList_["knob model3"] = "Virtual KnobMouse";
78    deviceList_["keyboard model1"] = "Virtual keyboard";
79    deviceList_["keyboard model2"] = "Virtual KeyboardConsumerCtrl";
80    deviceList_["keyboard model3"] = "Virtual KeyboardSysCtrl";
81    deviceList_["trackball"] = "Virtual Trackball";
82    deviceList_["trackpad model1"] = "Virtual TrackPadMouse";
83    deviceList_["trackpad model2"] = "Virtual Trackpad";
84}
85
86std::vector<std::string> GetDeviceNode::ReadDeviceFile()
87{
88    char realPath[PATH_MAX] = {};
89    if (realpath(DEVICES_INFO_PATH.c_str(), realPath) == nullptr) {
90        MMI_HILOGE("The path is error, path:%{public}s", DEVICES_INFO_PATH.c_str());
91        return {};
92    }
93    FILE* fp = fopen(DEVICES_INFO_PATH.c_str(), "r");
94    if (fp == nullptr) {
95        MMI_HILOGW("Open file:%{public}s failed", DEVICES_INFO_PATH.c_str());
96        return {};
97    }
98    char buf[READ_CMD_BUFF_SIZE] = {};
99    std::vector<std::string> deviceStrs;
100    while (fgets(buf, sizeof(buf), fp) != nullptr) {
101        deviceStrs.push_back(buf);
102    }
103    if (fclose(fp) != 0) {
104        MMI_HILOGW("Close file:%{public}s failed", DEVICES_INFO_PATH.c_str());
105    }
106    return deviceStrs;
107}
108
109void GetDeviceNode::AnalyseDevices(const std::vector<std::string> &deviceStrs,
110    std::map<std::string, std::vector<std::string>> &deviceList) const
111{
112    std::string name;
113    for (const auto &item : deviceStrs) {
114        if (item.empty()) {
115            MMI_HILOGE("Device info is empty");
116            return;
117        }
118        std::string temp = item.substr(0, 1);
119        uint64_t endPos = 0;
120        uint64_t startPos = 0;
121        if (temp == "N") {
122            startPos = item.find("=") + strlen("N:");
123            endPos = item.size() - 1;
124            name = item.substr(startPos, endPos - startPos - 1);
125        }
126        if (temp == "H") {
127            startPos = item.rfind("event");
128            uint64_t eventLength = item.substr(startPos).find_first_of(" ");
129            std::string target = item.substr(startPos, eventLength);
130            if (!(name.empty())) {
131                deviceList[name].push_back(target);
132                name.clear();
133                target.clear();
134            }
135        }
136    }
137}
138} // namespace MMI
139} // namespace OHOS