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 "multimodal_event_handler.h"
17
18 #include <fstream>
19
20 #include "cJSON.h"
21 #include "config_policy_utils.h"
22
23 #include "event_log_helper.h"
24 #include "input_manager_impl.h"
25 #include "mmi_client.h"
26 #include "multimodal_input_connect_manager.h"
27 #include "proto.h"
28 #include "tablet_event_input_subscribe_manager.h"
29 #include "pre_monitor_manager.h"
30 #include "util.h"
31
32 #undef MMI_LOG_DOMAIN
33 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
34 #undef MMI_LOG_TAG
35 #define MMI_LOG_TAG "MultimodalEventHandler"
36
37 namespace OHOS {
38 namespace MMI {
39 namespace {
40 constexpr int32_t MIN_MULTI_TOUCH_POINT_NUM { 0 };
41 constexpr int32_t MAX_MULTI_TOUCH_POINT_NUM { 10 };
42 constexpr int32_t UNKNOWN_MULTI_TOUCH_POINT_NUM { -1 };
43 constexpr std::uintmax_t MAX_SIZE_OF_INPUT_PRODUCT_CONFIG { 4096 };
44 }
45
OnConnected(const IfMMIClient & client)46 void OnConnected(const IfMMIClient& client)
47 {
48 CALL_DEBUG_ENTER;
49 InputMgrImpl.OnConnected();
50 INPUT_DEVICE_IMPL.OnConnected();
51 #ifdef OHOS_BUILD_ENABLE_KEYBOARD
52 KeyEventInputSubscribeMgr.OnConnected();
53 #endif // OHOS_BUILD_ENABLE_KEYBOARD
54 #ifdef OHOS_BUILD_ENABLE_SWITCH
55 SWITCH_EVENT_INPUT_SUBSCRIBE_MGR.OnConnected();
56 #endif // OHOS_BUILD_ENABLE_SWITCH
57 TABLET_EVENT_INPUT_SUBSCRIBE_MGR.OnConnected();
58 #ifdef OHOS_BUILD_ENABLE_MONITOR
59 IMonitorMgr.OnConnected();
60 PRE_MONITOR_MGR.OnConnected();
61 #endif // OHOS_BUILD_ENABLE_MONITOR
62 #ifdef OHOS_BUILD_ENABLE_INTERCEPTOR
63 InputInterMgr->OnConnected();
64 #endif // OHOS_BUILD_ENABLE_INTERCEPTOR
65 INPUT_ACTIVE_SUBSCRIBE_MGR.OnConnected();
66 DEVICE_CONSUMER.OnConnected();
67 }
68
OnDisconnected(const IfMMIClient & client)69 void OnDisconnected(const IfMMIClient &client)
70 {
71 CALL_DEBUG_ENTER;
72 InputMgrImpl.OnDisconnected();
73 INPUT_DEVICE_IMPL.OnDisconnected();
74 #ifdef OHOS_BUILD_ENABLE_MONITOR
75 IMonitorMgr.OnDisconnected();
76 #endif // OHOS_BUILD_ENABLE_MONITOR
77 }
78
MultimodalEventHandler()79 MultimodalEventHandler::MultimodalEventHandler() {}
~MultimodalEventHandler()80 MultimodalEventHandler::~MultimodalEventHandler() {}
81
82 #ifdef OHOS_BUILD_ENABLE_KEYBOARD
SubscribeKeyEvent(const KeyEventInputSubscribeManager::SubscribeKeyEventInfo & subscribeInfo)83 int32_t MultimodalEventHandler::SubscribeKeyEvent(
84 const KeyEventInputSubscribeManager::SubscribeKeyEventInfo &subscribeInfo)
85 {
86 CALL_DEBUG_ENTER;
87 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
88 return MULTIMODAL_INPUT_CONNECT_MGR->SubscribeKeyEvent(subscribeInfo.GetSubscribeId(),
89 subscribeInfo.GetKeyOption());
90 }
91
UnsubscribeKeyEvent(int32_t subscribeId)92 int32_t MultimodalEventHandler::UnsubscribeKeyEvent(int32_t subscribeId)
93 {
94 CALL_DEBUG_ENTER;
95 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
96 return MULTIMODAL_INPUT_CONNECT_MGR->UnsubscribeKeyEvent(subscribeId);
97 }
98
SubscribeHotkey(const KeyEventInputSubscribeManager::SubscribeKeyEventInfo & subscribeInfo)99 int32_t MultimodalEventHandler::SubscribeHotkey(
100 const KeyEventInputSubscribeManager::SubscribeKeyEventInfo &subscribeInfo)
101 {
102 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
103 return MULTIMODAL_INPUT_CONNECT_MGR->SubscribeHotkey(
104 subscribeInfo.GetSubscribeId(), subscribeInfo.GetKeyOption());
105 }
106
UnsubscribeHotkey(int32_t subscribeId)107 int32_t MultimodalEventHandler::UnsubscribeHotkey(int32_t subscribeId)
108 {
109 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
110 return MULTIMODAL_INPUT_CONNECT_MGR->UnsubscribeHotkey(subscribeId);
111 }
112
InjectEvent(const std::shared_ptr<KeyEvent> keyEvent,bool isNativeInject)113 int32_t MultimodalEventHandler::InjectEvent(const std::shared_ptr<KeyEvent> keyEvent, bool isNativeInject)
114 {
115 CALL_DEBUG_ENTER;
116 CHKPR(keyEvent, ERROR_NULL_POINTER);
117 EndLogTraceId(keyEvent->GetId());
118 keyEvent->UpdateId();
119 LogTracer lt(keyEvent->GetId(), keyEvent->GetEventType(), keyEvent->GetKeyAction());
120 if (keyEvent->GetKeyCode() < 0) {
121 if (EventLogHelper::IsBetaVersion()) {
122 MMI_HILOGE("KeyCode is invalid:%{private}u", keyEvent->GetKeyCode());
123 }
124 return RET_ERR;
125 }
126 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
127 int32_t ret = MULTIMODAL_INPUT_CONNECT_MGR->InjectKeyEvent(keyEvent, isNativeInject);
128 if (ret != 0) {
129 MMI_HILOGE("Send to server failed, ret:%{public}d", ret);
130 return RET_ERR;
131 }
132 return RET_OK;
133 }
134 #endif // OHOS_BUILD_ENABLE_KEYBOARD
135
136 #ifdef OHOS_BUILD_ENABLE_KEY_PRESSED_HANDLER
SubscribeKeyMonitor(const KeyMonitorOption & keyOption)137 int32_t MultimodalEventHandler::SubscribeKeyMonitor(const KeyMonitorOption &keyOption)
138 {
139 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
140 return MULTIMODAL_INPUT_CONNECT_MGR->SubscribeKeyMonitor(keyOption);
141 }
142
UnsubscribeKeyMonitor(const KeyMonitorOption & keyOption)143 int32_t MultimodalEventHandler::UnsubscribeKeyMonitor(const KeyMonitorOption &keyOption)
144 {
145 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
146 return MULTIMODAL_INPUT_CONNECT_MGR->UnsubscribeKeyMonitor(keyOption);
147 }
148 #endif // OHOS_BUILD_ENABLE_KEY_PRESSED_HANDLER
149
150 #ifdef OHOS_BUILD_ENABLE_SWITCH
SubscribeSwitchEvent(int32_t subscribeId,int32_t switchType)151 int32_t MultimodalEventHandler::SubscribeSwitchEvent(int32_t subscribeId, int32_t switchType)
152 {
153 CALL_DEBUG_ENTER;
154 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
155 return MULTIMODAL_INPUT_CONNECT_MGR->SubscribeSwitchEvent(subscribeId, switchType);
156 }
157
UnsubscribeSwitchEvent(int32_t subscribeId)158 int32_t MultimodalEventHandler::UnsubscribeSwitchEvent(int32_t subscribeId)
159 {
160 CALL_DEBUG_ENTER;
161 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
162 return MULTIMODAL_INPUT_CONNECT_MGR->UnsubscribeSwitchEvent(subscribeId);
163 }
164 #endif // OHOS_BUILD_ENABLE_SWITCH
165
SubscribeTabletProximity(int32_t subscribeId)166 int32_t MultimodalEventHandler::SubscribeTabletProximity(int32_t subscribeId)
167 {
168 CALL_DEBUG_ENTER;
169 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
170 return MULTIMODAL_INPUT_CONNECT_MGR->SubscribeTabletProximity(subscribeId);
171 }
172
UnsubscribetabletProximity(int32_t subscribeId)173 int32_t MultimodalEventHandler::UnsubscribetabletProximity(int32_t subscribeId)
174 {
175 CALL_DEBUG_ENTER;
176 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
177 return MULTIMODAL_INPUT_CONNECT_MGR->UnsubscribetabletProximity(subscribeId);
178 }
179
SubscribeLongPressEvent(int32_t subscribeId,const LongPressRequest & longPressRequest)180 int32_t MultimodalEventHandler::SubscribeLongPressEvent(int32_t subscribeId,
181 const LongPressRequest &longPressRequest)
182 {
183 CALL_DEBUG_ENTER;
184 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
185 return MULTIMODAL_INPUT_CONNECT_MGR->SubscribeLongPressEvent(subscribeId, longPressRequest);
186 }
187
UnsubscribeLongPressEvent(int32_t subscribeId)188 int32_t MultimodalEventHandler::UnsubscribeLongPressEvent(int32_t subscribeId)
189 {
190 CALL_DEBUG_ENTER;
191 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
192 return MULTIMODAL_INPUT_CONNECT_MGR->UnsubscribeLongPressEvent(subscribeId);
193 }
194
InitClient(EventHandlerPtr eventHandler)195 bool MultimodalEventHandler::InitClient(EventHandlerPtr eventHandler)
196 {
197 CALL_DEBUG_ENTER;
198 std::lock_guard<std::mutex> guard(mtx_);
199 if (client_ != nullptr) {
200 if (eventHandler != nullptr) {
201 client_->MarkIsEventHandlerChanged(eventHandler);
202 }
203 return true;
204 }
205 client_ = std::make_shared<MMIClient>();
206 client_->SetEventHandler(eventHandler);
207 client_->RegisterConnectedFunction(&OnConnected);
208 client_->RegisterDisconnectedFunction(&OnDisconnected);
209 if (!client_->Start()) {
210 client_ = nullptr;
211 MMI_HILOGE("The client fails to start");
212 return false;
213 }
214 EventHandlerPtr eventHandlerPtr = client_->GetEventHandler();
215 CHKPF(eventHandlerPtr);
216 if (!eventHandlerPtr->PostTask([this] { SetClientInfo(GetPid(), GetThisThreadId()); })) {
217 MMI_HILOGE("Send reconnect event failed");
218 return false;
219 }
220 return true;
221 }
222
GetMMIClient()223 MMIClientPtr MultimodalEventHandler::GetMMIClient()
224 {
225 std::lock_guard<std::mutex> guard(mtx_);
226 CHKPP(client_);
227 return client_->GetSharedPtr();
228 }
229
230 #if defined(OHOS_BUILD_ENABLE_POINTER) || defined(OHOS_BUILD_ENABLE_TOUCH)
InjectPointerEvent(std::shared_ptr<PointerEvent> pointerEvent,bool isNativeInject,int32_t useCoordinate)231 int32_t MultimodalEventHandler::InjectPointerEvent(std::shared_ptr<PointerEvent> pointerEvent, bool isNativeInject,
232 int32_t useCoordinate)
233 {
234 CHKPR(pointerEvent, ERROR_NULL_POINTER);
235 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
236 int32_t ret = MULTIMODAL_INPUT_CONNECT_MGR->InjectPointerEvent(pointerEvent, isNativeInject, useCoordinate);
237 if (ret != 0) {
238 MMI_HILOGE("Send to server failed, ret:%{public}d", ret);
239 return RET_ERR;
240 }
241 return RET_OK;
242 }
243 #endif // OHOS_BUILD_ENABLE_POINTER || OHOS_BUILD_ENABLE_TOUCH
244
245 #if defined(OHOS_BUILD_ENABLE_POINTER) || defined(OHOS_BUILD_ENABLE_TOUCH)
InjectTouchPadEvent(std::shared_ptr<PointerEvent> pointerEvent,const TouchpadCDG & touchpadCDG,bool isNativeInject)246 int32_t MultimodalEventHandler::InjectTouchPadEvent(std::shared_ptr<PointerEvent> pointerEvent,
247 const TouchpadCDG &touchpadCDG, bool isNativeInject)
248 {
249 CHKPR(pointerEvent, ERROR_NULL_POINTER);
250 EventLogHelper::PrintEventData(pointerEvent, MMI_LOG_HEADER);
251 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
252 int32_t ret = MULTIMODAL_INPUT_CONNECT_MGR->InjectTouchPadEvent(pointerEvent, touchpadCDG, isNativeInject);
253 if (ret != 0) {
254 MMI_HILOGE("Send to server failed, ret:%{public}d", ret);
255 return RET_ERR;
256 }
257 return RET_OK;
258 }
259 #endif // OHOS_BUILD_ENABLE_POINTER || OHOS_BUILD_ENABLE_TOUCH
260
261 #if defined(OHOS_BUILD_ENABLE_POINTER) && defined(OHOS_BUILD_ENABLE_POINTER_DRAWING)
MoveMouseEvent(int32_t offsetX,int32_t offsetY)262 int32_t MultimodalEventHandler::MoveMouseEvent(int32_t offsetX, int32_t offsetY)
263 {
264 CALL_DEBUG_ENTER;
265 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
266 int32_t ret = MULTIMODAL_INPUT_CONNECT_MGR->MoveMouseEvent(offsetX, offsetY);
267 if (ret != 0) {
268 MMI_HILOGE("Send to server failed, ret:%{public}d", ret);
269 return RET_ERR;
270 }
271 return RET_OK;
272 }
273 #endif // OHOS_BUILD_ENABLE_POINTER && OHOS_BUILD_ENABLE_POINTER_DRAWING
274
Authorize(bool isAuthorize)275 int32_t MultimodalEventHandler::Authorize(bool isAuthorize)
276 {
277 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
278 int32_t ret = MULTIMODAL_INPUT_CONNECT_MGR->Authorize(isAuthorize);
279 if (ret != RET_OK) {
280 MMI_HILOGE("Send to server failed, ret:%{public}d", ret);
281 return RET_ERR;
282 }
283 return RET_OK;
284 }
285
CancelInjection()286 int32_t MultimodalEventHandler::CancelInjection()
287 {
288 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
289 int32_t ret = MULTIMODAL_INPUT_CONNECT_MGR->CancelInjection();
290 if (ret != RET_OK) {
291 MMI_HILOGE("Send to server failed, ret:%{public}d", ret);
292 return RET_ERR;
293 }
294 return RET_OK;
295 }
296
SetClientInfo(int32_t pid,uint64_t readThreadId)297 int32_t MultimodalEventHandler::SetClientInfo(int32_t pid, uint64_t readThreadId)
298 {
299 CALL_DEBUG_ENTER;
300 CHKPR(MULTIMODAL_INPUT_CONNECT_MGR, RET_ERR);
301 return MULTIMODAL_INPUT_CONNECT_MGR->SetClientInfo(pid, readThreadId);
302 }
303
ReadMaxTouchPoints(cJSON * jsonProductCfg,int32_t & maxMultiTouchPointNum)304 static void ReadMaxTouchPoints(cJSON *jsonProductCfg, int32_t &maxMultiTouchPointNum)
305 {
306 if (!cJSON_IsObject(jsonProductCfg)) {
307 MMI_HILOGE("Not json format");
308 return;
309 }
310 cJSON *jsonTouchscreen = cJSON_GetObjectItemCaseSensitive(jsonProductCfg, "touchscreen");
311 if (!cJSON_IsObject(jsonTouchscreen)) {
312 MMI_HILOGE("The jsonTouchscreen is not object");
313 return;
314 }
315 cJSON *jsonMaxTouchPoints = cJSON_GetObjectItemCaseSensitive(jsonTouchscreen, "MaxTouchPoints");
316 if (!cJSON_IsNumber(jsonMaxTouchPoints)) {
317 MMI_HILOGE("The jsonMaxTouchPoints is not number");
318 return;
319 }
320 auto sMaxTouchPoints = std::unique_ptr<char, std::function<void(char *)>>(
321 cJSON_Print(jsonMaxTouchPoints),
322 [](char *sMaxTouchPoints) {
323 if (sMaxTouchPoints != nullptr) {
324 cJSON_free(sMaxTouchPoints);
325 }
326 });
327 CHKPV(sMaxTouchPoints);
328 MMI_HILOGI("Config of touchscreen.MaxTouchPoints:%{public}s", sMaxTouchPoints.get());
329 if (!IsInteger(sMaxTouchPoints.get())) {
330 MMI_HILOGE("Config of touchscreen.MaxTouchPoints is not integer");
331 return;
332 }
333 auto num = static_cast<int32_t>(cJSON_GetNumberValue(jsonMaxTouchPoints));
334 if ((num < MIN_MULTI_TOUCH_POINT_NUM) || (num > MAX_MULTI_TOUCH_POINT_NUM)) {
335 MMI_HILOGW("Invalid config: MaxTouchPoints(%{public}d) is out of range[%{public}d, %{public}d]",
336 num, MIN_MULTI_TOUCH_POINT_NUM, MAX_MULTI_TOUCH_POINT_NUM);
337 return;
338 }
339 maxMultiTouchPointNum = num;
340 MMI_HILOGI("touchscreen.MaxTouchPoints:%{public}d", maxMultiTouchPointNum);
341 }
342
ReadMaxTouchPoints(std::ifstream & ifs,int32_t & maxMultiTouchPointNum)343 static void ReadMaxTouchPoints(std::ifstream &ifs, int32_t &maxMultiTouchPointNum)
344 {
345 std::string cfg { std::istream_iterator<char>(ifs), std::istream_iterator<char>() };
346 auto jsonProductCfg = std::unique_ptr<cJSON, std::function<void(cJSON *)>>(
347 cJSON_Parse(cfg.c_str()),
348 [](cJSON *productCfg) {
349 if (productCfg != nullptr) {
350 cJSON_Delete(productCfg);
351 }
352 });
353 CHKPV(jsonProductCfg);
354 ReadMaxTouchPoints(jsonProductCfg.get(), maxMultiTouchPointNum);
355 }
356
ReadMaxTouchPoints(const char * cfgPath,int32_t & maxMultiTouchPointNum)357 static void ReadMaxTouchPoints(const char *cfgPath, int32_t &maxMultiTouchPointNum)
358 {
359 std::error_code ec {};
360 auto fsize = std::filesystem::file_size(cfgPath, ec);
361 if (ec || (fsize > MAX_SIZE_OF_INPUT_PRODUCT_CONFIG)) {
362 MMI_HILOGE("Unexpected size of InputProductConfig");
363 return;
364 }
365 std::ifstream ifs(cfgPath);
366 if (!ifs.is_open()) {
367 MMI_HILOGE("Can not open config");
368 return;
369 }
370 ReadMaxTouchPoints(ifs, maxMultiTouchPointNum);
371 ifs.close();
372 }
373
ReadMaxMultiTouchPointNum(int32_t & maxMultiTouchPointNum)374 void MultimodalEventHandler::ReadMaxMultiTouchPointNum(int32_t &maxMultiTouchPointNum)
375 {
376 maxMultiTouchPointNum = -1;
377 char cfgName[] { "etc/input/input_product_config.json" };
378 char buf[MAX_PATH_LEN] {};
379 char *cfgPath = ::GetOneCfgFile(cfgName, buf, sizeof(buf));
380 if (cfgPath == nullptr) {
381 MMI_HILOGE("No input product config was found");
382 return;
383 }
384 auto realPath = std::unique_ptr<char, std::function<void(char *)>>(
385 ::realpath(cfgPath, nullptr),
386 [](auto arr) {
387 if (arr != nullptr) {
388 ::free(arr);
389 }
390 });
391 if (realPath == nullptr) {
392 MMI_HILOGI("No input product config");
393 return;
394 }
395 ReadMaxTouchPoints(realPath.get(), maxMultiTouchPointNum);
396 }
397
GetMaxMultiTouchPointNum(int32_t & pointNum)398 int32_t MultimodalEventHandler::GetMaxMultiTouchPointNum(int32_t &pointNum)
399 {
400 static int32_t maxMultiTouchPointNum { UNKNOWN_MULTI_TOUCH_POINT_NUM };
401 static std::once_flag flag;
402
403 std::call_once(flag, []() {
404 ReadMaxMultiTouchPointNum(maxMultiTouchPointNum);
405 });
406 if (maxMultiTouchPointNum < 0) {
407 pointNum = UNKNOWN_MULTI_TOUCH_POINT_NUM;
408 return MMI_ERR_NO_PRODUCT_CONFIG;
409 }
410 pointNum = maxMultiTouchPointNum;
411 return RET_OK;
412 }
413 } // namespace MMI
414 } // namespace OHOS
415