1 /*
2 * Copyright (c) 2021-2022 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 "core/focus/focus_node.h"
17
18 #include <algorithm>
19 #include <atomic>
20 #include <cinttypes>
21
22 #include "base/log/dump_log.h"
23 #include "base/log/log.h"
24 #include "core/common/ace_application_info.h"
25 #include "core/components/flex/flex_element.h"
26 #include "core/event/ace_event_handler.h"
27 #include "core/gestures/click_recognizer.h"
28 #include "core/pipeline/base/composed_element.h"
29 #include "core/pipeline/base/render_element.h"
30
31 namespace OHOS::Ace {
32 namespace {
33
GetRenderNode(const RefPtr<FocusNode> & node)34 inline RefPtr<RenderNode> GetRenderNode(const RefPtr<FocusNode>& node)
35 {
36 auto element = AceType::DynamicCast<RenderElement>(node);
37 if (!element) {
38 auto composedElement = AceType::DynamicCast<ComposedElement>(node);
39 if (composedElement) {
40 auto child = composedElement->GetChildren().front();
41 return child ? child->GetRenderNode() : nullptr;
42 }
43 return nullptr;
44 }
45 return element->GetRenderNode();
46 }
47
48 } // namespace
49
GenerateFocusIndex()50 int32_t FocusNode::GenerateFocusIndex()
51 {
52 static std::atomic<int32_t> counter { 1 };
53 return counter.fetch_add(1, std::memory_order_relaxed);
54 }
55
HandleKeyEvent(const KeyEvent & keyEvent)56 bool FocusNode::HandleKeyEvent(const KeyEvent& keyEvent)
57 {
58 if (!IsCurrentFocus()) {
59 return false;
60 }
61 if (OnKeyEvent(keyEvent)) {
62 return true;
63 }
64
65 auto element = AceType::DynamicCast<Element>(this);
66 if (!element) {
67 return false;
68 }
69 auto context = element->GetContext().Upgrade();
70 if (!context) {
71 return false;
72 }
73
74 switch (keyEvent.code) {
75 case KeyCode::KEY_ENTER:
76 case KeyCode::KEY_NUMPAD_ENTER:
77 case KeyCode::KEY_DPAD_CENTER:
78 if (keyEvent.action != KeyAction::DOWN) {
79 return false;
80 }
81 if (context->GetIsDeclarative()) {
82 return OnClick(keyEvent);
83 }
84 OnClick();
85 return true;
86
87 default:
88 return false;
89 }
90 }
91
CollectTabIndexNodes(TabIndexNodeList & tabIndexNodes)92 void FocusNode::CollectTabIndexNodes(TabIndexNodeList& tabIndexNodes)
93 {
94 RefPtr<FocusNode> node = AceType::Claim(this);
95 CHECK_NULL_VOID(node);
96 RefPtr<FocusGroup> scope = AceType::DynamicCast<FocusGroup>(node);
97 if (scope && scope->IsFocusable()) {
98 auto children = scope->GetChildrenList();
99 if (children.size() == 1 && !AceType::DynamicCast<FocusGroup>(children.front())) {
100 if (scope->GetTabIndex() > 0) {
101 tabIndexNodes.emplace_back(scope->GetTabIndex(), WeakClaim(AceType::RawPtr(scope)));
102 }
103 return;
104 }
105 for (auto& child : children) {
106 child->CollectTabIndexNodes(tabIndexNodes);
107 }
108 }
109 if (node->IsFocusable() && node->GetTabIndex() > 0) {
110 tabIndexNodes.emplace_back(node->GetTabIndex(), WeakClaim(AceType::RawPtr(node)));
111 }
112 }
113
GoToFocusByTabNodeIdx(TabIndexNodeList & tabIndexNodes,int32_t tabNodeIdx)114 bool FocusNode::GoToFocusByTabNodeIdx(TabIndexNodeList& tabIndexNodes, int32_t tabNodeIdx)
115 {
116 auto iter = tabIndexNodes.begin();
117 std::advance(iter, tabNodeIdx);
118 if (iter == tabIndexNodes.end()) {
119 LOGE("Tab index node is not found");
120 return false;
121 }
122 auto nodeNeedToFocus = (*iter).second.Upgrade();
123 if (!nodeNeedToFocus) {
124 LOGE("Tab index node is null");
125 return false;
126 }
127 LOGI("Focus on tab index node(%{public}d)", tabNodeIdx);
128 auto scopeNeedToFocus = AceType::DynamicCast<FocusGroup>(nodeNeedToFocus);
129 if (scopeNeedToFocus && !scopeNeedToFocus->IsGroupDefaultFocused()) {
130 auto defaultFocusNode = nodeNeedToFocus->GetChildDefaultFocusNode(false);
131 if (defaultFocusNode) {
132 if (!defaultFocusNode->IsFocusableWholePath()) {
133 LOGW("node(%{public}d) is not focusable", tabNodeIdx);
134 return false;
135 }
136 scopeNeedToFocus->SetIsGroupDefaultFocused(true);
137 return defaultFocusNode->RequestFocusImmediately();
138 }
139 }
140 if (!nodeNeedToFocus->IsFocusableWholePath()) {
141 LOGW("node(%{public}d) is not focusable", tabNodeIdx);
142 return false;
143 }
144 return nodeNeedToFocus->RequestFocusImmediately();
145 }
146
HandleFocusByTabIndex(const KeyEvent & event,const RefPtr<FocusGroup> & mainNode)147 bool FocusNode::HandleFocusByTabIndex(const KeyEvent& event, const RefPtr<FocusGroup>& mainNode)
148 {
149 if (event.code != KeyCode::KEY_TAB || event.action != KeyAction::DOWN) {
150 return false;
151 }
152 if (!mainNode) {
153 LOGE("Current page node is not exit. Can't handle focus by tabIndex.");
154 return false;
155 }
156 TabIndexNodeList tabIndexNodes;
157 tabIndexNodes.clear();
158 mainNode->CollectTabIndexNodes(tabIndexNodes);
159 tabIndexNodes.sort([](std::pair<int32_t, WeakPtr<FocusNode>>& a, std::pair<int32_t, WeakPtr<FocusNode>>& b) {
160 return a.first < b.first;
161 });
162 int32_t curTabFocusIndex = mainNode->GetFocusingTabNodeIdx(tabIndexNodes);
163 if ((curTabFocusIndex < 0 || curTabFocusIndex >= static_cast<int32_t>(tabIndexNodes.size())) &&
164 curTabFocusIndex != DEFAULT_TAB_FOCUSED_INDEX) {
165 LOGI("Current focused tabIndex node: %{public}d. Use default focus system.", curTabFocusIndex);
166 return false;
167 }
168 if (curTabFocusIndex == DEFAULT_TAB_FOCUSED_INDEX) {
169 curTabFocusIndex = 0;
170 } else {
171 if (event.IsShiftWith(KeyCode::KEY_TAB)) {
172 LOGI("RequestNextFocus by 'SHIFT-TAB'");
173 --curTabFocusIndex;
174 } else {
175 LOGI("RequestNextFocus by 'TAB'");
176 ++curTabFocusIndex;
177 }
178 }
179 if (curTabFocusIndex < 0 || curTabFocusIndex >= static_cast<int32_t>(tabIndexNodes.size())) {
180 LOGI("Focus from tab index node to normal node. Use default focus system.");
181 return false;
182 }
183 return GoToFocusByTabNodeIdx(tabIndexNodes, curTabFocusIndex);
184 }
185
DumpFocus()186 void FocusNode::DumpFocus() {}
187
DumpFocusTree(int32_t depth)188 void FocusNode::DumpFocusTree(int32_t depth)
189 {
190 if (DumpLog::GetInstance().GetDumpFile()) {
191 DumpFocus();
192 std::string information = AceType::TypeName(this);
193 if (IsCurrentFocus()) {
194 information += "(Node*)";
195 } else {
196 information += "(Node)";
197 }
198
199 if (!IsFocusable()) {
200 information = "(-)" + information;
201 }
202 DumpLog::GetInstance().Print(depth, information, 0);
203 }
204 }
205
IsFocusableByTab() const206 bool FocusNode::IsFocusableByTab() const
207 {
208 auto parent = GetParent().Upgrade();
209 if (parent) {
210 return (tabIndex_ == 0) && (parent->tabIndex_ == 0);
211 }
212 return tabIndex_ == 0;
213 }
214
IsFocusableWholePath() const215 bool FocusNode::IsFocusableWholePath() const
216 {
217 auto parent = GetParent().Upgrade();
218 while (parent) {
219 if (!parent->IsFocusable()) {
220 return false;
221 }
222 parent = parent->GetParent().Upgrade();
223 }
224 return IsFocusable();
225 }
226
RequestFocusImmediately()227 bool FocusNode::RequestFocusImmediately()
228 {
229 auto renderNode = GetRenderNode(AceType::Claim(this));
230 if (renderNode) {
231 auto context = renderNode->GetContext().Upgrade();
232 if (context && context->IsJsCard()) {
233 return false;
234 }
235 if (context && context->GetIsFocusingByTab()) {
236 if (!IsFocusableByTab()) {
237 return false;
238 }
239 }
240 }
241 if (IsCurrentFocus()) {
242 return true;
243 }
244
245 if (!IsFocusable()) {
246 return false;
247 }
248
249 currentFocus_ = true;
250 UpdateAccessibilityFocusInfo();
251 auto parent = GetParent().Upgrade();
252 if (parent) {
253 parent->SwitchFocus(AceType::Claim(this));
254 }
255
256 HandleFocus();
257 return true;
258 }
259
GetChildDefaultFocusNode(bool isGetDefaultFocus)260 RefPtr<FocusNode> FocusNode::GetChildDefaultFocusNode(bool isGetDefaultFocus)
261 {
262 if (isGetDefaultFocus && isDefaultFocus_ && IsFocusable()) {
263 return AceType::Claim(this);
264 }
265 if (!isGetDefaultFocus && isDefaultGroupFocus_ && IsFocusable()) {
266 return AceType::Claim(this);
267 }
268 RefPtr<FocusGroup> scope = AceType::DynamicCast<FocusGroup>(AceType::Claim(this));
269 if (!scope) {
270 return nullptr;
271 }
272 auto children = scope->GetChildrenList();
273 for (const auto& child : children) {
274 auto findNode = child->GetChildDefaultFocusNode(isGetDefaultFocus);
275 if (findNode) {
276 return findNode;
277 }
278 }
279 return nullptr;
280 }
281
GetChildFocusNodeById(const std::string & id)282 RefPtr<FocusNode> FocusNode::GetChildFocusNodeById(const std::string& id)
283 {
284 if (id.empty()) {
285 return nullptr;
286 }
287 if (GetInspectorKey() == id) {
288 return AceType::Claim(this);
289 }
290 RefPtr<FocusGroup> scope = AceType::DynamicCast<FocusGroup>(AceType::Claim(this));
291 if (scope) {
292 auto children = scope->GetChildrenList();
293 for (const auto& child : children) {
294 auto findNode = child->GetChildFocusNodeById(id);
295 if (findNode) {
296 return findNode;
297 }
298 }
299 }
300 return nullptr;
301 }
302
RequestFocusImmediatelyById(const std::string & id)303 bool FocusNode::RequestFocusImmediatelyById(const std::string& id)
304 {
305 auto focusNode = GetChildFocusNodeById(id);
306 if (!focusNode) {
307 LOGW("Can not find focus node by id: %{public}s", id.c_str());
308 return false;
309 }
310 if (!focusNode->IsFocusableWholePath()) {
311 return false;
312 }
313 return focusNode->RequestFocusImmediately();
314 }
315
UpdateAccessibilityFocusInfo()316 void FocusNode::UpdateAccessibilityFocusInfo()
317 {
318 auto renderNode = GetRenderNode(AceType::Claim(this));
319 if (!renderNode) {
320 LOGW("FocusNode renderNode is null.");
321 return;
322 }
323 auto accessibilityNode = renderNode->GetAccessibilityNode().Upgrade();
324 if (!accessibilityNode) {
325 return;
326 }
327 accessibilityNode->SetFocusedState(currentFocus_);
328 }
329
LostFocus(BlurReason reason)330 void FocusNode::LostFocus(BlurReason reason)
331 {
332 if (IsCurrentFocus()) {
333 blurReason_ = reason;
334 currentFocus_ = false;
335 UpdateAccessibilityFocusInfo();
336 OnBlur();
337 }
338 }
339
LostSelfFocus()340 void FocusNode::LostSelfFocus()
341 {
342 if (IsCurrentFocus()) {
343 SetFocusable(false);
344 SetFocusable(true);
345 }
346 }
347
RemoveSelf()348 void FocusNode::RemoveSelf()
349 {
350 auto parent = parent_.Upgrade();
351 if (parent) {
352 parent->RemoveChild(AceType::Claim(this));
353 }
354 }
355
SetFocusable(bool focusable)356 void FocusNode::SetFocusable(bool focusable)
357 {
358 if (focusable_ == focusable) {
359 return;
360 }
361 focusable_ = focusable;
362 RefreshParentFocusable(FocusNode::IsFocusable());
363 RefreshFocus();
364 }
365
SetEnabled(bool enabled)366 void FocusNode::SetEnabled(bool enabled)
367 {
368 enabled_ = enabled;
369 if (!enabled) {
370 RefreshFocus();
371 }
372 }
373
SetShow(bool show)374 void FocusNode::SetShow(bool show)
375 {
376 show_ = show;
377 if (!show) {
378 RefreshFocus();
379 }
380 }
381
RefreshFocus()382 void FocusNode::RefreshFocus()
383 {
384 if (!IsCurrentFocus()) {
385 return;
386 }
387
388 // lost current focus and request another focus
389 auto parent = GetParent().Upgrade();
390
391 // current node is root node
392 if (!parent) {
393 LostFocus();
394 return;
395 }
396 while (!parent->IsFocusable()) {
397 // parent node is root node
398 if (!parent->GetParent().Upgrade()) {
399 parent->LostFocus();
400 return;
401 }
402 parent = parent->GetParent().Upgrade();
403 }
404 parent->LostFocus();
405 parent->RequestFocusImmediately();
406 }
407
OnKeyEvent(const KeyEvent & keyEvent)408 bool FocusNode::OnKeyEvent(const KeyEvent& keyEvent)
409 {
410 auto element = AceType::DynamicCast<Element>(this);
411 if (!element) {
412 return false;
413 }
414 auto context = element->GetContext().Upgrade();
415 if (!context) {
416 return false;
417 }
418 if (context->GetIsDeclarative()) {
419 auto info = std::make_shared<KeyEventInfo>(keyEvent);
420 if (!onKeyEventCallback_) {
421 return false;
422 }
423 #ifdef LINUX_PLATFORM
424 LOGI("FocusNode::OnKeyEvent: Do key callback on %{public}s with key event{ Code(%{public}d), "
425 "Action(%{public}d), "
426 "SourceType(%{public}d), DeviceId(%{public}" PRId64 ") }. Return: %{public}d",
427 AceType::TypeName(this), info->GetKeyCode(), info->GetKeyType(), info->GetSourceDevice(),
428 info->GetDeviceId(), info->IsStopPropagation());
429 #else
430 LOGI("FocusNode::OnKeyEvent: Do key callback on %{public}s with key event{ Code(%{public}d), "
431 "Action(%{public}d), "
432 "SourceType(%{public}d), DeviceId(%{public}" PRId64 "), Time(%{public}lld) }. Return: %{public}d",
433 AceType::TypeName(this), info->GetKeyCode(), info->GetKeyType(), info->GetSourceDevice(),
434 info->GetDeviceId(), info->GetTimeStamp().time_since_epoch().count(), info->IsStopPropagation());
435 #endif
436 onKeyEventCallback_(info);
437 return info->IsStopPropagation();
438 } else {
439 if (onKeyCallback_) {
440 return onKeyCallback_(keyEvent);
441 }
442 }
443 return false;
444 }
445
RefreshParentFocusable(bool focusable)446 void FocusNode::RefreshParentFocusable(bool focusable)
447 {
448 // do nothing
449 }
450
RequestFocus()451 void FocusNode::RequestFocus()
452 {
453 if (IsCurrentFocus()) {
454 return;
455 }
456
457 auto element = AceType::DynamicCast<Element>(this);
458 if (!element) {
459 return;
460 }
461 auto context = element->GetContext().Upgrade();
462 if (context) {
463 context->AddDirtyFocus(AceType::Claim(this));
464 } else {
465 LOGE("fail to add dirty focus due to context is null");
466 }
467 }
468
OnClick(const KeyEvent & event)469 bool FocusNode::OnClick(const KeyEvent& event)
470 {
471 if (onClickEventCallback_) {
472 auto info = std::make_shared<ClickInfo>(-1);
473 info->SetTimeStamp(event.timeStamp);
474 info->SetGlobalLocation(
475 Offset((GetRect().Left() + GetRect().Right()) / 2, (GetRect().Top() + GetRect().Bottom()) / 2));
476 info->SetLocalLocation(
477 Offset((GetRect().Right() - GetRect().Left()) / 2, (GetRect().Bottom() - GetRect().Top()) / 2));
478 info->SetSourceDevice(static_cast<SourceType>(event.sourceType));
479 info->SetDeviceId(event.deviceId);
480 #ifdef LINUX_PLATFORM
481 LOGI("FocusNode::OnClick: Do click callback on %{public}s with key event{ Global(%{public}f,%{public}f), "
482 "Local(%{public}f,%{public}f), SourceType(%{public}d), DeviceId(%{public}" PRId64 ")}",
483 AceType::TypeName(this), info->GetGlobalLocation().GetX(), info->GetGlobalLocation().GetY(),
484 info->GetLocalLocation().GetX(), info->GetLocalLocation().GetY(), info->GetSourceDevice(),
485 info->GetDeviceId());
486 #else
487 LOGI("FocusNode::OnClick: Do click callback on %{public}s with key event{ Global(%{public}f,%{public}f), "
488 "Local(%{public}f,%{public}f), SourceType(%{public}d), DeviceId(%{public}" PRId64
489 "), Time(%{public}lld) }",
490 AceType::TypeName(this), info->GetGlobalLocation().GetX(), info->GetGlobalLocation().GetY(),
491 info->GetLocalLocation().GetX(), info->GetLocalLocation().GetY(), info->GetSourceDevice(),
492 info->GetDeviceId(), info->GetTimeStamp().time_since_epoch().count());
493 #endif
494 onClickEventCallback_(info);
495 return true;
496 }
497 return false;
498 }
499
AddChild(const RefPtr<FocusNode> & focusNode)500 void FocusGroup::AddChild(const RefPtr<FocusNode>& focusNode)
501 {
502 // Already belong to any focus scope.
503 if (!focusNode || !focusNode->GetParent().Invalid()) {
504 return;
505 }
506
507 auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
508 if (it == focusNodes_.end()) {
509 focusNodes_.emplace_back(focusNode);
510 focusNode->SetParent(AceType::WeakClaim(this));
511 }
512 }
513
AddChild(const RefPtr<FocusNode> & focusNode,const RefPtr<FocusNode> & nextFocusNode)514 void FocusGroup::AddChild(const RefPtr<FocusNode>& focusNode, const RefPtr<FocusNode>& nextFocusNode)
515 {
516 // Already belong to any focus scope.
517 if (!focusNode || !focusNode->GetParent().Invalid()) {
518 return;
519 }
520
521 auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
522 auto pos = std::find(focusNodes_.begin(), focusNodes_.end(), nextFocusNode);
523 if (it == focusNodes_.end()) {
524 focusNodes_.insert(pos, focusNode);
525 focusNode->SetParent(AceType::WeakClaim(this));
526 }
527 }
528
DumpFocusTree(int32_t depth)529 void FocusGroup::DumpFocusTree(int32_t depth)
530 {
531 if (DumpLog::GetInstance().GetDumpFile()) {
532 DumpFocus();
533 std::string information = AceType::TypeName(this);
534 if (IsCurrentFocus()) {
535 information += "(Scope*)";
536 } else {
537 information += "(Scope)";
538 }
539
540 if (!IsFocusable()) {
541 information = "(-)" + information;
542 }
543 DumpLog::GetInstance().Print(depth, information, focusNodes_.size());
544 }
545
546 for (const auto& item : focusNodes_) {
547 item->DumpFocusTree(depth + 1);
548 }
549 }
550
RemoveChild(const RefPtr<FocusNode> & focusNode)551 void FocusGroup::RemoveChild(const RefPtr<FocusNode>& focusNode)
552 {
553 // Not belong to this focus scope.
554 if (!focusNode || focusNode->GetParent() != this) {
555 return;
556 }
557
558 if (focusNode->IsCurrentFocus()) {
559 // Try to goto next focus, otherwise goto previous focus.
560 if (!GoToNextFocus(true) && !GoToNextFocus(false)) {
561 itLastFocusNode_ = focusNodes_.end();
562 }
563 focusNode->LostFocus();
564 } else {
565 if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_) == focusNode) {
566 itLastFocusNode_ = focusNodes_.end();
567 }
568 }
569
570 auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
571 if (it == focusNodes_.end()) {
572 return;
573 }
574 if (itLastFocusNode_ == it) {
575 itLastFocusNode_ = focusNodes_.end();
576 }
577 focusNode->SetParent(nullptr);
578 focusNodes_.erase(it);
579 }
580
SwitchFocus(const RefPtr<FocusNode> & focusNode)581 void FocusGroup::SwitchFocus(const RefPtr<FocusNode>& focusNode)
582 {
583 auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
584 ACE_DCHECK(it != focusNodes_.end());
585
586 auto itFocusNode = itLastFocusNode_;
587 itLastFocusNode_ = it;
588
589 if (IsCurrentFocus()) {
590 if (itFocusNode != focusNodes_.end() && itFocusNode != it) {
591 (*itFocusNode)->LostFocus();
592 }
593 } else {
594 RequestFocusImmediately();
595 }
596 }
597
IsFocusable() const598 bool FocusGroup::IsFocusable() const
599 {
600 if (!FocusNode::IsFocusable()) {
601 return false;
602 }
603 return std::any_of(focusNodes_.begin(), focusNodes_.end(),
604 [](const RefPtr<FocusNode>& focusNode) { return focusNode->IsFocusable(); });
605 }
606
IsFocusableByTab() const607 bool FocusGroup::IsFocusableByTab() const
608 {
609 if (!FocusNode::IsFocusableByTab()) {
610 return false;
611 }
612 if (focusNodes_.empty()) {
613 return true;
614 }
615 return std::any_of(focusNodes_.begin(), focusNodes_.end(),
616 [](const RefPtr<FocusNode>& focusNode) { return focusNode->IsFocusableByTab(); });
617 }
618
GoToNextFocus(bool reverse,const Rect & rect)619 bool FocusGroup::GoToNextFocus(bool reverse, const Rect& rect)
620 {
621 if (focusNodes_.empty()) {
622 return false;
623 }
624 auto itNewFocusNode = itLastFocusNode_;
625 if (itNewFocusNode == focusNodes_.end()) {
626 itNewFocusNode = focusNodes_.begin();
627 }
628 if (reverse) {
629 if (itNewFocusNode == focusNodes_.begin()) {
630 itNewFocusNode = focusNodes_.end();
631 return false;
632 } else {
633 --itNewFocusNode;
634 }
635 while (itNewFocusNode != focusNodes_.begin()) {
636 if (TryRequestFocus(*itNewFocusNode, rect)) {
637 return true;
638 }
639 --itNewFocusNode;
640 }
641 if (itNewFocusNode == focusNodes_.begin()) {
642 if (TryRequestFocus(*itNewFocusNode, rect)) {
643 return true;
644 }
645 }
646 } else {
647 if (itNewFocusNode != focusNodes_.end()) {
648 ++itNewFocusNode;
649 }
650 while (itNewFocusNode != focusNodes_.end()) {
651 if (TryRequestFocus(*itNewFocusNode, rect)) {
652 return true;
653 }
654 ++itNewFocusNode;
655 }
656 }
657
658 return false;
659 }
660
OnKeyEvent(const KeyEvent & keyEvent)661 bool FocusGroup::OnKeyEvent(const KeyEvent& keyEvent)
662 {
663 ACE_DCHECK(IsCurrentFocus());
664 if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_)->HandleKeyEvent(keyEvent)) {
665 return true;
666 }
667
668 if (FocusNode::OnKeyEvent(keyEvent)) {
669 return true;
670 }
671
672 if (keyEvent.action != KeyAction::DOWN) {
673 return false;
674 }
675
676 if (!CalculatePosition()) {
677 return false;
678 }
679
680 OnFocusMove(keyEvent.code);
681 switch (keyEvent.code) {
682 case KeyCode::TV_CONTROL_UP:
683 LOGI("RequestNextFocus 'UP' by KeyCode(%{public}d)", keyEvent.code);
684 return RequestNextFocus(true, true, GetRect());
685 case KeyCode::TV_CONTROL_DOWN:
686 LOGI("RequestNextFocus 'DOWN' by KeyCode(%{public}d)", keyEvent.code);
687 return RequestNextFocus(true, false, GetRect());
688 case KeyCode::TV_CONTROL_LEFT:
689 LOGI("RequestNextFocus 'LEFT' by KeyCode(%{public}d)", keyEvent.code);
690 return RequestNextFocus(false, !AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
691 case KeyCode::TV_CONTROL_RIGHT:
692 LOGI("RequestNextFocus 'RIGHT' by KeyCode(%{public}d)", keyEvent.code);
693 return RequestNextFocus(false, AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
694 case KeyCode::KEY_TAB: {
695 auto element = AceType::DynamicCast<Element>(this);
696 if (!element) {
697 return false;
698 }
699 auto context = element->GetContext().Upgrade();
700 if (!context) {
701 return false;
702 }
703 bool ret = false;
704 if (keyEvent.pressedCodes.size() == 1) {
705 LOGI("RequestNextFocus 'TAB' by KeyCode(%{public}d)", keyEvent.code);
706 context->SetIsFocusingByTab(true);
707 ret = RequestNextFocus(false, false, GetRect()) || RequestNextFocus(true, false, GetRect());
708 context->SetIsFocusingByTab(false);
709 } else {
710 LOGI("RequestNextFocus 'SHIFT-TAB' by KeyCode(%{public}d)", keyEvent.code);
711 if (keyEvent.IsKey({ KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_TAB }) ||
712 keyEvent.IsKey({ KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_TAB })) {
713 context->SetIsFocusingByTab(true);
714 ret = RequestNextFocus(false, true, GetRect()) || RequestNextFocus(true, true, GetRect());
715 context->SetIsFocusingByTab(false);
716 }
717 }
718 return ret;
719 }
720 default:
721 return false;
722 }
723 }
724
CalculatePosition()725 bool FocusGroup::CalculatePosition()
726 {
727 if (itLastFocusNode_ == focusNodes_.end()) {
728 return false;
729 }
730
731 Rect childRect;
732 if (!CalculateRect(*itLastFocusNode_, childRect)) {
733 return false;
734 }
735
736 if ((*itLastFocusNode_)->IsChild()) {
737 auto renderNode = GetRenderNode(*itLastFocusNode_);
738 if (!renderNode) {
739 return false;
740 }
741
742 Rect rect(childRect.GetOffset(), renderNode->GetLayoutSize());
743 (*itLastFocusNode_)->SetRect(rect);
744 SetRect(rect);
745 } else {
746 SetRect((*itLastFocusNode_)->GetRect() + childRect.GetOffset());
747 }
748
749 return true;
750 }
751
OnFocus()752 void FocusGroup::OnFocus()
753 {
754 if (focusNodes_.empty()) {
755 return;
756 }
757
758 auto itFocusNode = itLastFocusNode_;
759 do {
760 if (itLastFocusNode_ == focusNodes_.end()) {
761 itLastFocusNode_ = focusNodes_.begin();
762 if (itLastFocusNode_ == itFocusNode) {
763 break;
764 }
765 }
766 if ((*itLastFocusNode_)->RequestFocusImmediately()) {
767 FocusNode::OnFocus();
768 return;
769 }
770 } while ((++itLastFocusNode_) != itFocusNode);
771
772 // Not found any focusable node, clear focus.
773 itLastFocusNode_ = focusNodes_.end();
774 }
775
OnBlur()776 void FocusGroup::OnBlur()
777 {
778 FocusNode::OnBlur();
779
780 if (itLastFocusNode_ != focusNodes_.end() && *itLastFocusNode_) {
781 (*itLastFocusNode_)->LostFocus(blurReason_);
782 }
783 }
784
SetShow(bool show)785 void FocusGroup::SetShow(bool show)
786 {
787 FocusNode::SetShow(show);
788 RefreshParentFocusable(FocusNode::IsFocusable());
789 }
790
SetEnabled(bool enabled)791 void FocusGroup::SetEnabled(bool enabled)
792 {
793 FocusNode::SetEnabled(enabled);
794 RefreshParentFocusable(FocusNode::IsFocusable());
795 }
796
TryRequestFocus(const RefPtr<FocusNode> & focusNode,const Rect & rect)797 bool FocusGroup::TryRequestFocus(const RefPtr<FocusNode>& focusNode, const Rect& rect)
798 {
799 if (rect.IsValid()) {
800 Rect childRect;
801 if (!CalculateRect(focusNode, childRect) ||
802 !focusNode->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
803 return false;
804 }
805 }
806 return focusNode->RequestFocusImmediately();
807 }
808
AcceptFocusByRectOfLastFocus(const Rect & rect)809 bool FocusGroup::AcceptFocusByRectOfLastFocus(const Rect& rect)
810 {
811 if (focusNodes_.empty()) {
812 return false;
813 }
814
815 auto itFocusNode = itLastFocusNode_;
816 do {
817 if (itLastFocusNode_ == focusNodes_.end()) {
818 itLastFocusNode_ = focusNodes_.begin();
819 if (itLastFocusNode_ == itFocusNode) {
820 break;
821 }
822 }
823 Rect childRect;
824 if (!CalculateRect(*itLastFocusNode_, childRect)) {
825 continue;
826 }
827
828 if ((*itLastFocusNode_)->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
829 return true;
830 }
831 } while ((++itLastFocusNode_) != itFocusNode);
832
833 return false;
834 }
835
CalculateRect(const RefPtr<FocusNode> & node,Rect & rect)836 bool FocusGroup::CalculateRect(const RefPtr<FocusNode>& node, Rect& rect)
837 {
838 auto renderNode = GetRenderNode(AceType::Claim(this));
839 if (!renderNode) {
840 return false;
841 }
842 Offset nowOffset = renderNode->GetOffsetFromOrigin(Offset());
843
844 renderNode = GetRenderNode(node);
845 if (!renderNode) {
846 return false;
847 }
848 Offset childOffset = renderNode->GetOffsetFromOrigin(Offset());
849 rect.SetRect(childOffset - nowOffset, renderNode->GetLayoutSize());
850 return true;
851 }
852
RefreshParentFocusable(bool focusable)853 void FocusGroup::RefreshParentFocusable(bool focusable)
854 {
855 for (auto& item : focusNodes_) {
856 if (focusable != item->IsParentFocusable()) {
857 item->SetParentFocusable(focusable);
858 item->RefreshParentFocusable(item->FocusNode::IsFocusable());
859 }
860 }
861 }
862
RebuildChild(std::list<RefPtr<FocusNode>> && rebuildFocusNodes)863 void FocusGroup::RebuildChild(std::list<RefPtr<FocusNode>>&& rebuildFocusNodes)
864 {
865 if (rebuildFocusNodes.empty()) {
866 return;
867 }
868
869 focusNodes_ = std::move(rebuildFocusNodes);
870 itLastFocusNode_ = focusNodes_.end();
871 if (!IsCurrentFocus()) {
872 return;
873 }
874
875 auto it = focusNodes_.begin();
876 while (it != focusNodes_.end()) {
877 if ((*it)->IsCurrentFocus()) {
878 itLastFocusNode_ = it;
879 return;
880 }
881 ++it;
882 }
883
884 LostFocus();
885 itLastFocusNode_ = focusNodes_.end();
886 RequestFocusImmediately();
887 }
888
GetFocusingTabNodeIdx(TabIndexNodeList & tabIndexNodes)889 int32_t FocusGroup::GetFocusingTabNodeIdx(TabIndexNodeList& tabIndexNodes)
890 {
891 if (tabIndexNodes.empty()) {
892 return NONE_TAB_FOCUSED_INDEX;
893 }
894 if (isFirstFocusInPage_) {
895 isFirstFocusInPage_ = false;
896 return DEFAULT_TAB_FOCUSED_INDEX;
897 }
898 int32_t res = NONE_TAB_FOCUSED_INDEX;
899 int32_t i = 0;
900 for (auto& wpNode : tabIndexNodes) {
901 auto node = wpNode.second.Upgrade();
902 if (node && node->IsCurrentFocus()) {
903 res = i;
904 break;
905 }
906 ++i;
907 }
908 return res;
909 }
910
911 } // namespace OHOS::Ace
912