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