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/base/ime/input_method.h"
15 #include "ui/base/ime/text_input_client.h"
16 #include "ui/base/ime/text_input_focus_manager.h"
17 #include "ui/base/ui_base_switches_util.h"
18 #include "ui/events/event.h"
19 #include "ui/events/keycodes/keyboard_codes.h"
20 #include "ui/views/focus/focus_manager_delegate.h"
21 #include "ui/views/focus/focus_search.h"
22 #include "ui/views/focus/view_storage.h"
23 #include "ui/views/focus/widget_focus_manager.h"
24 #include "ui/views/view.h"
25 #include "ui/views/widget/root_view.h"
26 #include "ui/views/widget/widget.h"
27 #include "ui/views/widget/widget_delegate.h"
35 bool FocusManager::shortcut_handling_suspended_
= false;
36 bool FocusManager::arrow_key_traversal_enabled_
= false;
38 FocusManager::FocusManager(Widget
* widget
, FocusManagerDelegate
* delegate
)
42 accelerator_manager_(new ui::AcceleratorManager
),
43 focus_change_reason_(kReasonDirectFocusChange
),
44 is_changing_focus_(false) {
46 stored_focused_view_storage_id_
=
47 ViewStorage::GetInstance()->CreateStorageID();
50 FocusManager::~FocusManager() {
53 bool FocusManager::OnKeyEvent(const ui::KeyEvent
& event
) {
54 const int key_code
= event
.key_code();
56 if (event
.type() != ui::ET_KEY_PRESSED
&& event
.type() != ui::ET_KEY_RELEASED
)
59 if (shortcut_handling_suspended())
62 int modifiers
= ui::EF_NONE
;
63 if (event
.IsShiftDown())
64 modifiers
|= ui::EF_SHIFT_DOWN
;
65 if (event
.IsControlDown())
66 modifiers
|= ui::EF_CONTROL_DOWN
;
67 if (event
.IsAltDown())
68 modifiers
|= ui::EF_ALT_DOWN
;
69 ui::Accelerator
accelerator(event
.key_code(), modifiers
);
70 accelerator
.set_type(event
.type());
71 accelerator
.set_is_repeat(event
.IsRepeat());
73 if (event
.type() == ui::ET_KEY_PRESSED
) {
74 // If the focused view wants to process the key event as is, let it be.
75 if (focused_view_
&& focused_view_
->SkipDefaultKeyEventProcessing(event
) &&
76 !accelerator_manager_
->HasPriorityHandler(accelerator
))
79 // Intercept Tab related messages for focus traversal.
80 // Note that we don't do focus traversal if the root window is not part of
81 // the active window hierarchy as this would mean we have no focused view
82 // and would focus the first focusable view.
83 if (IsTabTraversalKeyEvent(event
)) {
84 AdvanceFocus(event
.IsShiftDown());
88 if (arrow_key_traversal_enabled_
&& ProcessArrowKeyTraversal(event
))
91 // Intercept arrow key messages to switch between grouped views.
92 if (focused_view_
&& focused_view_
->GetGroup() != -1 &&
93 (key_code
== ui::VKEY_UP
|| key_code
== ui::VKEY_DOWN
||
94 key_code
== ui::VKEY_LEFT
|| key_code
== ui::VKEY_RIGHT
)) {
95 bool next
= (key_code
== ui::VKEY_RIGHT
|| key_code
== ui::VKEY_DOWN
);
97 focused_view_
->parent()->GetViewsInGroup(focused_view_
->GetGroup(),
99 View::Views::const_iterator
i(
100 std::find(views
.begin(), views
.end(), focused_view_
));
101 DCHECK(i
!= views
.end());
102 int index
= static_cast<int>(i
- views
.begin());
103 index
+= next
? 1 : -1;
105 index
= static_cast<int>(views
.size()) - 1;
106 } else if (index
>= static_cast<int>(views
.size())) {
109 SetFocusedViewWithReason(views
[index
], kReasonFocusTraversal
);
114 // Process keyboard accelerators.
115 // If the key combination matches an accelerator, the accelerator is
116 // triggered, otherwise the key event is processed as usual.
117 if (ProcessAccelerator(accelerator
)) {
118 // If a shortcut was activated for this keydown message, do not propagate
119 // the event further.
125 void FocusManager::ValidateFocusedView() {
126 if (focused_view_
&& !ContainsView(focused_view_
))
130 // Tests whether a view is valid, whether it still belongs to the window
131 // hierarchy of the FocusManager.
132 bool FocusManager::ContainsView(View
* view
) {
133 Widget
* widget
= view
->GetWidget();
134 return widget
? widget
->GetFocusManager() == this : false;
137 void FocusManager::AdvanceFocus(bool reverse
) {
138 View
* v
= GetNextFocusableView(focused_view_
, NULL
, reverse
, false);
139 // Note: Do not skip this next block when v == focused_view_. If the user
140 // tabs past the last focusable element in a webpage, we'll get here, and if
141 // the TabContentsContainerView is the only focusable view (possible in
142 // fullscreen mode), we need to run this block in order to cycle around to the
143 // first element on the page.
145 views::View
* focused_view
= focused_view_
;
146 v
->AboutToRequestFocusFromTabTraversal(reverse
);
147 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
148 // don't change focus again.
149 if (focused_view
== focused_view_
)
150 SetFocusedViewWithReason(v
, kReasonFocusTraversal
);
154 void FocusManager::ClearNativeFocus() {
155 // Keep the top root window focused so we get keyboard events.
156 widget_
->ClearNativeFocus();
159 bool FocusManager::RotatePaneFocus(Direction direction
,
160 FocusCycleWrappingBehavior wrap
) {
161 // Get the list of all accessible panes.
162 std::vector
<View
*> panes
;
163 widget_
->widget_delegate()->GetAccessiblePanes(&panes
);
165 // Count the number of panes and set the default index if no pane
166 // is initially focused.
167 int count
= static_cast<int>(panes
.size());
171 // Initialize |index| to an appropriate starting index if nothing is
172 // focused initially.
173 int index
= direction
== kBackward
? 0 : count
- 1;
175 // Check to see if a pane already has focus and update the index accordingly.
176 const views::View
* focused_view
= GetFocusedView();
178 for (int i
= 0; i
< count
; i
++) {
179 if (panes
[i
] && panes
[i
]->Contains(focused_view
)) {
187 int start_index
= index
;
189 if (direction
== kBackward
)
194 if (wrap
== kNoWrap
&& (index
>= count
|| index
< 0))
196 index
= (index
+ count
) % count
;
198 // Ensure that we don't loop more than once.
199 if (index
== start_index
)
202 views::View
* pane
= panes
[index
];
205 if (!pane
->visible())
208 pane
->RequestFocus();
209 focused_view
= GetFocusedView();
210 if (pane
== focused_view
|| pane
->Contains(focused_view
))
217 View
* FocusManager::GetNextFocusableView(View
* original_starting_view
,
218 Widget
* starting_widget
,
221 FocusTraversable
* focus_traversable
= NULL
;
223 // Let's revalidate the focused view.
224 ValidateFocusedView();
226 View
* starting_view
= NULL
;
227 if (original_starting_view
) {
228 // Search up the containment hierarchy to see if a view is acting as
229 // a pane, and wants to implement its own focus traversable to keep
230 // the focus trapped within that pane.
231 View
* pane_search
= original_starting_view
;
232 while (pane_search
) {
233 focus_traversable
= pane_search
->GetPaneFocusTraversable();
234 if (focus_traversable
) {
235 starting_view
= original_starting_view
;
238 pane_search
= pane_search
->parent();
241 if (!focus_traversable
) {
243 // If the starting view has a focus traversable, use it.
244 // This is the case with NativeWidgetWins for example.
245 focus_traversable
= original_starting_view
->GetFocusTraversable();
247 // Otherwise default to the root view.
248 if (!focus_traversable
) {
250 original_starting_view
->GetWidget()->GetFocusTraversable();
251 starting_view
= original_starting_view
;
254 // When you are going back, starting view's FocusTraversable
255 // should not be used.
257 original_starting_view
->GetWidget()->GetFocusTraversable();
258 starting_view
= original_starting_view
;
262 Widget
* widget
= starting_widget
? starting_widget
: widget_
;
263 focus_traversable
= widget
->GetFocusTraversable();
266 // Traverse the FocusTraversable tree down to find the focusable view.
267 View
* v
= FindFocusableView(focus_traversable
, starting_view
, reverse
);
271 // Let's go up in the FocusTraversable tree.
272 FocusTraversable
* parent_focus_traversable
=
273 focus_traversable
->GetFocusTraversableParent();
274 starting_view
= focus_traversable
->GetFocusTraversableParentView();
275 while (parent_focus_traversable
) {
276 FocusTraversable
* new_focus_traversable
= NULL
;
277 View
* new_starting_view
= NULL
;
278 // When we are going backward, the parent view might gain the next focus.
279 bool check_starting_view
= reverse
;
280 v
= parent_focus_traversable
->GetFocusSearch()->FindNextFocusableView(
281 starting_view
, reverse
, FocusSearch::UP
,
282 check_starting_view
, &new_focus_traversable
, &new_starting_view
);
284 if (new_focus_traversable
) {
287 // There is a FocusTraversable, traverse it down.
288 v
= FindFocusableView(new_focus_traversable
, NULL
, reverse
);
294 starting_view
= focus_traversable
->GetFocusTraversableParentView();
295 parent_focus_traversable
=
296 parent_focus_traversable
->GetFocusTraversableParent();
299 // If we get here, we have reached the end of the focus hierarchy, let's
300 // loop. Make sure there was at least a view to start with, to prevent
301 // infinitely looping in empty windows.
302 if (!dont_loop
&& original_starting_view
) {
303 // Easy, just clear the selection and press tab again.
304 // By calling with NULL as the starting view, we'll start from either
305 // the starting views widget or |widget_|.
306 Widget
* widget
= original_starting_view
->GetWidget();
307 if (widget
->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
309 return GetNextFocusableView(NULL
, widget
, reverse
, true);
315 void FocusManager::SetFocusedViewWithReason(
316 View
* view
, FocusChangeReason reason
) {
317 if (focused_view_
== view
) {
318 // In the case that the widget lost the focus and gained it back without
319 // changing the focused view, we have to make the text input client focused.
320 // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
321 FocusTextInputClient(focused_view_
);
325 base::AutoReset
<bool> auto_changing_focus(&is_changing_focus_
, true);
326 // Update the reason for the focus change (since this is checked by
327 // some listeners), then notify all listeners.
328 focus_change_reason_
= reason
;
329 FOR_EACH_OBSERVER(FocusChangeListener
, focus_change_listeners_
,
330 OnWillChangeFocus(focused_view_
, view
));
332 View
* old_focused_view
= focused_view_
;
333 focused_view_
= view
;
334 if (old_focused_view
) {
335 old_focused_view
->Blur();
336 BlurTextInputClient(old_focused_view
);
338 // Also make |focused_view_| the stored focus view. This way the stored focus
339 // view is remembered if focus changes are requested prior to a show or while
341 SetStoredFocusView(focused_view_
);
343 FocusTextInputClient(focused_view_
);
344 focused_view_
->Focus();
347 FOR_EACH_OBSERVER(FocusChangeListener
, focus_change_listeners_
,
348 OnDidChangeFocus(old_focused_view
, focused_view_
));
351 void FocusManager::ClearFocus() {
352 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
353 // persist it in this case.
354 views::View
* focused_view
= GetStoredFocusView();
355 SetFocusedView(NULL
);
357 SetStoredFocusView(focused_view
);
360 void FocusManager::StoreFocusedView(bool clear_native_focus
) {
361 View
* focused_view
= focused_view_
;
362 // Don't do anything if no focused view. Storing the view (which is NULL), in
363 // this case, would clobber the view that was previously saved.
367 View
* v
= focused_view_
;
369 if (clear_native_focus
) {
370 // Temporarily disable notification. ClearFocus() will set the focus to the
371 // main browser window. This extra focus bounce which happens during
372 // deactivation can confuse registered WidgetFocusListeners, as the focus
373 // is not changing due to a user-initiated event.
374 AutoNativeNotificationDisabler local_notification_disabler
;
375 // ClearFocus() also stores the focused view.
378 SetFocusedView(NULL
);
379 SetStoredFocusView(focused_view
);
383 v
->SchedulePaint(); // Remove focus border.
386 bool FocusManager::RestoreFocusedView() {
387 View
* view
= GetStoredFocusView();
389 if (ContainsView(view
)) {
390 if (!view
->IsFocusable() && view
->IsAccessibilityFocusable()) {
391 // RequestFocus would fail, but we want to restore focus to controls
392 // that had focus in accessibility mode.
393 SetFocusedViewWithReason(view
, kReasonFocusRestore
);
395 // This usually just sets the focus if this view is focusable, but
396 // let the view override RequestFocus if necessary.
397 view
->RequestFocus();
399 // If it succeeded, the reason would be incorrect; set it to
401 if (focused_view_
== view
)
402 focus_change_reason_
= kReasonFocusRestore
;
410 void FocusManager::SetStoredFocusView(View
* focus_view
) {
411 ViewStorage
* view_storage
= ViewStorage::GetInstance();
413 // This should never happen but bug 981648 seems to indicate it could.
418 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
419 // is stored twice causing an assert. We should find a better alternative than
420 // removing the view from the storage explicitly.
421 view_storage
->RemoveView(stored_focused_view_storage_id_
);
426 view_storage
->StoreView(stored_focused_view_storage_id_
, focus_view
);
429 View
* FocusManager::GetStoredFocusView() {
430 ViewStorage
* view_storage
= ViewStorage::GetInstance();
432 // This should never happen but bug 981648 seems to indicate it could.
437 return view_storage
->RetrieveView(stored_focused_view_storage_id_
);
440 void FocusManager::ClearStoredFocusedView() {
441 SetStoredFocusView(NULL
);
444 void FocusManager::OnTextInputClientChanged(View
* view
) {
445 if (view
== focused_view_
)
446 FocusTextInputClient(view
);
449 void FocusManager::FocusTextInputClient(View
* view
) {
450 if (!switches::IsTextInputFocusManagerEnabled())
453 // If the widget is not active, do not steal the text input focus.
454 if (!widget_
->IsActive())
457 ui::TextInputClient
* text_input_client
=
458 view
? view
->GetTextInputClient() : NULL
;
459 ui::TextInputFocusManager::GetInstance()->
460 FocusTextInputClient(text_input_client
);
461 ui::InputMethod
* input_method
= widget_
->GetHostInputMethod();
463 input_method
->OnTextInputTypeChanged(text_input_client
);
464 input_method
->OnCaretBoundsChanged(text_input_client
);
468 void FocusManager::BlurTextInputClient(View
* view
) {
469 if (!switches::IsTextInputFocusManagerEnabled())
472 ui::TextInputClient
* text_input_client
=
473 view
? view
->GetTextInputClient() : NULL
;
474 if (text_input_client
&& text_input_client
->HasCompositionText()) {
475 text_input_client
->ConfirmCompositionText();
476 ui::InputMethod
* input_method
= widget_
->GetHostInputMethod();
477 if (input_method
&& input_method
->GetTextInputClient() == text_input_client
)
478 input_method
->CancelComposition(text_input_client
);
480 ui::TextInputFocusManager::GetInstance()->
481 BlurTextInputClient(text_input_client
);
484 // Find the next (previous if reverse is true) focusable view for the specified
485 // FocusTraversable, starting at the specified view, traversing down the
486 // FocusTraversable hierarchy.
487 View
* FocusManager::FindFocusableView(FocusTraversable
* focus_traversable
,
490 FocusTraversable
* new_focus_traversable
= NULL
;
491 View
* new_starting_view
= NULL
;
492 View
* v
= focus_traversable
->GetFocusSearch()->FindNextFocusableView(
497 &new_focus_traversable
,
500 // Let's go down the FocusTraversable tree as much as we can.
501 while (new_focus_traversable
) {
503 focus_traversable
= new_focus_traversable
;
504 new_focus_traversable
= NULL
;
505 starting_view
= NULL
;
506 v
= focus_traversable
->GetFocusSearch()->FindNextFocusableView(
511 &new_focus_traversable
,
517 void FocusManager::RegisterAccelerator(
518 const ui::Accelerator
& accelerator
,
519 ui::AcceleratorManager::HandlerPriority priority
,
520 ui::AcceleratorTarget
* target
) {
521 accelerator_manager_
->Register(accelerator
, priority
, target
);
524 void FocusManager::UnregisterAccelerator(const ui::Accelerator
& accelerator
,
525 ui::AcceleratorTarget
* target
) {
526 accelerator_manager_
->Unregister(accelerator
, target
);
529 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget
* target
) {
530 accelerator_manager_
->UnregisterAll(target
);
533 bool FocusManager::ProcessAccelerator(const ui::Accelerator
& accelerator
) {
534 if (accelerator_manager_
->Process(accelerator
))
537 return delegate_
->ProcessAccelerator(accelerator
);
541 ui::AcceleratorTarget
* FocusManager::GetCurrentTargetForAccelerator(
542 const ui::Accelerator
& accelerator
) const {
543 ui::AcceleratorTarget
* target
=
544 accelerator_manager_
->GetCurrentTarget(accelerator
);
545 if (!target
&& delegate_
.get())
546 target
= delegate_
->GetCurrentTargetForAccelerator(accelerator
);
550 bool FocusManager::HasPriorityHandler(
551 const ui::Accelerator
& accelerator
) const {
552 return accelerator_manager_
->HasPriorityHandler(accelerator
);
556 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent
& key_event
) {
557 return key_event
.key_code() == ui::VKEY_TAB
&& !key_event
.IsControlDown();
560 void FocusManager::ViewRemoved(View
* removed
) {
561 // If the view being removed contains (or is) the focused view,
562 // clear the focus. However, it's not safe to call ClearFocus()
563 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
564 // be called while the top level widget is being destroyed.
565 if (focused_view_
&& removed
->Contains(focused_view_
))
566 SetFocusedView(NULL
);
569 void FocusManager::AddFocusChangeListener(FocusChangeListener
* listener
) {
570 focus_change_listeners_
.AddObserver(listener
);
573 void FocusManager::RemoveFocusChangeListener(FocusChangeListener
* listener
) {
574 focus_change_listeners_
.RemoveObserver(listener
);
577 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent
& event
) {
578 if (event
.IsShiftDown() || event
.IsControlDown() || event
.IsAltDown())
581 const int key_code
= event
.key_code();
582 if (key_code
== ui::VKEY_LEFT
|| key_code
== ui::VKEY_UP
) {
586 if (key_code
== ui::VKEY_RIGHT
|| key_code
== ui::VKEY_DOWN
) {