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