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