1 /*
2 * Copyright (c) 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 "general_device.h"
17
18 #include <iostream>
19 #include <sstream>
20 #include <thread>
21
22 namespace OHOS {
23 namespace MMI {
24 namespace {
25 constexpr size_t DEFAULT_BUF_SIZE { 1024 };
26 constexpr int32_t SLEEP_TIME { 500 };
27 }
28
Close()29 void GeneralDevice::Close()
30 {
31 vDev_.reset();
32 }
33
SendEvent(uint16_t type,uint16_t code,int32_t value)34 void GeneralDevice::SendEvent(uint16_t type, uint16_t code, int32_t value)
35 {
36 if (vDev_ == nullptr) {
37 std::cout << "No input device" << std::endl;
38 return;
39 }
40 vDev_->SendEvent(type, code, value);
41 }
42
GetDevPath() const43 std::string GeneralDevice::GetDevPath() const
44 {
45 return (vDev_ != nullptr ? vDev_->GetDevPath() : std::string());
46 }
47
OpenDevice(const std::string & name)48 bool GeneralDevice::OpenDevice(const std::string &name)
49 {
50 int32_t nTries = 6;
51
52 while (nTries-- > 0) {
53 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
54 std::string node;
55 if (GeneralDevice::FindDeviceNode(name, node)) {
56 std::cout << "Found node path: " << node << std::endl;
57 auto vInpuDev = std::make_unique<VInputDevice>(node);
58 vInpuDev->Open();
59 if (vInpuDev->IsActive()) {
60 vDev_ = std::move(vInpuDev);
61 return true;
62 }
63 }
64 }
65 return false;
66 }
67
FindDeviceNode(const std::string & name,std::string & node)68 bool GeneralDevice::FindDeviceNode(const std::string &name, std::string &node)
69 {
70 std::map<std::string, std::string> nodes;
71 GetInputDeviceNodes(nodes);
72 std::cout << "There are " << nodes.size() << " device nodes" << std::endl;
73
74 std::map<std::string, std::string>::const_iterator cItr = nodes.find(name);
75 if (cItr == nodes.cend()) {
76 std::cout << "No virtual stylus were found" << std::endl;
77 return false;
78 }
79 std::cout << "Node name : \'" << cItr->second << "\'" << std::endl;
80 std::ostringstream ss;
81 ss << "/dev/input/" << cItr->second;
82 node = ss.str();
83 return true;
84 }
85
Execute(std::vector<std::string> & results)86 void GeneralDevice::Execute(std::vector<std::string> &results)
87 {
88 char buffer[DEFAULT_BUF_SIZE] {};
89 FILE *pin = popen("cat /proc/bus/input/devices", "r");
90 if (pin == nullptr) {
91 std::cout << "Failed to popen command" << std::endl;
92 return;
93 }
94 while (!feof(pin)) {
95 if (fgets(buffer, sizeof(buffer), pin) != nullptr) {
96 results.push_back(buffer);
97 }
98 }
99 pclose(pin);
100 }
101
GetInputDeviceNodes(std::map<std::string,std::string> & nodes)102 void GeneralDevice::GetInputDeviceNodes(std::map<std::string, std::string> &nodes)
103 {
104 std::vector<std::string> results;
105 Execute(results);
106 if (results.empty()) {
107 std::cout << "Failed to list devices" << std::endl;
108 return;
109 }
110 const std::string kname { "Name=\"" };
111 const std::string kevent { "event" };
112 std::string name;
113 for (const auto &res : results) {
114 if (res[0] == 'N') {
115 std::string::size_type spos = res.find(kname);
116 if (spos != std::string::npos) {
117 spos += kname.size();
118 std::string::size_type tpos = res.find("\"", spos);
119 if (tpos != std::string::npos) {
120 name = res.substr(spos, tpos - spos);
121 }
122 }
123 } else if (!name.empty() && (res[0] == 'H')) {
124 std::string::size_type spos = res.find(kevent);
125 if (spos != std::string::npos) {
126 std::map<std::string, std::string>::const_iterator cItr = nodes.find(name);
127 if (cItr != nodes.end()) {
128 nodes.erase(cItr);
129 }
130 std::string::size_type tpos = spos + kevent.size();
131 while (std::isalnum(res[tpos])) {
132 ++tpos;
133 }
134 auto [_, ret] = nodes.emplace(name, res.substr(spos, tpos - spos));
135 if (!ret) {
136 std::cout << "name is duplicated" << std::endl;
137 }
138 name.clear();
139 }
140 }
141 }
142 }
143 } // namespace MMI
144 } // namespace OHOS