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 LOGD("Position information: Node is %{public}s, X: %{public}lf Y: %{public}lf W: %{public}lf H: %{public}lf",
681 AceType::TypeName(this), GetRect().Left(), GetRect().Top(), GetRect().Width(), GetRect().Height());
682
683 OnFocusMove(keyEvent.code);
684 switch (keyEvent.code) {
685 case KeyCode::TV_CONTROL_UP:
686 LOGI("RequestNextFocus 'UP' by KeyCode(%{public}d)", keyEvent.code);
687 return RequestNextFocus(true, true, GetRect());
688 case KeyCode::TV_CONTROL_DOWN:
689 LOGI("RequestNextFocus 'DOWN' by KeyCode(%{public}d)", keyEvent.code);
690 return RequestNextFocus(true, false, GetRect());
691 case KeyCode::TV_CONTROL_LEFT:
692 LOGI("RequestNextFocus 'LEFT' by KeyCode(%{public}d)", keyEvent.code);
693 return RequestNextFocus(false, !AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
694 case KeyCode::TV_CONTROL_RIGHT:
695 LOGI("RequestNextFocus 'RIGHT' by KeyCode(%{public}d)", keyEvent.code);
696 return RequestNextFocus(false, AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
697 case KeyCode::KEY_TAB: {
698 auto element = AceType::DynamicCast<Element>(this);
699 if (!element) {
700 return false;
701 }
702 auto context = element->GetContext().Upgrade();
703 if (!context) {
704 return false;
705 }
706 bool ret = false;
707 if (keyEvent.pressedCodes.size() == 1) {
708 LOGI("RequestNextFocus 'TAB' by KeyCode(%{public}d)", keyEvent.code);
709 context->SetIsFocusingByTab(true);
710 ret = RequestNextFocus(false, false, GetRect()) || RequestNextFocus(true, false, GetRect());
711 context->SetIsFocusingByTab(false);
712 } else {
713 LOGI("RequestNextFocus 'SHIFT-TAB' by KeyCode(%{public}d)", keyEvent.code);
714 if (keyEvent.IsKey({ KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_TAB }) ||
715 keyEvent.IsKey({ KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_TAB })) {
716 context->SetIsFocusingByTab(true);
717 ret = RequestNextFocus(false, true, GetRect()) || RequestNextFocus(true, true, GetRect());
718 context->SetIsFocusingByTab(false);
719 }
720 }
721 return ret;
722 }
723 default:
724 return false;
725 }
726 }
727
CalculatePosition()728 bool FocusGroup::CalculatePosition()
729 {
730 if (itLastFocusNode_ == focusNodes_.end()) {
731 return false;
732 }
733
734 Rect childRect;
735 if (!CalculateRect(*itLastFocusNode_, childRect)) {
736 return false;
737 }
738
739 if ((*itLastFocusNode_)->IsChild()) {
740 auto renderNode = GetRenderNode(*itLastFocusNode_);
741 if (!renderNode) {
742 return false;
743 }
744
745 Rect rect(childRect.GetOffset(), renderNode->GetLayoutSize());
746 (*itLastFocusNode_)->SetRect(rect);
747 SetRect(rect);
748 } else {
749 SetRect((*itLastFocusNode_)->GetRect() + childRect.GetOffset());
750 }
751
752 return true;
753 }
754
OnFocus()755 void FocusGroup::OnFocus()
756 {
757 if (focusNodes_.empty()) {
758 return;
759 }
760
761 auto itFocusNode = itLastFocusNode_;
762 do {
763 if (itLastFocusNode_ == focusNodes_.end()) {
764 itLastFocusNode_ = focusNodes_.begin();
765 if (itLastFocusNode_ == itFocusNode) {
766 break;
767 }
768 }
769 if ((*itLastFocusNode_)->RequestFocusImmediately()) {
770 FocusNode::OnFocus();
771 return;
772 }
773 } while ((++itLastFocusNode_) != itFocusNode);
774
775 // Not found any focusable node, clear focus.
776 itLastFocusNode_ = focusNodes_.end();
777 }
778
OnBlur()779 void FocusGroup::OnBlur()
780 {
781 FocusNode::OnBlur();
782
783 if (itLastFocusNode_ != focusNodes_.end() && *itLastFocusNode_) {
784 (*itLastFocusNode_)->LostFocus(blurReason_);
785 }
786 }
787
SetShow(bool show)788 void FocusGroup::SetShow(bool show)
789 {
790 FocusNode::SetShow(show);
791 RefreshParentFocusable(FocusNode::IsFocusable());
792 }
793
SetEnabled(bool enabled)794 void FocusGroup::SetEnabled(bool enabled)
795 {
796 FocusNode::SetEnabled(enabled);
797 RefreshParentFocusable(FocusNode::IsFocusable());
798 }
799
TryRequestFocus(const RefPtr<FocusNode> & focusNode,const Rect & rect)800 bool FocusGroup::TryRequestFocus(const RefPtr<FocusNode>& focusNode, const Rect& rect)
801 {
802 if (rect.IsValid()) {
803 Rect childRect;
804 if (!CalculateRect(focusNode, childRect) ||
805 !focusNode->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
806 return false;
807 }
808 }
809 return focusNode->RequestFocusImmediately();
810 }
811
AcceptFocusByRectOfLastFocus(const Rect & rect)812 bool FocusGroup::AcceptFocusByRectOfLastFocus(const Rect& rect)
813 {
814 if (focusNodes_.empty()) {
815 return false;
816 }
817
818 auto itFocusNode = itLastFocusNode_;
819 do {
820 if (itLastFocusNode_ == focusNodes_.end()) {
821 itLastFocusNode_ = focusNodes_.begin();
822 if (itLastFocusNode_ == itFocusNode) {
823 break;
824 }
825 }
826 Rect childRect;
827 if (!CalculateRect(*itLastFocusNode_, childRect)) {
828 continue;
829 }
830
831 if ((*itLastFocusNode_)->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
832 return true;
833 }
834 } while ((++itLastFocusNode_) != itFocusNode);
835
836 return false;
837 }
838
CalculateRect(const RefPtr<FocusNode> & node,Rect & rect)839 bool FocusGroup::CalculateRect(const RefPtr<FocusNode>& node, Rect& rect)
840 {
841 auto renderNode = GetRenderNode(AceType::Claim(this));
842 if (!renderNode) {
843 return false;
844 }
845 Offset nowOffset = renderNode->GetOffsetFromOrigin(Offset());
846
847 renderNode = GetRenderNode(node);
848 if (!renderNode) {
849 return false;
850 }
851 Offset childOffset = renderNode->GetOffsetFromOrigin(Offset());
852 rect.SetRect(childOffset - nowOffset, renderNode->GetLayoutSize());
853 return true;
854 }
855
RefreshParentFocusable(bool focusable)856 void FocusGroup::RefreshParentFocusable(bool focusable)
857 {
858 for (auto& item : focusNodes_) {
859 if (focusable != item->IsParentFocusable()) {
860 item->SetParentFocusable(focusable);
861 item->RefreshParentFocusable(item->FocusNode::IsFocusable());
862 }
863 }
864 }
865
RebuildChild(std::list<RefPtr<FocusNode>> && rebuildFocusNodes)866 void FocusGroup::RebuildChild(std::list<RefPtr<FocusNode>>&& rebuildFocusNodes)
867 {
868 if (rebuildFocusNodes.empty()) {
869 return;
870 }
871
872 focusNodes_ = std::move(rebuildFocusNodes);
873 itLastFocusNode_ = focusNodes_.end();
874 if (!IsCurrentFocus()) {
875 return;
876 }
877
878 auto it = focusNodes_.begin();
879 while (it != focusNodes_.end()) {
880 if ((*it)->IsCurrentFocus()) {
881 itLastFocusNode_ = it;
882 return;
883 }
884 ++it;
885 }
886
887 LostFocus();
888 itLastFocusNode_ = focusNodes_.end();
889 RequestFocusImmediately();
890 }
891
GetFocusingTabNodeIdx(TabIndexNodeList & tabIndexNodes)892 int32_t FocusGroup::GetFocusingTabNodeIdx(TabIndexNodeList& tabIndexNodes)
893 {
894 if (tabIndexNodes.empty()) {
895 LOGD("No tabIndex node exist in this page.");
896 return NONE_TAB_FOCUSED_INDEX;
897 }
898 if (isFirstFocusInPage_) {
899 isFirstFocusInPage_ = false;
900 return DEFAULT_TAB_FOCUSED_INDEX;
901 }
902 int32_t res = NONE_TAB_FOCUSED_INDEX;
903 int32_t i = 0;
904 for (auto& wpNode : tabIndexNodes) {
905 auto node = wpNode.second.Upgrade();
906 if (node && node->IsCurrentFocus()) {
907 res = i;
908 break;
909 }
910 ++i;
911 }
912 return res;
913 }
914
915 } // namespace OHOS::Ace
916