1 /*
2 * Copyright (c) 2023 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 #include "intention_event_manager.h"
16
17 #ifdef IMF_ENABLE
18 #include <input_method_controller.h>
19 #endif // IMF_ENABLE
20 #include "scene_session.h"
21 #include "session_helper.h"
22 #include "session_manager/include/scene_session_manager.h"
23 #include "window_manager_hilog.h"
24 #include <hitrace_meter.h>
25 #include "parameters.h"
26 #include "xcollie/xcollie.h"
27
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "IntentionEventManager" };
32 constexpr int32_t TRANSPARENT_FINGER_ID = 10000;
33 std::shared_ptr<MMI::PointerEvent> g_lastMouseEvent = nullptr;
34 int32_t g_lastLeaveWindowId = -1;
35 constexpr int32_t DELAY_TIME = 15;
36 constexpr unsigned int FREQUENT_CLICK_TIME_LIMIT = 3;
37 constexpr int FREQUENT_CLICK_COUNT_LIMIT = 8;
38 static const bool IS_BETA = OHOS::system::GetParameter("const.logsystem.versiontype", "").find("beta") !=
39 std::string::npos;
40
LogPointInfo(const std::shared_ptr<MMI::PointerEvent> & pointerEvent)41 void LogPointInfo(const std::shared_ptr<MMI::PointerEvent>& pointerEvent)
42 {
43 if (pointerEvent == nullptr) {
44 return;
45 }
46
47 uint32_t windowId = static_cast<uint32_t>(pointerEvent->GetTargetWindowId());
48 TLOGD(WmsLogTag::WMS_EVENT, "point source:%{public}d", pointerEvent->GetSourceType());
49 auto actionId = pointerEvent->GetPointerId();
50 int32_t action = pointerEvent->GetPointerAction();
51 if (action == MMI::PointerEvent::POINTER_ACTION_MOVE) {
52 return;
53 }
54
55 MMI::PointerEvent::PointerItem item;
56 if (pointerEvent->GetPointerItem(actionId, item)) {
57 TLOGD(WmsLogTag::WMS_EVENT, "action point info:windowid:%{public}d,id:%{public}d,displayx:%{private}d,"
58 "displayy:%{private}d,windowx:%{private}d,windowy:%{private}d,action:%{public}d pressure:"
59 "%{public}f,tiltx:%{public}f,tiltY:%{public}f",
60 windowId, actionId, item.GetDisplayX(), item.GetDisplayY(), item.GetWindowX(), item.GetWindowY(),
61 pointerEvent->GetPointerAction(), item.GetPressure(), item.GetTiltX(), item.GetTiltY());
62 }
63 auto ids = pointerEvent->GetPointerIds();
64 for (auto&& id :ids) {
65 MMI::PointerEvent::PointerItem item;
66 if (pointerEvent->GetPointerItem(id, item)) {
67 TLOGD(WmsLogTag::WMS_EVENT, "all point info: id:%{public}d,x:%{private}d,y:%{private}d,"
68 "isPressend:%{public}d,pressure:%{public}f,tiltX:%{public}f,tiltY:%{public}f",
69 actionId, item.GetWindowX(), item.GetWindowY(), item.IsPressed(), item.GetPressure(),
70 item.GetTiltX(), item.GetTiltY());
71 }
72 }
73 }
74 } // namespace
75
IntentionEventManager()76 IntentionEventManager::IntentionEventManager() {}
~IntentionEventManager()77 IntentionEventManager::~IntentionEventManager() {}
78
~InputEventListener()79 IntentionEventManager::InputEventListener::~InputEventListener()
80 {
81 std::lock_guard<std::mutex> guard(mouseEventMutex_);
82 g_lastMouseEvent = nullptr;
83 }
84
EnableInputEventListener(Ace::UIContent * uiContent,std::shared_ptr<AppExecFwk::EventHandler> eventHandler)85 bool IntentionEventManager::EnableInputEventListener(Ace::UIContent* uiContent,
86 std::shared_ptr<AppExecFwk::EventHandler> eventHandler)
87 {
88 if (uiContent == nullptr) {
89 TLOGE(WmsLogTag::WMS_EVENT, "EnableInputEventListener uiContent is null");
90 return false;
91 }
92 if (eventHandler == nullptr) {
93 TLOGE(WmsLogTag::WMS_EVENT, "EnableInputEventListener eventHandler is null");
94 return false;
95 }
96 auto listener =
97 std::make_shared<IntentionEventManager::InputEventListener>(uiContent, eventHandler);
98 MMI::InputManager::GetInstance()->SetWindowInputEventConsumer(listener, eventHandler);
99 TLOGI(WmsLogTag::WMS_EVENT, "SetWindowInputEventConsumer success");
100 if (IS_BETA) {
101 // Xcollie's SetTimerCounter task is set with the params to record count and time of the input down event
102 int id = HiviewDFX::XCollie::GetInstance().SetTimerCount("FREQUENT_CLICK_WARNING", FREQUENT_CLICK_TIME_LIMIT,
103 FREQUENT_CLICK_COUNT_LIMIT);
104 }
105 return true;
106 }
107
UpdateLastMouseEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const108 void IntentionEventManager::InputEventListener::UpdateLastMouseEvent(
109 std::shared_ptr<MMI::PointerEvent> pointerEvent) const
110 {
111 if (pointerEvent == nullptr) {
112 TLOGE(WmsLogTag::WMS_EVENT, "UpdateLastMouseEvent pointerEvent is null");
113 return;
114 }
115 g_lastLeaveWindowId = -1;
116 if ((pointerEvent->GetSourceType() == MMI::PointerEvent::SOURCE_TYPE_MOUSE) &&
117 (pointerEvent->GetPointerAction() != MMI::PointerEvent::POINTER_ACTION_LEAVE_WINDOW)) {
118 std::lock_guard<std::mutex> guard(mouseEventMutex_);
119 g_lastMouseEvent = std::make_shared<MMI::PointerEvent>(*pointerEvent);
120 } else if (g_lastMouseEvent != nullptr) {
121 TLOGD(WmsLogTag::WMS_EVENT, "Clear last mouse event");
122 std::lock_guard<std::mutex> guard(mouseEventMutex_);
123 g_lastMouseEvent = nullptr;
124 SceneSession::ClearEnterWindow();
125 }
126 }
127
CheckPointerEvent(const std::shared_ptr<MMI::PointerEvent> pointerEvent) const128 bool IntentionEventManager::InputEventListener::CheckPointerEvent(
129 const std::shared_ptr<MMI::PointerEvent> pointerEvent) const
130 {
131 if (pointerEvent == nullptr) {
132 TLOGE(WmsLogTag::WMS_EVENT, "pointerEvent is null");
133 return false;
134 }
135 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IEM:PointerEvent id:%d action:%d",
136 pointerEvent->GetId(), pointerEvent->GetPointerAction());
137 if (uiContent_ == nullptr) {
138 TLOGE(WmsLogTag::WMS_EVENT, "uiContent_ is null");
139 pointerEvent->MarkProcessed();
140 return false;
141 }
142 if (!SceneSessionManager::GetInstance().IsInputEventEnabled()) {
143 TLOGW(WmsLogTag::WMS_EVENT, "inputEvent is disabled temporarily, eventId is %{public}d", pointerEvent->GetId());
144 pointerEvent->MarkProcessed();
145 return false;
146 }
147 return true;
148 }
149
OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const150 void IntentionEventManager::InputEventListener::OnInputEvent(
151 std::shared_ptr<MMI::PointerEvent> pointerEvent) const
152 {
153 if (!CheckPointerEvent(pointerEvent)) {
154 return;
155 }
156 LogPointInfo(pointerEvent);
157 int32_t action = pointerEvent->GetPointerAction();
158 uint32_t windowId = static_cast<uint32_t>(pointerEvent->GetTargetWindowId());
159 auto sceneSession = SceneSessionManager::GetInstance().GetSceneSession(windowId);
160 if (sceneSession == nullptr) {
161 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "The scene session is nullptr");
162 pointerEvent->MarkProcessed();
163 return;
164 }
165 auto dispatchTimes = pointerEvent->GetDispatchTimes();
166 if (dispatchTimes > 0) {
167 MMI::PointerEvent::PointerItem pointerItem;
168 auto pointerId = pointerEvent->GetPointerId();
169 if (pointerEvent->GetPointerItem(pointerId, pointerItem)) {
170 pointerItem.SetPointerId(pointerId + dispatchTimes * TRANSPARENT_FINGER_ID);
171 pointerEvent->UpdatePointerItem(pointerId, pointerItem);
172 pointerEvent->SetPointerId(pointerId + dispatchTimes * TRANSPARENT_FINGER_ID);
173 }
174 }
175 if (action != MMI::PointerEvent::POINTER_ACTION_MOVE) {
176 static uint32_t eventId = 0;
177 TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "eid:%{public}d,InputId:%{public}d,wid:%{public}u"
178 ",windowName:%{public}s,action:%{public}d,isSystem:%{public}d", eventId++, pointerEvent->GetId(), windowId,
179 sceneSession->GetSessionInfo().abilityName_.c_str(), action, sceneSession->GetSessionInfo().isSystem_);
180 }
181 if (sceneSession->GetSessionInfo().isSystem_) {
182 sceneSession->SendPointerEventToUI(pointerEvent);
183 // notify touchOutside and touchDown event
184 if (action == MMI::PointerEvent::POINTER_ACTION_DOWN ||
185 action == MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN) {
186 MMI::PointerEvent::PointerItem pointerItem;
187 if (pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), pointerItem)) {
188 sceneSession->ProcessPointDownSession(pointerItem.GetDisplayX(), pointerItem.GetDisplayY());
189 }
190 if (IS_BETA) {
191 /*
192 * Triggers input down event recorded.
193 * If the special num of the events reached within the sepcial time interval,
194 * a panic behavior is reported.
195 */
196 HiviewDFX::XCollie::GetInstance().TriggerTimerCount("FREQUENT_CLICK_WARNING", true, "");
197 }
198 }
199 } else {
200 // transfer pointer event for move and drag
201 WSError ret = sceneSession->TransferPointerEvent(pointerEvent);
202 if (sceneSession->GetWindowType() == WindowType::WINDOW_TYPE_SYSTEM_FLOAT) {
203 sceneSession->NotifyOutsideDownEvent(pointerEvent);
204 }
205 if ((ret != WSError::WS_OK || static_cast<int32_t>(getprocpid()) != sceneSession->GetCallingPid()) &&
206 pointerEvent != nullptr) {
207 pointerEvent->MarkProcessed();
208 }
209 }
210 UpdateLastMouseEvent(pointerEvent);
211 }
212
DispatchKeyEventCallback(int32_t focusedSessionId,std::shared_ptr<MMI::KeyEvent> keyEvent,bool consumed) const213 void IntentionEventManager::InputEventListener::DispatchKeyEventCallback(
214 int32_t focusedSessionId, std::shared_ptr<MMI::KeyEvent> keyEvent, bool consumed) const
215 {
216 if (keyEvent == nullptr) {
217 WLOGFW("keyEvent is null, focusedSessionId:%{public}" PRId32
218 ", consumed:%{public}" PRId32, focusedSessionId, consumed);
219 return;
220 }
221
222 if (consumed) {
223 WLOGD("Input method has processed key event, id:%{public}" PRId32 ", focusedSessionId:%{public}" PRId32,
224 keyEvent->GetId(), focusedSessionId);
225 return;
226 }
227
228 auto focusedSceneSession = SceneSessionManager::GetInstance().GetSceneSession(focusedSessionId);
229 if (focusedSceneSession == nullptr) {
230 WLOGFE("focusedSceneSession is null");
231 keyEvent->MarkProcessed();
232 return;
233 }
234
235 if (uiContent_ == nullptr) {
236 WLOGFE("uiContent_ is null");
237 keyEvent->MarkProcessed();
238 return;
239 }
240
241 focusedSceneSession->SendKeyEventToUI(keyEvent);
242 }
243
OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const244 void IntentionEventManager::InputEventListener::OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const
245 {
246 if (keyEvent == nullptr) {
247 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "The key event is nullptr");
248 return;
249 }
250 HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IEM:KeyEvent id:%d", keyEvent->GetId());
251 if (!SceneSessionManager::GetInstance().IsInputEventEnabled()) {
252 TLOGD(WmsLogTag::WMS_INPUT_KEY_FLOW, "OnInputEvent is disabled temporarily");
253 keyEvent->MarkProcessed();
254 return;
255 }
256 auto focusedSessionId = SceneSessionManager::GetInstance().GetFocusedSessionId();
257 if (focusedSessionId == INVALID_SESSION_ID) {
258 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "focusedSessionId is invalid");
259 keyEvent->MarkProcessed();
260 return;
261 }
262 auto focusedSceneSession = SceneSessionManager::GetInstance().GetSceneSession(focusedSessionId);
263 if (focusedSceneSession == nullptr) {
264 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "focusedSceneSession is null");
265 keyEvent->MarkProcessed();
266 return;
267 }
268 auto isSystem = focusedSceneSession->GetSessionInfo().isSystem_;
269 static uint32_t eventId = 0;
270 TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "eid:%{public}d,InputId:%{public}d,wid:%{public}u"
271 ",focusId:%{public}d,isSystem:%{public}d",
272 eventId++, keyEvent->GetId(), keyEvent->GetTargetWindowId(), focusedSessionId, isSystem);
273 if (!isSystem) {
274 WSError ret = focusedSceneSession->TransferKeyEvent(keyEvent);
275 if ((ret != WSError::WS_OK || static_cast<int32_t>(getprocpid()) != focusedSceneSession->GetCallingPid()) &&
276 keyEvent != nullptr) {
277 keyEvent->MarkProcessed();
278 }
279 return;
280 }
281 bool isConsumed = focusedSceneSession->SendKeyEventToUI(keyEvent, true);
282 if (isConsumed) {
283 TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "SendKeyEventToUI id:%{public}d isConsumed:%{public}d",
284 keyEvent->GetId(), static_cast<int>(isConsumed));
285 return;
286 }
287 #ifdef IMF_ENABLE
288 bool isKeyboardEvent = IsKeyboardEvent(keyEvent);
289 if (isKeyboardEvent) {
290 WLOGD("Async dispatch keyEvent to input method");
291 auto callback = [this, focusedSessionId] (std::shared_ptr<MMI::KeyEvent>& keyEvent, bool consumed) {
292 this->DispatchKeyEventCallback(focusedSessionId, keyEvent, consumed);
293 };
294 auto ret = MiscServices::InputMethodController::GetInstance()->DispatchKeyEvent(keyEvent, callback);
295 if (ret != 0) {
296 WLOGFE("DispatchKeyEvent failed, ret:%{public}d, id:%{public}d, focusedSessionId:%{public}d",
297 ret, keyEvent->GetId(), focusedSessionId);
298 DispatchKeyEventCallback(focusedSessionId, keyEvent, false);
299 }
300 return;
301 }
302 #endif // IMF_ENABLE
303 TLOGD(WmsLogTag::WMS_INPUT_KEY_FLOW, "Syetem window scene, transfer key event to root scene");
304 if (uiContent_ == nullptr) {
305 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "uiContent_ is null");
306 keyEvent->MarkProcessed();
307 return;
308 }
309 focusedSceneSession->SendKeyEventToUI(keyEvent);
310 }
311
IsKeyboardEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent) const312 bool IntentionEventManager::InputEventListener::IsKeyboardEvent(
313 const std::shared_ptr<MMI::KeyEvent>& keyEvent) const
314 {
315 int32_t keyCode = keyEvent->GetKeyCode();
316 bool isKeyFN = (keyCode == MMI::KeyEvent::KEYCODE_FN);
317 bool isKeyBack = (keyCode == MMI::KeyEvent::KEYCODE_BACK);
318 bool isKeyboard = (keyCode >= MMI::KeyEvent::KEYCODE_0 && keyCode <= MMI::KeyEvent::KEYCODE_NUMPAD_RIGHT_PAREN);
319 bool isKeySound = (keyCode == MMI::KeyEvent::KEYCODE_SOUND);
320 TLOGI(WmsLogTag::WMS_EVENT, "isKeyFN: %{public}d, isKeyboard: %{public}d", isKeyFN, isKeyboard);
321 return (isKeyFN || isKeyboard || isKeyBack || isKeySound);
322 }
323
OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const324 void IntentionEventManager::InputEventListener::OnInputEvent(
325 std::shared_ptr<MMI::AxisEvent> axisEvent) const
326 {
327 if (axisEvent == nullptr) {
328 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "axisEvent is nullptr");
329 return;
330 }
331 if (uiContent_ == nullptr) {
332 TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "uiContent_ is null");
333 axisEvent->MarkProcessed();
334 return;
335 }
336 if (!(uiContent_->ProcessAxisEvent(axisEvent))) {
337 TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "The UI content consumes the axis event failed.");
338 axisEvent->MarkProcessed();
339 }
340 }
341 }
342 } // namespace OHOS::Rosen
343