• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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