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"
33 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
34 static const int kEventFlagsMask
= ui::EF_SHIFT_DOWN
| ui::EF_CONTROL_DOWN
|
35 ui::EF_ALT_DOWN
| ui::EF_COMMAND_DOWN
;
37 static const int kEventFlagsMask
= ui::EF_SHIFT_DOWN
| ui::EF_CONTROL_DOWN
|
41 static inline int CalculateModifiers(const ui::KeyEvent
& event
) {
42 return event
.flags() & kEventFlagsMask
;
47 bool FocusManager::arrow_key_traversal_enabled_
= false;
49 FocusManager::FocusManager(Widget
* widget
, FocusManagerDelegate
* delegate
)
53 accelerator_manager_(new ui::AcceleratorManager
),
54 shortcut_handling_suspended_(false),
55 focus_change_reason_(kReasonDirectFocusChange
),
56 is_changing_focus_(false) {
58 stored_focused_view_storage_id_
=
59 ViewStorage::GetInstance()->CreateStorageID();
62 FocusManager::~FocusManager() {
65 bool FocusManager::OnKeyEvent(const ui::KeyEvent
& event
) {
66 const int key_code
= event
.key_code();
68 if (event
.type() != ui::ET_KEY_PRESSED
&& event
.type() != ui::ET_KEY_RELEASED
)
71 if (shortcut_handling_suspended())
74 int modifiers
= CalculateModifiers(event
);
75 ui::Accelerator
accelerator(event
.key_code(), modifiers
);
76 accelerator
.set_type(event
.type());
77 accelerator
.set_is_repeat(event
.IsRepeat());
79 if (event
.type() == ui::ET_KEY_PRESSED
) {
80 // If the focused view wants to process the key event as is, let it be.
81 if (focused_view_
&& focused_view_
->SkipDefaultKeyEventProcessing(event
) &&
82 !accelerator_manager_
->HasPriorityHandler(accelerator
))
85 // Intercept Tab related messages for focus traversal.
86 // Note that we don't do focus traversal if the root window is not part of
87 // the active window hierarchy as this would mean we have no focused view
88 // and would focus the first focusable view.
89 if (IsTabTraversalKeyEvent(event
)) {
90 AdvanceFocus(event
.IsShiftDown());
94 if (arrow_key_traversal_enabled_
&& ProcessArrowKeyTraversal(event
))
97 // Intercept arrow key messages to switch between grouped views.
98 if (focused_view_
&& focused_view_
->GetGroup() != -1 &&
99 (key_code
== ui::VKEY_UP
|| key_code
== ui::VKEY_DOWN
||
100 key_code
== ui::VKEY_LEFT
|| key_code
== ui::VKEY_RIGHT
)) {
101 bool next
= (key_code
== ui::VKEY_RIGHT
|| key_code
== ui::VKEY_DOWN
);
103 focused_view_
->parent()->GetViewsInGroup(focused_view_
->GetGroup(),
105 View::Views::const_iterator
i(
106 std::find(views
.begin(), views
.end(), focused_view_
));
107 DCHECK(i
!= views
.end());
108 int index
= static_cast<int>(i
- views
.begin());
109 index
+= next
? 1 : -1;
111 index
= static_cast<int>(views
.size()) - 1;
112 } else if (index
>= static_cast<int>(views
.size())) {
115 SetFocusedViewWithReason(views
[index
], kReasonFocusTraversal
);
120 // Process keyboard accelerators.
121 // If the key combination matches an accelerator, the accelerator is
122 // triggered, otherwise the key event is processed as usual.
123 if (ProcessAccelerator(accelerator
)) {
124 // If a shortcut was activated for this keydown message, do not propagate
125 // the event further.
131 void FocusManager::ValidateFocusedView() {
132 if (focused_view_
&& !ContainsView(focused_view_
))
136 // Tests whether a view is valid, whether it still belongs to the window
137 // hierarchy of the FocusManager.
138 bool FocusManager::ContainsView(View
* view
) {
139 Widget
* widget
= view
->GetWidget();
140 return widget
? widget
->GetFocusManager() == this : false;
143 void FocusManager::AdvanceFocus(bool reverse
) {
144 View
* v
= GetNextFocusableView(focused_view_
, NULL
, reverse
, false);
145 // Note: Do not skip this next block when v == focused_view_. If the user
146 // tabs past the last focusable element in a webpage, we'll get here, and if
147 // the TabContentsContainerView is the only focusable view (possible in
148 // fullscreen mode), we need to run this block in order to cycle around to the
149 // first element on the page.
151 views::View
* focused_view
= focused_view_
;
152 v
->AboutToRequestFocusFromTabTraversal(reverse
);
153 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
154 // don't change focus again.
155 if (focused_view
== focused_view_
)
156 SetFocusedViewWithReason(v
, kReasonFocusTraversal
);
160 void FocusManager::ClearNativeFocus() {
161 // Keep the top root window focused so we get keyboard events.
162 widget_
->ClearNativeFocus();
165 bool FocusManager::RotatePaneFocus(Direction direction
,
166 FocusCycleWrappingBehavior wrap
) {
167 // Get the list of all accessible panes.
168 std::vector
<View
*> panes
;
169 widget_
->widget_delegate()->GetAccessiblePanes(&panes
);
171 // Count the number of panes and set the default index if no pane
172 // is initially focused.
173 int count
= static_cast<int>(panes
.size());
177 // Initialize |index| to an appropriate starting index if nothing is
178 // focused initially.
179 int index
= direction
== kBackward
? 0 : count
- 1;
181 // Check to see if a pane already has focus and update the index accordingly.
182 const views::View
* focused_view
= GetFocusedView();
184 for (int i
= 0; i
< count
; i
++) {
185 if (panes
[i
] && panes
[i
]->Contains(focused_view
)) {
193 int start_index
= index
;
195 if (direction
== kBackward
)
200 if (wrap
== kNoWrap
&& (index
>= count
|| index
< 0))
202 index
= (index
+ count
) % count
;
204 // Ensure that we don't loop more than once.
205 if (index
== start_index
)
208 views::View
* pane
= panes
[index
];
211 if (!pane
->visible())
214 pane
->RequestFocus();
215 focused_view
= GetFocusedView();
216 if (pane
== focused_view
|| pane
->Contains(focused_view
))
223 View
* FocusManager::GetNextFocusableView(View
* original_starting_view
,
224 Widget
* starting_widget
,
227 FocusTraversable
* focus_traversable
= NULL
;
229 // Let's revalidate the focused view.
230 ValidateFocusedView();
232 View
* starting_view
= NULL
;
233 if (original_starting_view
) {
234 // Search up the containment hierarchy to see if a view is acting as
235 // a pane, and wants to implement its own focus traversable to keep
236 // the focus trapped within that pane.
237 View
* pane_search
= original_starting_view
;
238 while (pane_search
) {
239 focus_traversable
= pane_search
->GetPaneFocusTraversable();
240 if (focus_traversable
) {
241 starting_view
= original_starting_view
;
244 pane_search
= pane_search
->parent();
247 if (!focus_traversable
) {
249 // If the starting view has a focus traversable, use it.
250 // This is the case with NativeWidgetWins for example.
251 focus_traversable
= original_starting_view
->GetFocusTraversable();
253 // Otherwise default to the root view.
254 if (!focus_traversable
) {
256 original_starting_view
->GetWidget()->GetFocusTraversable();
257 starting_view
= original_starting_view
;
260 // When you are going back, starting view's FocusTraversable
261 // should not be used.
263 original_starting_view
->GetWidget()->GetFocusTraversable();
264 starting_view
= original_starting_view
;
268 Widget
* widget
= starting_widget
? starting_widget
: widget_
;
269 focus_traversable
= widget
->GetFocusTraversable();
272 // Traverse the FocusTraversable tree down to find the focusable view.
273 View
* v
= FindFocusableView(focus_traversable
, starting_view
, reverse
);
277 // Let's go up in the FocusTraversable tree.
278 FocusTraversable
* parent_focus_traversable
=
279 focus_traversable
->GetFocusTraversableParent();
280 starting_view
= focus_traversable
->GetFocusTraversableParentView();
281 while (parent_focus_traversable
) {
282 FocusTraversable
* new_focus_traversable
= NULL
;
283 View
* new_starting_view
= NULL
;
284 // When we are going backward, the parent view might gain the next focus.
285 bool check_starting_view
= reverse
;
286 v
= parent_focus_traversable
->GetFocusSearch()->FindNextFocusableView(
287 starting_view
, reverse
, FocusSearch::UP
,
288 check_starting_view
, &new_focus_traversable
, &new_starting_view
);
290 if (new_focus_traversable
) {
293 // There is a FocusTraversable, traverse it down.
294 v
= FindFocusableView(new_focus_traversable
, NULL
, reverse
);
300 starting_view
= focus_traversable
->GetFocusTraversableParentView();
301 parent_focus_traversable
=
302 parent_focus_traversable
->GetFocusTraversableParent();
305 // If we get here, we have reached the end of the focus hierarchy, let's
306 // loop. Make sure there was at least a view to start with, to prevent
307 // infinitely looping in empty windows.
308 if (!dont_loop
&& original_starting_view
) {
309 // Easy, just clear the selection and press tab again.
310 // By calling with NULL as the starting view, we'll start from either
311 // the starting views widget or |widget_|.
312 Widget
* widget
= original_starting_view
->GetWidget();
313 if (widget
->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
315 return GetNextFocusableView(NULL
, widget
, reverse
, true);
321 void FocusManager::SetFocusedViewWithReason(
322 View
* view
, FocusChangeReason reason
) {
323 if (focused_view_
== view
) {
324 // In the case that the widget lost the focus and gained it back without
325 // changing the focused view, we have to make the text input client focused.
326 // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
327 FocusTextInputClient(focused_view_
);
331 base::AutoReset
<bool> auto_changing_focus(&is_changing_focus_
, true);
332 // Update the reason for the focus change (since this is checked by
333 // some listeners), then notify all listeners.
334 focus_change_reason_
= reason
;
335 FOR_EACH_OBSERVER(FocusChangeListener
, focus_change_listeners_
,
336 OnWillChangeFocus(focused_view_
, view
));
338 View
* old_focused_view
= focused_view_
;
339 focused_view_
= view
;
340 if (old_focused_view
) {
341 old_focused_view
->Blur();
342 BlurTextInputClient(old_focused_view
);
344 // Also make |focused_view_| the stored focus view. This way the stored focus
345 // view is remembered if focus changes are requested prior to a show or while
347 SetStoredFocusView(focused_view_
);
349 FocusTextInputClient(focused_view_
);
350 focused_view_
->Focus();
353 FOR_EACH_OBSERVER(FocusChangeListener
, focus_change_listeners_
,
354 OnDidChangeFocus(old_focused_view
, focused_view_
));
357 void FocusManager::ClearFocus() {
358 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
359 // persist it in this case.
360 views::View
* focused_view
= GetStoredFocusView();
361 SetFocusedView(NULL
);
363 SetStoredFocusView(focused_view
);
366 void FocusManager::AdvanceFocusIfNecessary() {
367 // If widget is inactive, there is no focused view to check. The stored view
368 // will also be checked for focusability when it is being restored.
369 if (!widget_
->IsActive())
372 // If widget is active and focused view is not focusable, advance focus or,
373 // if not possible, clear focus.
374 if (focused_view_
&& !focused_view_
->IsAccessibilityFocusable()) {
376 if (focused_view_
&& !focused_view_
->IsAccessibilityFocusable())
381 void FocusManager::StoreFocusedView(bool clear_native_focus
) {
382 View
* focused_view
= focused_view_
;
383 // Don't do anything if no focused view. Storing the view (which is NULL), in
384 // this case, would clobber the view that was previously saved.
388 View
* v
= focused_view_
;
390 if (clear_native_focus
) {
391 // Temporarily disable notification. ClearFocus() will set the focus to the
392 // main browser window. This extra focus bounce which happens during
393 // deactivation can confuse registered WidgetFocusListeners, as the focus
394 // is not changing due to a user-initiated event.
395 AutoNativeNotificationDisabler local_notification_disabler
;
396 // ClearFocus() also stores the focused view.
399 SetFocusedView(NULL
);
400 SetStoredFocusView(focused_view
);
404 v
->SchedulePaint(); // Remove focus border.
407 bool FocusManager::RestoreFocusedView() {
408 View
* view
= GetStoredFocusView();
410 if (ContainsView(view
)) {
411 if (!view
->IsFocusable() && view
->IsAccessibilityFocusable()) {
412 // RequestFocus would fail, but we want to restore focus to controls
413 // that had focus in accessibility mode.
414 SetFocusedViewWithReason(view
, kReasonFocusRestore
);
416 // This usually just sets the focus if this view is focusable, but
417 // let the view override RequestFocus if necessary.
418 view
->RequestFocus();
420 // If it succeeded, the reason would be incorrect; set it to
422 if (focused_view_
== view
)
423 focus_change_reason_
= kReasonFocusRestore
;
431 void FocusManager::SetStoredFocusView(View
* focus_view
) {
432 ViewStorage
* view_storage
= ViewStorage::GetInstance();
434 // This should never happen but bug 981648 seems to indicate it could.
439 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
440 // is stored twice causing an assert. We should find a better alternative than
441 // removing the view from the storage explicitly.
442 view_storage
->RemoveView(stored_focused_view_storage_id_
);
447 view_storage
->StoreView(stored_focused_view_storage_id_
, focus_view
);
450 View
* FocusManager::GetStoredFocusView() {
451 ViewStorage
* view_storage
= ViewStorage::GetInstance();
453 // This should never happen but bug 981648 seems to indicate it could.
458 return view_storage
->RetrieveView(stored_focused_view_storage_id_
);
461 void FocusManager::ClearStoredFocusedView() {
462 SetStoredFocusView(NULL
);
465 void FocusManager::OnTextInputClientChanged(View
* view
) {
466 if (view
== focused_view_
)
467 FocusTextInputClient(view
);
470 void FocusManager::FocusTextInputClient(View
* view
) {
471 if (!switches::IsTextInputFocusManagerEnabled())
474 // If the widget is not active, do not steal the text input focus.
475 if (!widget_
->IsActive())
478 ui::TextInputClient
* text_input_client
=
479 view
? view
->GetTextInputClient() : NULL
;
480 ui::TextInputFocusManager::GetInstance()->
481 FocusTextInputClient(text_input_client
);
482 ui::InputMethod
* input_method
= widget_
->GetHostInputMethod();
484 input_method
->OnTextInputTypeChanged(text_input_client
);
485 input_method
->OnCaretBoundsChanged(text_input_client
);
489 void FocusManager::BlurTextInputClient(View
* view
) {
490 if (!switches::IsTextInputFocusManagerEnabled())
493 ui::TextInputClient
* text_input_client
=
494 view
? view
->GetTextInputClient() : NULL
;
495 if (text_input_client
&& text_input_client
->HasCompositionText()) {
496 text_input_client
->ConfirmCompositionText();
497 ui::InputMethod
* input_method
= widget_
->GetHostInputMethod();
498 if (input_method
&& input_method
->GetTextInputClient() == text_input_client
)
499 input_method
->CancelComposition(text_input_client
);
501 ui::TextInputFocusManager::GetInstance()->
502 BlurTextInputClient(text_input_client
);
505 // Find the next (previous if reverse is true) focusable view for the specified
506 // FocusTraversable, starting at the specified view, traversing down the
507 // FocusTraversable hierarchy.
508 View
* FocusManager::FindFocusableView(FocusTraversable
* focus_traversable
,
511 FocusTraversable
* new_focus_traversable
= NULL
;
512 View
* new_starting_view
= NULL
;
513 View
* v
= focus_traversable
->GetFocusSearch()->FindNextFocusableView(
518 &new_focus_traversable
,
521 // Let's go down the FocusTraversable tree as much as we can.
522 while (new_focus_traversable
) {
524 focus_traversable
= new_focus_traversable
;
525 new_focus_traversable
= NULL
;
526 starting_view
= NULL
;
527 v
= focus_traversable
->GetFocusSearch()->FindNextFocusableView(
532 &new_focus_traversable
,
538 void FocusManager::RegisterAccelerator(
539 const ui::Accelerator
& accelerator
,
540 ui::AcceleratorManager::HandlerPriority priority
,
541 ui::AcceleratorTarget
* target
) {
542 accelerator_manager_
->Register(accelerator
, priority
, target
);
545 void FocusManager::UnregisterAccelerator(const ui::Accelerator
& accelerator
,
546 ui::AcceleratorTarget
* target
) {
547 accelerator_manager_
->Unregister(accelerator
, target
);
550 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget
* target
) {
551 accelerator_manager_
->UnregisterAll(target
);
554 bool FocusManager::ProcessAccelerator(const ui::Accelerator
& accelerator
) {
555 if (accelerator_manager_
->Process(accelerator
))
558 return delegate_
->ProcessAccelerator(accelerator
);
562 ui::AcceleratorTarget
* FocusManager::GetCurrentTargetForAccelerator(
563 const ui::Accelerator
& accelerator
) const {
564 ui::AcceleratorTarget
* target
=
565 accelerator_manager_
->GetCurrentTarget(accelerator
);
566 if (!target
&& delegate_
.get())
567 target
= delegate_
->GetCurrentTargetForAccelerator(accelerator
);
571 bool FocusManager::HasPriorityHandler(
572 const ui::Accelerator
& accelerator
) const {
573 return accelerator_manager_
->HasPriorityHandler(accelerator
);
577 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent
& key_event
) {
578 return key_event
.key_code() == ui::VKEY_TAB
&& !key_event
.IsControlDown();
581 void FocusManager::ViewRemoved(View
* removed
) {
582 // If the view being removed contains (or is) the focused view,
583 // clear the focus. However, it's not safe to call ClearFocus()
584 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
585 // be called while the top level widget is being destroyed.
586 if (focused_view_
&& removed
->Contains(focused_view_
))
587 SetFocusedView(NULL
);
590 void FocusManager::AddFocusChangeListener(FocusChangeListener
* listener
) {
591 focus_change_listeners_
.AddObserver(listener
);
594 void FocusManager::RemoveFocusChangeListener(FocusChangeListener
* listener
) {
595 focus_change_listeners_
.RemoveObserver(listener
);
598 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent
& event
) {
599 if (event
.IsShiftDown() || event
.IsControlDown() || event
.IsAltDown())
602 const int key_code
= event
.key_code();
603 if (key_code
== ui::VKEY_LEFT
|| key_code
== ui::VKEY_UP
) {
607 if (key_code
== ui::VKEY_RIGHT
|| key_code
== ui::VKEY_DOWN
) {