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