• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "focus_event_handler.h"
16 
17 #include "core/components_ng/base/frame_node.h"
18 #include "core/components_ng/event/event_constants.h"
19 #include "core/components/theme/app_theme.h"
20 #include "core/event/focus_axis_event.h"
21 #include "core/event/key_event.h"
22 #include "core/pipeline_ng/pipeline_context.h"
23 #include "core/event/crown_event.h"
24 namespace OHOS::Ace::NG {
GetFocusIntension(const NonPointerEvent & event)25 FocusIntension FocusEvent::GetFocusIntension(const NonPointerEvent& event)
26 {
27     if (event.eventType != UIInputEventType::KEY) {
28         return FocusIntension::NONE;
29     }
30     const KeyEvent& keyEvent = static_cast<const KeyEvent&>(event);
31     if (keyEvent.isPreIme || keyEvent.action != KeyAction::DOWN) {
32         return FocusIntension::NONE;
33     }
34     // Arrow key event is used to trasfer focus regardless of its pressed keys
35     switch (keyEvent.code) {
36         case KeyCode::KEY_DPAD_UP:
37             return FocusIntension::UP;
38         case KeyCode::KEY_DPAD_DOWN:
39             return FocusIntension::DOWN;
40         case KeyCode::KEY_DPAD_LEFT:
41             return FocusIntension::LEFT;
42         case KeyCode::KEY_DPAD_RIGHT:
43             return FocusIntension::RIGHT;
44         default:;
45     }
46 
47     if (keyEvent.pressedCodes.size() != 1) {
48         return keyEvent.IsExactlyShiftWith(KeyCode::KEY_TAB) ? FocusIntension::SHIFT_TAB : FocusIntension::NONE;
49     }
50     switch (keyEvent.code) {
51         case KeyCode::KEY_TAB:
52             return FocusIntension::TAB;
53         case KeyCode::KEY_MOVE_HOME:
54             return FocusIntension::HOME;
55         case KeyCode::KEY_MOVE_END:
56             return FocusIntension::END;
57         case KeyCode::KEY_ENTER:
58         case KeyCode::KEY_NUMPAD_ENTER:
59             return FocusIntension::SELECT;
60         case KeyCode::KEY_SPACE:
61             return FocusIntension::SPACE;
62         default:;
63     }
64     return GetFocusIntensionFromKey(keyEvent.keyIntention);
65 }
66 
GetFocusIntensionFromKey(KeyIntention keyIntention)67 FocusIntension FocusEvent::GetFocusIntensionFromKey(KeyIntention keyIntention)
68 {
69     switch (keyIntention) {
70         case KeyIntention::INTENTION_SELECT:
71             return FocusIntension::SELECT;
72         case KeyIntention::INTENTION_ESCAPE:
73             return FocusIntension::ESC;
74         case KeyIntention::INTENTION_HOME:
75             return FocusIntension::HOME;
76         default:;
77             return FocusIntension::NONE;
78     }
79 }
80 
HasCustomKeyEventDispatch(const FocusEvent & event)81 bool FocusEventHandler::HasCustomKeyEventDispatch(const FocusEvent& event)
82 {
83     if (event.event.eventType != UIInputEventType::KEY) {
84         return false;
85     }
86     const KeyEvent& keyEvent = static_cast<const KeyEvent&>(event.event);
87     if (keyEvent.isPreIme) {
88         return false;
89     }
90     return GetOnKeyEventDispatchCallback() != nullptr;
91 }
92 
HandleCustomEventDispatch(const FocusEvent & event)93 bool FocusEventHandler::HandleCustomEventDispatch(const FocusEvent& event)
94 {
95     auto onKeyEventDispatchCallback = GetOnKeyEventDispatchCallback();
96     if (onKeyEventDispatchCallback) {
97         const KeyEvent& keyEvent = static_cast<const KeyEvent&>(event.event);
98         auto info = KeyEventInfo(keyEvent);
99         return onKeyEventDispatchCallback(info);
100     }
101     return false;
102 }
103 
OnFocusEvent(const FocusEvent & event)104 bool FocusEventHandler::OnFocusEvent(const FocusEvent& event)
105 {
106     if (!IsCurrentFocus()) {
107         TAG_LOGI(AceLogTag::ACE_FOCUS,
108             "node: %{public}s/%{public}d cannot handle key event because is not current focus",
109             GetFrameName().c_str(), GetFrameId());
110         return false;
111     }
112 
113     if (HasCustomKeyEventDispatch(event)) {
114         return HandleCustomEventDispatch(event);
115     }
116 
117     if (focusType_ == FocusType::SCOPE) {
118         return OnFocusEventScope(event);
119     }
120     if (focusType_ == FocusType::NODE) {
121         return OnFocusEventNode(event);
122     }
123     TAG_LOGW(AceLogTag::ACE_FOCUS, "Current node focus type: %{public}d is invalid.", focusType_);
124     return false;
125 }
126 
OnFocusEventScope(const FocusEvent & event)127 bool FocusEventHandler::OnFocusEventScope(const FocusEvent& event)
128 {
129     ACE_DCHECK(IsCurrentFocus());
130     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
131     if (lastFocusNode && lastFocusNode->OnFocusEvent(event)) {
132         TAG_LOGD(AceLogTag::ACE_FOCUS,
133             "OnKeyEvent: Node %{public}s/%{public}d will not handle Event(type:%{private}d). "
134             "Because its child %{public}s/%{public}d already has consumed this event.",
135             GetFrameName().c_str(), GetFrameId(), event.event.eventType, lastFocusNode->GetFrameName().c_str(),
136             lastFocusNode->GetFrameId());
137         return true;
138     }
139     return OnFocusEventNode(event);
140 }
141 
OnFocusEventNode(const FocusEvent & focusEvent)142 bool FocusEventHandler::OnFocusEventNode(const FocusEvent& focusEvent)
143 {
144     ACE_DCHECK(IsCurrentFocus());
145 
146     bool ret = false;
147     if (focusEvent.event.eventType == UIInputEventType::KEY) {
148         const KeyEvent& keyEvent = static_cast<const KeyEvent&>(focusEvent.event);
149         ret = HandleKeyEvent(keyEvent, focusEvent.intension);
150     }
151     if (focusEvent.event.eventType == UIInputEventType::FOCUS_AXIS) {
152         const FocusAxisEvent& focusAxisEvent = static_cast<const FocusAxisEvent&>(focusEvent.event);
153         return HandleFocusAxisEvent(focusAxisEvent);
154     }
155     if (focusEvent.event.eventType == UIInputEventType::CROWN) {
156         const CrownEvent& crownEvent = static_cast<const CrownEvent&>(focusEvent.event);
157         return HandleCrownEvent(crownEvent);
158     }
159 
160     auto keyProcessingMode = static_cast<KeyProcessingMode>(GetKeyProcessingMode());
161     if (keyProcessingMode == KeyProcessingMode::ANCESTOR_EVENT) {
162         return ret;
163     }
164     return ret ? true : HandleFocusTravel(focusEvent);
165 }
166 
GetKeyProcessingMode()167 int32_t FocusEventHandler::GetKeyProcessingMode()
168 {
169     auto frameNode = GetFrameNode();
170     CHECK_NULL_RETURN(frameNode, static_cast<int32_t>(KeyProcessingMode::FOCUS_NAVIGATION));
171     auto context = frameNode->GetContextRefPtr();
172     CHECK_NULL_RETURN(context, static_cast<int32_t>(KeyProcessingMode::FOCUS_NAVIGATION));
173     auto focusManager = context->GetOrCreateFocusManager();
174     CHECK_NULL_RETURN(focusManager, static_cast<int32_t>(KeyProcessingMode::FOCUS_NAVIGATION));
175     return static_cast<int32_t>(focusManager->GetKeyProcessingMode());
176 }
177 
HandleKeyEvent(const KeyEvent & event,FocusIntension intension)178 bool FocusEventHandler::HandleKeyEvent(const KeyEvent& event, FocusIntension intension)
179 {
180     // ReDispatch event will not be consumed again.
181     if (event.isRedispatch) {
182         return false;
183     }
184 
185     auto node = GetFrameNode();
186     CHECK_NULL_RETURN(node, false);
187     auto* pipeline = node->GetContext();
188     CHECK_NULL_RETURN(pipeline, false);
189     auto info = KeyEventInfo(event);
190     if (event.HasKey(KeyCode::KEY_META_LEFT) || event.HasKey(KeyCode::KEY_META_RIGHT)) {
191         info.SetMetaKey(1);
192     }
193     if (event.isPreIme) {
194         return OnKeyPreIme(info, event);
195     }
196 
197     bool retInternal = OnKeyEventNodeInternal(event);
198     bool retCallback = OnKeyEventNodeUser(info, event);
199     if (retInternal || retCallback) {
200         return true;
201     }
202     // Handle on click
203     auto appTheme = pipeline->GetTheme<AppTheme>();
204     CHECK_NULL_RETURN(appTheme, false);
205     if (!pipeline->GetIsFocusActive() && (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) ||
206                                              !appTheme->NeedFocusHandleClick())) {
207         return false;
208     }
209     if (intension == FocusIntension::SELECT && !IsTabStop()) {
210         intension = FocusIntension::SPACE;
211     }
212     auto ret = false;
213     if (intension == FocusIntension::SPACE) {
214         ret = OnClick(event);
215         TAG_LOGI(AceLogTag::ACE_FOCUS,
216             "OnClick: Node %{public}s/%{public}d handle KeyEvent("
217             SEC_PLD(%{private}d) ", %{public}d) return: %{public}d",
218             GetFrameName().c_str(), GetFrameId(), SEC_PARAM(event.code), event.action, ret);
219     }
220     return ret;
221 }
222 
HandleFocusAxisEvent(const FocusAxisEvent & event)223 bool FocusEventHandler::HandleFocusAxisEvent(const FocusAxisEvent& event)
224 {
225     auto node = GetFrameNode();
226     CHECK_NULL_RETURN(node, false);
227     auto* pipeline = node->GetContext();
228     CHECK_NULL_RETURN(pipeline, false);
229     auto onFocusAxisCallback = GetOnFocusAxisCallback();
230     CHECK_NULL_RETURN(onFocusAxisCallback, false);
231     auto info = FocusAxisEventInfo(event);
232     auto eventHub = node->GetOrCreateEventHub<EventHub>();
233     if (eventHub) {
234         auto targetImpl = eventHub->CreateGetEventTargetImpl();
235         info.SetTarget(targetImpl().value_or(EventTarget()));
236     }
237     onFocusAxisCallback(info);
238     return info.IsStopPropagation();
239 }
240 
HandleCrownEvent(const CrownEvent & CrownEvent)241 bool FocusEventHandler::HandleCrownEvent(const CrownEvent& CrownEvent)
242 {
243     ACE_DCHECK(IsCurrentFocus());
244     bool retCallback = false;
245     auto onCrownEventCallback = GetOnCrownCallback();
246     if (onCrownEventCallback) {
247         CrownEventInfo crownInfo(CrownEvent);
248         onCrownEventCallback(crownInfo);
249         retCallback = crownInfo.IsStopPropagation();
250         TAG_LOGI(AceLogTag::ACE_FOCUS,
251             "OnCrownEventUser: Node %{public}s/%{public}d handle CrownAction:%{public}d",
252             GetFrameName().c_str(), GetFrameId(), CrownEvent.action);
253     } else {
254         retCallback = ProcessOnCrownEventInternal(CrownEvent);
255         TAG_LOGI(AceLogTag::ACE_FOCUS,
256             "OnCrownEventInternal: Node %{public}s/%{public}d handle CrownAction:%{public}d",
257             GetFrameName().c_str(), GetFrameId(), CrownEvent.action);
258     }
259     return retCallback;
260 }
261 
ProcessOnCrownEventInternal(const CrownEvent & event)262 bool FocusEventHandler::ProcessOnCrownEventInternal(const CrownEvent& event)
263 {
264     bool result = false;
265     auto onCrownEventCallbackInternal = GetOnCrownEventInternal();
266     if (onCrownEventCallbackInternal) {
267         onCrownEventCallbackInternal(event);
268         result = true;
269     }
270     return result;
271 }
272 
OnKeyPreIme(KeyEventInfo & info,const KeyEvent & keyEvent)273 bool FocusEventHandler::OnKeyPreIme(KeyEventInfo& info, const KeyEvent& keyEvent)
274 {
275     TAG_LOGD(AceLogTag::ACE_FOCUS,
276         "node: %{public}s/%{public}d try to handle OnKeyPreIme by "
277         "code:%{private}d/action:%{public}d/isPreIme:%{public}d",
278         GetFrameName().c_str(), GetFrameId(), keyEvent.code, keyEvent.action, keyEvent.isPreIme);
279     auto onKeyPreIme = GetOnKeyPreIme();
280     if (onKeyPreIme) {
281         bool retPreIme = onKeyPreIme(info);
282         auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
283         auto eventManager = pipeline->GetEventManager();
284         if (eventManager) {
285             eventManager->SetIsKeyConsumed(retPreIme);
286         }
287         TAG_LOGI(AceLogTag::ACE_FOCUS, "node: %{public}s/%{public}d handle OnKeyPreIme",
288             GetFrameName().c_str(), GetFrameId());
289         return info.IsStopPropagation();
290     } else if (GetFrameName() == V2::UI_EXTENSION_COMPONENT_ETS_TAG ||
291                GetFrameName() == V2::EMBEDDED_COMPONENT_ETS_TAG ||
292                GetFrameName() == V2::DYNAMIC_COMPONENT_ETS_TAG) {
293         TAG_LOGI(AceLogTag::ACE_FOCUS, "node: %{public}s/%{public}d try to process OnKeyEventInternal",
294             GetFrameName().c_str(), GetFrameId());
295         return ProcessOnKeyEventInternal(keyEvent);
296     } else {
297         return false;
298     }
299 }
300 
OnClick(const KeyEvent & event)301 bool FocusEventHandler::OnClick(const KeyEvent& event)
302 {
303     auto onClickCallback = GetOnClickCallback();
304     if (onClickCallback) {
305         auto info = GestureEvent();
306         info.SetTimeStamp(event.timeStamp);
307         auto geometryNode = GetGeometryNode();
308         CHECK_NULL_RETURN(geometryNode, false);
309         auto rect = geometryNode->GetFrameRect();
310         auto centerToWindow = Offset((rect.Left() + rect.Right()) / 2, (rect.Top() + rect.Bottom()) / 2);
311         auto centerToNode = Offset((rect.Right() - rect.Left()) / 2, (rect.Bottom() - rect.Top()) / 2);
312         info.SetGlobalLocation(centerToWindow);
313         info.SetLocalLocation(centerToNode);
314         info.SetSourceDevice(event.sourceType);
315         info.SetDeviceId(event.deviceId);
316         info.SetInputEventType(InputEventType::KEYBOARD);
317         auto node = GetFrameNode();
318         CHECK_NULL_RETURN(node, false);
319         auto pipelineContext = node->GetContextRefPtr();
320         if (pipelineContext) {
321             auto windowOffset = pipelineContext->GetCurrentWindowRect().GetOffset() + centerToWindow;
322             auto globalWindowOffset = pipelineContext->GetGlobalDisplayWindowRect().GetOffset() + centerToWindow;
323             info.SetScreenLocation(windowOffset);
324             info.SetGlobalDisplayLocation(globalWindowOffset);
325         }
326         info.SetSourceTool(SourceTool::UNKNOWN);
327         info.SetPatternName(node->GetTag().c_str());
328         auto eventHub = node->GetOrCreateEventHub<EventHub>();
329         if (eventHub) {
330             auto targetImpl = eventHub->CreateGetEventTargetImpl();
331             info.SetTarget(targetImpl().value_or(EventTarget()));
332         }
333         info.SetTargetDisplayId(event.targetDisplayId);
334         onClickCallback(info);
335         return true;
336     }
337     return false;
338 }
339 
OnKeyEventNodeInternal(const KeyEvent & keyEvent)340 bool FocusEventHandler::OnKeyEventNodeInternal(const KeyEvent& keyEvent)
341 {
342     auto node = GetFrameNode();
343     CHECK_NULL_RETURN(node, false);
344     auto* pipeline = node->GetContext();
345     CHECK_NULL_RETURN(pipeline, false);
346     bool isBypassInner = keyEvent.IsKey({ KeyCode::KEY_TAB }) && pipeline && pipeline->IsTabJustTriggerOnKeyEvent();
347     auto retInternal = false;
348     if (isNodeNeedKey_) {
349         retInternal =  ProcessOnKeyEventInternal(keyEvent);
350         TAG_LOGI(AceLogTag::ACE_FOCUS,
351             "OnKeyEventInteral Node process self: Node %{public}s/%{public}d"
352             "handle KeyEvent(" SEC_PLD(%{private}d) ", %{public}d) "
353             "return: %{public}d",
354             GetFrameName().c_str(), GetFrameId(), SEC_PARAM(keyEvent.code), keyEvent.action, retInternal);
355         return retInternal;
356     }
357     if (!isBypassInner && !onKeyEventsInternal_.empty()) {
358         retInternal = ProcessOnKeyEventInternal(keyEvent);
359         TAG_LOGI(AceLogTag::ACE_FOCUS,
360             "OnKeyEventInteral: Node %{public}s/%{public}d"
361             "handle KeyEvent(" SEC_PLD(%{private}d) ", %{public}d) "
362             "return: %{public}d",
363             GetFrameName().c_str(), GetFrameId(), SEC_PARAM(keyEvent.code), keyEvent.action, retInternal);
364     }
365     return retInternal;
366 }
367 
OnKeyEventNodeUser(KeyEventInfo & info,const KeyEvent & keyEvent)368 bool FocusEventHandler::OnKeyEventNodeUser(KeyEventInfo& info, const KeyEvent& keyEvent)
369 {
370     auto node = GetFrameNode();
371     CHECK_NULL_RETURN(node, false);
372     auto* pipeline = node->GetContext();
373     CHECK_NULL_RETURN(pipeline, false);
374     auto retCallback = false;
375     auto onKeyEventCallback = GetOnKeyCallback();
376     if (onKeyEventCallback) {
377         auto result = onKeyEventCallback(info);
378         retCallback = info.IsStopPropagation() || result;
379         auto eventManager = pipeline->GetEventManager();
380         PrintOnKeyEventUserInfo(keyEvent, retCallback);
381     }
382 
383     auto onJSFrameNodeKeyCallback = GetJSFrameNodeOnKeyCallback();
384     if (onJSFrameNodeKeyCallback) {
385         onJSFrameNodeKeyCallback(info);
386         retCallback = info.IsStopPropagation();
387         PrintOnKeyEventUserInfo(keyEvent, retCallback);
388     }
389     return retCallback;
390 }
391 
PrintOnKeyEventUserInfo(const KeyEvent & keyEvent,bool retCallback)392 void FocusEventHandler::PrintOnKeyEventUserInfo(const KeyEvent& keyEvent, bool retCallback)
393 {
394     TAG_LOGI(AceLogTag::ACE_FOCUS,
395         "OnKeyEventUser: Node %{public}s/%{public}d"
396         "handle KeyEvent(" SEC_PLD(%{private}d) ", %{public}d) return: %{public}d",
397         GetFrameName().c_str(), GetFrameId(), SEC_PARAM(keyEvent.code), keyEvent.action, retCallback);
398 }
399 
ProcessOnKeyEventInternal(const KeyEvent & event)400 bool FocusEventHandler::ProcessOnKeyEventInternal(const KeyEvent& event)
401 {
402     bool result = false;
403     for (const auto& onKeyEvent : onKeyEventsInternal_) {
404         auto callback = onKeyEvent.second;
405         if (callback && callback(event)) {
406             result = true;
407         }
408     }
409     return result;
410 }
411 } // namespace OHOS::Ace::NG