1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/views/focus/focus_manager.h"
10 #include "base/auto_reset.h"
11 #include "base/logging.h"
12 #include "build/build_config.h"
13 #include "ui/base/accelerators/accelerator.h"
14 #include "ui/events/event.h"
15 #include "ui/events/keycodes/keyboard_codes.h"
16 #include "ui/views/focus/focus_manager_delegate.h"
17 #include "ui/views/focus/focus_search.h"
18 #include "ui/views/focus/view_storage.h"
19 #include "ui/views/focus/widget_focus_manager.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/root_view.h"
22 #include "ui/views/widget/widget.h"
23 #include "ui/views/widget/widget_delegate.h"
29 class FocusManagerEventHandler
: public ui::EventHandler
{
31 FocusManagerEventHandler(FocusManager
* parent
) : focus_manager_(parent
) {}
33 // Implementation of ui::EventHandler:
34 virtual void OnKeyEvent(ui::KeyEvent
* event
) OVERRIDE
{
35 if (!focus_manager_
->OnKeyEvent(*event
))
40 FocusManager
* focus_manager_
;
45 bool FocusManager::shortcut_handling_suspended_
= false;
46 bool FocusManager::arrow_key_traversal_enabled_
= false;
48 FocusManager::FocusManager(Widget
* widget
, FocusManagerDelegate
* delegate
)
52 accelerator_manager_(new ui::AcceleratorManager
),
53 focus_change_reason_(kReasonDirectFocusChange
),
54 is_changing_focus_(false) {
56 stored_focused_view_storage_id_
=
57 ViewStorage::GetInstance()->CreateStorageID();
60 FocusManager::~FocusManager() {
63 bool FocusManager::OnKeyEvent(const ui::KeyEvent
& event
) {
64 const int key_code
= event
.key_code();
66 if (event
.type() != ui::ET_KEY_PRESSED
&& event
.type() != ui::ET_KEY_RELEASED
)
69 if (shortcut_handling_suspended())
72 int modifiers
= ui::EF_NONE
;
73 if (event
.IsShiftDown())
74 modifiers
|= ui::EF_SHIFT_DOWN
;
75 if (event
.IsControlDown())
76 modifiers
|= ui::EF_CONTROL_DOWN
;
77 if (event
.IsAltDown())
78 modifiers
|= ui::EF_ALT_DOWN
;
79 ui::Accelerator
accelerator(event
.key_code(), modifiers
);
80 accelerator
.set_type(event
.type());
82 if (event
.type() == ui::ET_KEY_PRESSED
) {
83 // If the focused view wants to process the key event as is, let it be.
84 if (focused_view_
&& focused_view_
->SkipDefaultKeyEventProcessing(event
) &&
85 !accelerator_manager_
->HasPriorityHandler(accelerator
))
88 // Intercept Tab related messages for focus traversal.
89 // Note that we don't do focus traversal if the root window is not part of
90 // the active window hierarchy as this would mean we have no focused view
91 // and would focus the first focusable view.
92 #if defined(OS_WIN) && !defined(USE_AURA)
93 HWND top_window
= widget_
->GetNativeView();
94 HWND active_window
= ::GetActiveWindow();
95 if ((active_window
== top_window
|| ::IsChild(active_window
, top_window
)) &&
96 IsTabTraversalKeyEvent(event
)) {
97 AdvanceFocus(event
.IsShiftDown());
101 if (IsTabTraversalKeyEvent(event
)) {
102 AdvanceFocus(event
.IsShiftDown());
107 if (arrow_key_traversal_enabled_
&& ProcessArrowKeyTraversal(event
))
110 // Intercept arrow key messages to switch between grouped views.
111 if (focused_view_
&& focused_view_
->GetGroup() != -1 &&
112 (key_code
== ui::VKEY_UP
|| key_code
== ui::VKEY_DOWN
||
113 key_code
== ui::VKEY_LEFT
|| key_code
== ui::VKEY_RIGHT
)) {
114 bool next
= (key_code
== ui::VKEY_RIGHT
|| key_code
== ui::VKEY_DOWN
);
116 focused_view_
->parent()->GetViewsInGroup(focused_view_
->GetGroup(),
118 View::Views::const_iterator
i(
119 std::find(views
.begin(), views
.end(), focused_view_
));
120 DCHECK(i
!= views
.end());
121 int index
= static_cast<int>(i
- views
.begin());
122 index
+= next
? 1 : -1;
124 index
= static_cast<int>(views
.size()) - 1;
125 } else if (index
>= static_cast<int>(views
.size())) {
128 SetFocusedViewWithReason(views
[index
], kReasonFocusTraversal
);
133 // Process keyboard accelerators.
134 // If the key combination matches an accelerator, the accelerator is
135 // triggered, otherwise the key event is processed as usual.
136 if (ProcessAccelerator(accelerator
)) {
137 // If a shortcut was activated for this keydown message, do not propagate
138 // the event further.
144 void FocusManager::ValidateFocusedView() {
145 if (focused_view_
&& !ContainsView(focused_view_
))
149 // Tests whether a view is valid, whether it still belongs to the window
150 // hierarchy of the FocusManager.
151 bool FocusManager::ContainsView(View
* view
) {
152 Widget
* widget
= view
->GetWidget();
153 return widget
? widget
->GetFocusManager() == this : false;
156 void FocusManager::AdvanceFocus(bool reverse
) {
157 View
* v
= GetNextFocusableView(focused_view_
, NULL
, reverse
, false);
158 // Note: Do not skip this next block when v == focused_view_. If the user
159 // tabs past the last focusable element in a webpage, we'll get here, and if
160 // the TabContentsContainerView is the only focusable view (possible in
161 // fullscreen mode), we need to run this block in order to cycle around to the
162 // first element on the page.
164 views::View
* focused_view
= focused_view_
;
165 v
->AboutToRequestFocusFromTabTraversal(reverse
);
166 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
167 // don't change focus again.
168 if (focused_view
== focused_view_
)
169 SetFocusedViewWithReason(v
, kReasonFocusTraversal
);
173 void FocusManager::ClearNativeFocus() {
174 // Keep the top root window focused so we get keyboard events.
175 widget_
->ClearNativeFocus();
178 bool FocusManager::RotatePaneFocus(Direction direction
,
179 FocusCycleWrappingBehavior wrap
) {
180 // Get the list of all accessible panes.
181 std::vector
<View
*> panes
;
182 widget_
->widget_delegate()->GetAccessiblePanes(&panes
);
184 // Count the number of panes and set the default index if no pane
185 // is initially focused.
186 int count
= static_cast<int>(panes
.size());
190 // Initialize |index| to an appropriate starting index if nothing is
191 // focused initially.
192 int index
= direction
== kBackward
? 0 : count
- 1;
194 // Check to see if a pane already has focus and update the index accordingly.
195 const views::View
* focused_view
= GetFocusedView();
197 for (int i
= 0; i
< count
; i
++) {
198 if (panes
[i
] && panes
[i
]->Contains(focused_view
)) {
206 int start_index
= index
;
208 if (direction
== kBackward
)
213 if (wrap
== kNoWrap
&& (index
>= count
|| index
< 0))
215 index
= (index
+ count
) % count
;
217 // Ensure that we don't loop more than once.
218 if (index
== start_index
)
221 views::View
* pane
= panes
[index
];
224 if (!pane
->visible())
227 pane
->RequestFocus();
228 focused_view
= GetFocusedView();
229 if (pane
== focused_view
|| pane
->Contains(focused_view
))
236 View
* FocusManager::GetNextFocusableView(View
* original_starting_view
,
237 Widget
* starting_widget
,
240 FocusTraversable
* focus_traversable
= NULL
;
242 // Let's revalidate the focused view.
243 ValidateFocusedView();
245 View
* starting_view
= NULL
;
246 if (original_starting_view
) {
247 // Search up the containment hierarchy to see if a view is acting as
248 // a pane, and wants to implement its own focus traversable to keep
249 // the focus trapped within that pane.
250 View
* pane_search
= original_starting_view
;
251 while (pane_search
) {
252 focus_traversable
= pane_search
->GetPaneFocusTraversable();
253 if (focus_traversable
) {
254 starting_view
= original_starting_view
;
257 pane_search
= pane_search
->parent();
260 if (!focus_traversable
) {
262 // If the starting view has a focus traversable, use it.
263 // This is the case with NativeWidgetWins for example.
264 focus_traversable
= original_starting_view
->GetFocusTraversable();
266 // Otherwise default to the root view.
267 if (!focus_traversable
) {
269 original_starting_view
->GetWidget()->GetFocusTraversable();
270 starting_view
= original_starting_view
;
273 // When you are going back, starting view's FocusTraversable
274 // should not be used.
276 original_starting_view
->GetWidget()->GetFocusTraversable();
277 starting_view
= original_starting_view
;
281 Widget
* widget
= starting_widget
? starting_widget
: widget_
;
282 focus_traversable
= widget
->GetFocusTraversable();
285 // Traverse the FocusTraversable tree down to find the focusable view.
286 View
* v
= FindFocusableView(focus_traversable
, starting_view
, reverse
);
290 // Let's go up in the FocusTraversable tree.
291 FocusTraversable
* parent_focus_traversable
=
292 focus_traversable
->GetFocusTraversableParent();
293 starting_view
= focus_traversable
->GetFocusTraversableParentView();
294 while (parent_focus_traversable
) {
295 FocusTraversable
* new_focus_traversable
= NULL
;
296 View
* new_starting_view
= NULL
;
297 // When we are going backward, the parent view might gain the next focus.
298 bool check_starting_view
= reverse
;
299 v
= parent_focus_traversable
->GetFocusSearch()->FindNextFocusableView(
300 starting_view
, reverse
, FocusSearch::UP
,
301 check_starting_view
, &new_focus_traversable
, &new_starting_view
);
303 if (new_focus_traversable
) {
306 // There is a FocusTraversable, traverse it down.
307 v
= FindFocusableView(new_focus_traversable
, NULL
, reverse
);
313 starting_view
= focus_traversable
->GetFocusTraversableParentView();
314 parent_focus_traversable
=
315 parent_focus_traversable
->GetFocusTraversableParent();
318 // If we get here, we have reached the end of the focus hierarchy, let's
319 // loop. Make sure there was at least a view to start with, to prevent
320 // infinitely looping in empty windows.
321 if (!dont_loop
&& original_starting_view
) {
322 // Easy, just clear the selection and press tab again.
323 // By calling with NULL as the starting view, we'll start from either
324 // the starting views widget or |widget_|.
325 Widget
* widget
= original_starting_view
->GetWidget();
326 if (widget
->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
328 return GetNextFocusableView(NULL
, widget
, reverse
, true);
334 void FocusManager::SetFocusedViewWithReason(
335 View
* view
, FocusChangeReason reason
) {
336 if (focused_view_
== view
)
339 base::AutoReset
<bool> auto_changing_focus(&is_changing_focus_
, true);
340 // Update the reason for the focus change (since this is checked by
341 // some listeners), then notify all listeners.
342 focus_change_reason_
= reason
;
343 FOR_EACH_OBSERVER(FocusChangeListener
, focus_change_listeners_
,
344 OnWillChangeFocus(focused_view_
, view
));
346 View
* old_focused_view
= focused_view_
;
347 focused_view_
= view
;
348 if (old_focused_view
)
349 old_focused_view
->Blur();
350 // Also make |focused_view_| the stored focus view. This way the stored focus
351 // view is remembered if focus changes are requested prior to a show or while
353 SetStoredFocusView(focused_view_
);
355 focused_view_
->Focus();
357 FOR_EACH_OBSERVER(FocusChangeListener
, focus_change_listeners_
,
358 OnDidChangeFocus(old_focused_view
, focused_view_
));
361 void FocusManager::ClearFocus() {
362 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
363 // persist it in this case.
364 views::View
* focused_view
= GetStoredFocusView();
365 SetFocusedView(NULL
);
367 SetStoredFocusView(focused_view
);
370 void FocusManager::StoreFocusedView(bool clear_native_focus
) {
371 View
* focused_view
= focused_view_
;
372 // Don't do anything if no focused view. Storing the view (which is NULL), in
373 // this case, would clobber the view that was previously saved.
377 View
* v
= focused_view_
;
379 if (clear_native_focus
) {
380 // Temporarily disable notification. ClearFocus() will set the focus to the
381 // main browser window. This extra focus bounce which happens during
382 // deactivation can confuse registered WidgetFocusListeners, as the focus
383 // is not changing due to a user-initiated event.
384 AutoNativeNotificationDisabler local_notification_disabler
;
385 // ClearFocus() also stores the focused view.
388 SetFocusedView(NULL
);
389 SetStoredFocusView(focused_view
);
393 v
->SchedulePaint(); // Remove focus border.
396 bool FocusManager::RestoreFocusedView() {
397 View
* view
= GetStoredFocusView();
399 if (ContainsView(view
)) {
400 if (!view
->IsFocusable() && view
->IsAccessibilityFocusable()) {
401 // RequestFocus would fail, but we want to restore focus to controls
402 // that had focus in accessibility mode.
403 SetFocusedViewWithReason(view
, kReasonFocusRestore
);
405 // This usually just sets the focus if this view is focusable, but
406 // let the view override RequestFocus if necessary.
407 view
->RequestFocus();
409 // If it succeeded, the reason would be incorrect; set it to
411 if (focused_view_
== view
)
412 focus_change_reason_
= kReasonFocusRestore
;
420 void FocusManager::SetStoredFocusView(View
* focus_view
) {
421 ViewStorage
* view_storage
= ViewStorage::GetInstance();
423 // This should never happen but bug 981648 seems to indicate it could.
428 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
429 // is stored twice causing an assert. We should find a better alternative than
430 // removing the view from the storage explicitly.
431 view_storage
->RemoveView(stored_focused_view_storage_id_
);
436 view_storage
->StoreView(stored_focused_view_storage_id_
, focus_view
);
439 View
* FocusManager::GetStoredFocusView() {
440 ViewStorage
* view_storage
= ViewStorage::GetInstance();
442 // This should never happen but bug 981648 seems to indicate it could.
447 return view_storage
->RetrieveView(stored_focused_view_storage_id_
);
450 void FocusManager::ClearStoredFocusedView() {
451 SetStoredFocusView(NULL
);
454 // Find the next (previous if reverse is true) focusable view for the specified
455 // FocusTraversable, starting at the specified view, traversing down the
456 // FocusTraversable hierarchy.
457 View
* FocusManager::FindFocusableView(FocusTraversable
* focus_traversable
,
460 FocusTraversable
* new_focus_traversable
= NULL
;
461 View
* new_starting_view
= NULL
;
462 View
* v
= focus_traversable
->GetFocusSearch()->FindNextFocusableView(
467 &new_focus_traversable
,
470 // Let's go down the FocusTraversable tree as much as we can.
471 while (new_focus_traversable
) {
473 focus_traversable
= new_focus_traversable
;
474 new_focus_traversable
= NULL
;
475 starting_view
= NULL
;
476 v
= focus_traversable
->GetFocusSearch()->FindNextFocusableView(
481 &new_focus_traversable
,
487 void FocusManager::RegisterAccelerator(
488 const ui::Accelerator
& accelerator
,
489 ui::AcceleratorManager::HandlerPriority priority
,
490 ui::AcceleratorTarget
* target
) {
491 accelerator_manager_
->Register(accelerator
, priority
, target
);
494 void FocusManager::UnregisterAccelerator(const ui::Accelerator
& accelerator
,
495 ui::AcceleratorTarget
* target
) {
496 accelerator_manager_
->Unregister(accelerator
, target
);
499 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget
* target
) {
500 accelerator_manager_
->UnregisterAll(target
);
503 bool FocusManager::ProcessAccelerator(const ui::Accelerator
& accelerator
) {
504 if (accelerator_manager_
->Process(accelerator
))
507 return delegate_
->ProcessAccelerator(accelerator
);
511 ui::AcceleratorTarget
* FocusManager::GetCurrentTargetForAccelerator(
512 const ui::Accelerator
& accelerator
) const {
513 ui::AcceleratorTarget
* target
=
514 accelerator_manager_
->GetCurrentTarget(accelerator
);
515 if (!target
&& delegate_
.get())
516 target
= delegate_
->GetCurrentTargetForAccelerator(accelerator
);
520 bool FocusManager::HasPriorityHandler(
521 const ui::Accelerator
& accelerator
) const {
522 return accelerator_manager_
->HasPriorityHandler(accelerator
);
526 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent
& key_event
) {
527 return key_event
.key_code() == ui::VKEY_TAB
&& !key_event
.IsControlDown();
530 ui::EventHandler
* FocusManager::GetEventHandler() {
532 event_handler_
.reset(new FocusManagerEventHandler(this));
533 return event_handler_
.get();
536 void FocusManager::ViewRemoved(View
* removed
) {
537 // If the view being removed contains (or is) the focused view,
538 // clear the focus. However, it's not safe to call ClearFocus()
539 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
540 // be called while the top level widget is being destroyed.
541 if (focused_view_
&& removed
->Contains(focused_view_
))
542 SetFocusedView(NULL
);
545 void FocusManager::AddFocusChangeListener(FocusChangeListener
* listener
) {
546 focus_change_listeners_
.AddObserver(listener
);
549 void FocusManager::RemoveFocusChangeListener(FocusChangeListener
* listener
) {
550 focus_change_listeners_
.RemoveObserver(listener
);
553 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent
& event
) {
554 if (event
.IsShiftDown() || event
.IsControlDown() || event
.IsAltDown())
557 const int key_code
= event
.key_code();
558 if (key_code
== ui::VKEY_LEFT
|| key_code
== ui::VKEY_UP
) {
562 if (key_code
== ui::VKEY_RIGHT
|| key_code
== ui::VKEY_DOWN
) {