1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
ash / quick_insert / views / quick_insert_pseudo_focus.cc [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/quick_insert/views/quick_insert_pseudo_focus.h"
#include "ash/quick_insert/views/quick_insert_item_view.h"
#include "ash/quick_insert/views/quick_insert_list_item_view.h"
#include "ash/quick_insert/views/quick_insert_search_bar_textfield.h"
#include "base/functional/bind.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/types/event_type.h"
#include "ui/views/controls/focus_ring.h"
#include "ui/views/focus/focus_manager.h"
#include "ui/views/view.h"
#include "ui/views/view_utils.h"
namespace ash {
void ApplyQuickInsertPseudoFocusToView(views::View* view) {
if (view == nullptr) {
return;
}
// QuickInsertItemView has special pseudo focus behavior, so handle it
// separately.
if (auto* item_view = views::AsViewClass<QuickInsertItemView>(view)) {
item_view->SetItemState(QuickInsertItemView::ItemState::kPseudoFocused);
if (auto* list_item_view =
views::AsViewClass<QuickInsertListItemView>(view)) {
list_item_view->SetBadgeVisible(true);
}
return;
}
// QuickInsertSearchBarTextfield has special pseudo focus appearance.
if (auto* textfield =
views::AsViewClass<QuickInsertSearchBarTextfield>(view)) {
textfield->SetShouldShowFocusIndicator(true);
return;
}
// Otherwise, default to drawing a focus ring around the view.
// TODO: b/328144222 - Add accessibility announcement when a view gains
// pseudo focus.
if (views::FocusRing* focus_ring = views::FocusRing::Get(view)) {
focus_ring->SetHasFocusPredicate(
base::BindRepeating([](const views::View* view) { return true; }));
focus_ring->SchedulePaint();
}
}
void RemoveQuickInsertPseudoFocusFromView(views::View* view) {
if (view == nullptr) {
return;
}
// QuickInsertItemView has special pseudo focus behavior, so handle it
// separately.
if (auto* item_view = views::AsViewClass<QuickInsertItemView>(view)) {
item_view->SetItemState(QuickInsertItemView::ItemState::kNormal);
if (auto* list_item_view =
views::AsViewClass<QuickInsertListItemView>(view)) {
list_item_view->SetBadgeVisible(false);
}
return;
}
// QuickInsertSearchBarTextfield has special pseudo focus appearance.
if (auto* textfield =
views::AsViewClass<QuickInsertSearchBarTextfield>(view)) {
textfield->SetShouldShowFocusIndicator(false);
return;
}
// Otherwise, default to removing the focus ring around the view.
// TODO: b/328144222 - Add accessibility announcement when a view loses
// pseudo focus.
if (views::FocusRing* focus_ring = views::FocusRing::Get(view)) {
focus_ring->SetHasFocusPredicate(
base::BindRepeating([](const views::View* view) { return false; }));
focus_ring->SchedulePaint();
}
}
bool DoQuickInsertPseudoFocusedActionOnView(views::View* view) {
if (view == nullptr) {
return false;
}
// QuickInsertSearchBarTextfield has no pseudo focus action.
if (views::IsViewClass<QuickInsertSearchBarTextfield>(view)) {
return true;
}
// QuickInsertItemView has special pseudo focus behavior, so handle it
// separately.
if (auto* item_view = views::AsViewClass<QuickInsertItemView>(view)) {
item_view->SelectItem();
return true;
}
// Otherwise, default to behaving the same way as pressing the enter key.
// Here we check that `view` does not have actual focus, to ensure we won't
// trigger an infinite recursive loop of pseudo focused actions when manually
// calling `OnKeyEvent` (since the focused view may forward key events to be
// handled by the pseudo focused view).
CHECK(!view->HasFocus());
ui::KeyEvent key_event(ui::EventType::kKeyPressed, ui::VKEY_RETURN,
ui::DomCode::ENTER, ui::EF_NONE);
view->OnKeyEvent(&key_event);
return key_event.handled();
}
views::View* GetNextQuickInsertPseudoFocusableView(
views::View* view,
QuickInsertPseudoFocusDirection direction,
bool should_loop) {
return view == nullptr || view->GetFocusManager() == nullptr
? nullptr
: view->GetFocusManager()->GetNextFocusableView(
view, view->GetWidget(),
direction == QuickInsertPseudoFocusDirection::kBackward,
!should_loop);
}
} // namespace ash