1 /*
2 * Copyright (c) 2025 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
17 #include "special_input_device_parser.h"
18
19 #include "devicestatus_define.h"
20 #include "json_parser.h"
21
22 #include <cJSON.h>
23
24 #undef LOG_TAG
25 #define LOG_TAG "SpecialInputDeviceParser"
26
27 namespace OHOS {
28 namespace Msdp {
29 namespace DeviceStatus {
30 namespace {
31 constexpr std::string_view specialInputDeviceDir { "/etc/multimodalinput/special_input_device_config.json" };
32 constexpr int32_t maxJsonArraySize { 100 };
33 }
34
GetInstance()35 SpecialInputDeviceParser& SpecialInputDeviceParser::GetInstance()
36 {
37 static SpecialInputDeviceParser instance;
38 return instance;
39 }
40
Init()41 int32_t SpecialInputDeviceParser::Init()
42 {
43 CALL_DEBUG_ENTER;
44 if (isInitialized_.load()) {
45 return RET_OK;
46 }
47 std::string jsonStr = ReadJsonFile(std::string(specialInputDeviceDir));
48 if (jsonStr.empty()) {
49 FI_HILOGE("Read specialInputDevice failed");
50 return RET_ERR;
51 }
52 JsonParser parser(jsonStr.c_str());
53 if (!cJSON_IsObject(parser.Get())) {
54 FI_HILOGE("Not valid object");
55 return RET_ERR;
56 }
57 if (ParseExactlyMatch(parser) != RET_OK) {
58 FI_HILOGE("ParseExactlyMatch failed");
59 return RET_ERR;
60 }
61 if (ParseContainMatch(parser) != RET_OK) {
62 FI_HILOGE("ParseContainMatch failed");
63 return RET_ERR;
64 }
65 if (ParseSpecialInputDevice(parser) != RET_OK) {
66 FI_HILOGE("ParseSpecialInputDevice failed");
67 return RET_ERR;
68 }
69 PrintSpecialInputDevice();
70 isInitialized_.store(true);
71 return RET_OK;
72 }
73
IsPointerDevice(const std::string & name,bool & isPointerDevice)74 int32_t SpecialInputDeviceParser::IsPointerDevice(const std::string &name, bool &isPointerDevice)
75 {
76 if (Init() != RET_OK) {
77 FI_HILOGE("Init failed");
78 return RET_ERR;
79 }
80 std::shared_lock<std::shared_mutex> lock(lock_);
81 if (exactlyMatchInputDevice_.find(name) != exactlyMatchInputDevice_.end()) {
82 isPointerDevice = exactlyMatchInputDevice_[name].isMouse;
83 return RET_OK;
84 }
85 for (const auto &containItem : containMatchInputDevice_) {
86 if (IsAllKeywordsMatched(name, containItem.keywords)) {
87 isPointerDevice = containItem.isMouse;
88 return RET_OK;
89 }
90 }
91 return RET_ERR;
92 }
93
GetInputDevName(const std::string & alias)94 std::string SpecialInputDeviceParser::GetInputDevName(const std::string &alias)
95 {
96 if (Init() != RET_OK) {
97 FI_HILOGE("Init failed");
98 return "";
99 }
100 std::shared_lock<std::shared_mutex> lock(lock_);
101 if (specialInputDevices_.find(alias) != specialInputDevices_.end()) {
102 return specialInputDevices_[alias];
103 }
104 FI_HILOGW("No %{public}s matched.", alias.c_str());
105 return "";
106 }
107
ParseExactlyMatch(const JsonParser & jsonParser)108 int32_t SpecialInputDeviceParser::ParseExactlyMatch(const JsonParser &jsonParser)
109 {
110 cJSON *exactlyMatchJson = cJSON_GetObjectItemCaseSensitive(jsonParser.Get(), "exactly_match");
111 if (!cJSON_IsArray(exactlyMatchJson)) {
112 FI_HILOGE("exactlyMatchJson is not array");
113 return RET_ERR;
114 }
115 int32_t arraySize = cJSON_GetArraySize(exactlyMatchJson);
116 if (arraySize > maxJsonArraySize) {
117 FI_HILOGW("arraySize is too much, truncate it");
118 }
119 for (int32_t i = 0; i < std::min(arraySize, maxJsonArraySize); i++) {
120 cJSON* devItemJson = cJSON_GetArrayItem(exactlyMatchJson, i);
121 if (devItemJson == nullptr) {
122 FI_HILOGE("The devItem init failed");
123 continue;
124 }
125 ExactlyMatchInputDevice inputDev;
126 if (ParseExactlyMatchItem(devItemJson, inputDev) != RET_OK) {
127 FI_HILOGE("ParseExactlyMatchItem failed");
128 continue;
129 }
130 std::unique_lock<std::shared_mutex> lock(lock_);
131 exactlyMatchInputDevice_.insert({inputDev.devName, { inputDev.devName, inputDev.isMouse }});
132 }
133 return RET_OK;
134 }
135
ParseContainMatch(const JsonParser & jsonParser)136 int32_t SpecialInputDeviceParser::ParseContainMatch(const JsonParser &jsonParser)
137 {
138 cJSON *containMatchJson = cJSON_GetObjectItemCaseSensitive(jsonParser.Get(), "contain_match");
139 if (!cJSON_IsArray(containMatchJson)) {
140 FI_HILOGE("containMatchJson is not array");
141 return RET_ERR;
142 }
143 int32_t arraySize = cJSON_GetArraySize(containMatchJson);
144 if (arraySize > maxJsonArraySize) {
145 FI_HILOGE("arraySize is too much");
146 return RET_ERR;
147 }
148 for (int32_t i = 0; i < arraySize; i++) {
149 cJSON* devItemJson = cJSON_GetArrayItem(containMatchJson, i);
150 if (devItemJson == nullptr) {
151 FI_HILOGE("The devItem init failed");
152 continue;
153 }
154 ContainMatchInputDevice inputDev;
155 if (ParseContainMatchItem(devItemJson, inputDev) != RET_OK) {
156 FI_HILOGE("ParseContainMatchItem failed");
157 continue;
158 }
159 std::unique_lock<std::shared_mutex> lock(lock_);
160 containMatchInputDevice_.push_back(inputDev);
161 }
162 return RET_OK;
163 }
164
ParseSpecialInputDevice(const JsonParser & jsonParser)165 int32_t SpecialInputDeviceParser::ParseSpecialInputDevice(const JsonParser &jsonParser)
166 {
167 cJSON *specialInputDevJson = cJSON_GetObjectItemCaseSensitive(jsonParser.Get(), "special_input_device");
168 if (!cJSON_IsArray(specialInputDevJson)) {
169 FI_HILOGE("specialInputDevJson is not array");
170 return RET_ERR;
171 }
172 int32_t arraySize = cJSON_GetArraySize(specialInputDevJson);
173 if (arraySize > maxJsonArraySize) {
174 FI_HILOGE("arraySize is too much");
175 return RET_ERR;
176 }
177 for (int32_t i = 0; i < arraySize; i++) {
178 cJSON* devItemJson = cJSON_GetArrayItem(specialInputDevJson, i);
179 if (devItemJson == nullptr) {
180 FI_HILOGE("The devItem init failed");
181 continue;
182 }
183 SpecialInputDevice inputDev;
184 if (ParseSpecialInputDeviceItem(devItemJson, inputDev) != RET_OK) {
185 FI_HILOGE("ParseSpecialInputDeviceItem failed");
186 continue;
187 }
188 std::unique_lock<std::shared_mutex> lock(lock_);
189 specialInputDevices_.insert({ inputDev.inputDevAlias, inputDev.inputDevName });
190 }
191 return RET_OK;
192 }
193
ParseExactlyMatchItem(const cJSON * json,ExactlyMatchInputDevice & deviceProp)194 int32_t SpecialInputDeviceParser::ParseExactlyMatchItem(const cJSON *json, ExactlyMatchInputDevice &deviceProp)
195 {
196 if (JsonParser::ParseString(json, "device_name", deviceProp.devName) != RET_OK) {
197 FI_HILOGE("Parse device_name failed");
198 return RET_ERR;
199 }
200 if (JsonParser::ParseBool(json, "is_mouse", deviceProp.isMouse) != RET_OK) {
201 FI_HILOGE("Parse is_mouse failed");
202 return RET_ERR;
203 }
204 return RET_OK;
205 }
206
ParseContainMatchItem(const cJSON * json,ContainMatchInputDevice & deviceProp)207 int32_t SpecialInputDeviceParser::ParseContainMatchItem(const cJSON *json, ContainMatchInputDevice &deviceProp)
208 {
209 std::vector<std::string> keywords;
210 if (JsonParser::ParseStringArray(json, "keywords", keywords, maxJsonArraySize) != RET_OK) {
211 FI_HILOGE("Parse keywords failed");
212 return RET_ERR;
213 }
214 deviceProp.keywords = std::move(keywords);
215 if (JsonParser::ParseBool(json, "is_mouse", deviceProp.isMouse) != RET_OK) {
216 FI_HILOGE("Parse is_mouse failed");
217 return RET_ERR;
218 }
219 return RET_OK;
220 }
221
ParseSpecialInputDeviceItem(const cJSON * json,SpecialInputDevice & specialInputDev)222 int32_t SpecialInputDeviceParser::ParseSpecialInputDeviceItem(const cJSON *json, SpecialInputDevice &specialInputDev)
223 {
224 if (JsonParser::ParseString(json, "input_device_alias", specialInputDev.inputDevAlias) != RET_OK) {
225 FI_HILOGE("Parse input_device_alias failed");
226 return RET_ERR;
227 }
228 if (JsonParser::ParseString(json, "input_device_name", specialInputDev.inputDevName) != RET_OK) {
229 FI_HILOGE("Parse input_device_name failed");
230 return RET_ERR;
231 }
232 return RET_OK;
233 }
234
IsAllKeywordsMatched(const std::string & name,const std::vector<std::string> & keywords)235 bool SpecialInputDeviceParser::IsAllKeywordsMatched(const std::string &name, const std::vector<std::string> &keywords)
236 {
237 if (keywords.empty()) {
238 return false;
239 }
240 for (const auto &key : keywords) {
241 if (name.find(key) == std::string::npos) {
242 return false;
243 }
244 }
245 return true;
246 }
247
PrintSpecialInputDevice()248 void SpecialInputDeviceParser::PrintSpecialInputDevice()
249 {
250 std::shared_lock<std::shared_mutex> lock(lock_);
251 FI_HILOGI("Excatly Match:");
252 for (const auto &elem : exactlyMatchInputDevice_) {
253 FI_HILOGI("deviceName:%{public}s -> isMouse:%{public}d", elem.second.devName.c_str(), elem.second.isMouse);
254 }
255 FI_HILOGI("Contain Match:");
256 for (const auto &elem : containMatchInputDevice_) {
257 std::string keywords;
258 std::for_each(elem.keywords.begin(), elem.keywords.end(), [&keywords](const std::string &key) {
259 keywords.append(key + ", ");
260 });
261 FI_HILOGI("keywords:%{public}s -> isMouse:%{public}d", keywords.c_str(), elem.isMouse);
262 }
263 FI_HILOGI("Special Input Device:");
264 for (const auto &elem : specialInputDevices_) {
265 FI_HILOGI("devAlias:%{public}s -> devName:%{public}s", elem.first.c_str(), elem.second.c_str());
266 }
267 }
268 } // namespace DeviceStatus
269 } // namespace Msdp
270 } // namespace OHOS