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.
4
5 #include "ui/views/focus/focus_manager.h"
6
7 #include <algorithm>
8 #include <vector>
9
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"
24
25 namespace views {
26
27 namespace {
28
29 } // namespace
30
31 bool FocusManager::shortcut_handling_suspended_ = false;
32 bool FocusManager::arrow_key_traversal_enabled_ = false;
33
FocusManager(Widget * widget,FocusManagerDelegate * delegate)34 FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
35 : widget_(widget),
36 delegate_(delegate),
37 focused_view_(NULL),
38 accelerator_manager_(new ui::AcceleratorManager),
39 focus_change_reason_(kReasonDirectFocusChange),
40 is_changing_focus_(false) {
41 DCHECK(widget_);
42 stored_focused_view_storage_id_ =
43 ViewStorage::GetInstance()->CreateStorageID();
44 }
45
~FocusManager()46 FocusManager::~FocusManager() {
47 }
48
OnKeyEvent(const ui::KeyEvent & event)49 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
50 const int key_code = event.key_code();
51
52 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
53 return false;
54
55 if (shortcut_handling_suspended())
56 return true;
57
58 int modifiers = ui::EF_NONE;
59 if (event.IsShiftDown())
60 modifiers |= ui::EF_SHIFT_DOWN;
61 if (event.IsControlDown())
62 modifiers |= ui::EF_CONTROL_DOWN;
63 if (event.IsAltDown())
64 modifiers |= ui::EF_ALT_DOWN;
65 ui::Accelerator accelerator(event.key_code(), modifiers);
66 accelerator.set_type(event.type());
67
68 if (event.type() == ui::ET_KEY_PRESSED) {
69 // If the focused view wants to process the key event as is, let it be.
70 if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
71 !accelerator_manager_->HasPriorityHandler(accelerator))
72 return true;
73
74 // Intercept Tab related messages for focus traversal.
75 // Note that we don't do focus traversal if the root window is not part of
76 // the active window hierarchy as this would mean we have no focused view
77 // and would focus the first focusable view.
78 #if defined(OS_WIN) && !defined(USE_AURA)
79 HWND top_window = widget_->GetNativeView();
80 HWND active_window = ::GetActiveWindow();
81 if ((active_window == top_window || ::IsChild(active_window, top_window)) &&
82 IsTabTraversalKeyEvent(event)) {
83 AdvanceFocus(event.IsShiftDown());
84 return false;
85 }
86 #else
87 if (IsTabTraversalKeyEvent(event)) {
88 AdvanceFocus(event.IsShiftDown());
89 return false;
90 }
91 #endif
92
93 if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
94 return false;
95
96 // Intercept arrow key messages to switch between grouped views.
97 if (focused_view_ && focused_view_->GetGroup() != -1 &&
98 (key_code == ui::VKEY_UP || key_code == ui::VKEY_DOWN ||
99 key_code == ui::VKEY_LEFT || key_code == ui::VKEY_RIGHT)) {
100 bool next = (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN);
101 View::Views views;
102 focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
103 &views);
104 View::Views::const_iterator i(
105 std::find(views.begin(), views.end(), focused_view_));
106 DCHECK(i != views.end());
107 int index = static_cast<int>(i - views.begin());
108 index += next ? 1 : -1;
109 if (index < 0) {
110 index = static_cast<int>(views.size()) - 1;
111 } else if (index >= static_cast<int>(views.size())) {
112 index = 0;
113 }
114 SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
115 return false;
116 }
117 }
118
119 // Process keyboard accelerators.
120 // If the key combination matches an accelerator, the accelerator is
121 // triggered, otherwise the key event is processed as usual.
122 if (ProcessAccelerator(accelerator)) {
123 // If a shortcut was activated for this keydown message, do not propagate
124 // the event further.
125 return false;
126 }
127 return true;
128 }
129
ValidateFocusedView()130 void FocusManager::ValidateFocusedView() {
131 if (focused_view_ && !ContainsView(focused_view_))
132 ClearFocus();
133 }
134
135 // Tests whether a view is valid, whether it still belongs to the window
136 // hierarchy of the FocusManager.
ContainsView(View * view)137 bool FocusManager::ContainsView(View* view) {
138 Widget* widget = view->GetWidget();
139 return widget ? widget->GetFocusManager() == this : false;
140 }
141
AdvanceFocus(bool reverse)142 void FocusManager::AdvanceFocus(bool reverse) {
143 View* v = GetNextFocusableView(focused_view_, NULL, reverse, false);
144 // Note: Do not skip this next block when v == focused_view_. If the user
145 // tabs past the last focusable element in a webpage, we'll get here, and if
146 // the TabContentsContainerView is the only focusable view (possible in
147 // fullscreen mode), we need to run this block in order to cycle around to the
148 // first element on the page.
149 if (v) {
150 views::View* focused_view = focused_view_;
151 v->AboutToRequestFocusFromTabTraversal(reverse);
152 // AboutToRequestFocusFromTabTraversal() may have changed focus. If it did,
153 // don't change focus again.
154 if (focused_view == focused_view_)
155 SetFocusedViewWithReason(v, kReasonFocusTraversal);
156 }
157 }
158
ClearNativeFocus()159 void FocusManager::ClearNativeFocus() {
160 // Keep the top root window focused so we get keyboard events.
161 widget_->ClearNativeFocus();
162 }
163
RotatePaneFocus(Direction direction,FocusCycleWrappingBehavior wrap)164 bool FocusManager::RotatePaneFocus(Direction direction,
165 FocusCycleWrappingBehavior wrap) {
166 // Get the list of all accessible panes.
167 std::vector<View*> panes;
168 widget_->widget_delegate()->GetAccessiblePanes(&panes);
169
170 // Count the number of panes and set the default index if no pane
171 // is initially focused.
172 int count = static_cast<int>(panes.size());
173 if (count == 0)
174 return false;
175
176 // Initialize |index| to an appropriate starting index if nothing is
177 // focused initially.
178 int index = direction == kBackward ? 0 : count - 1;
179
180 // Check to see if a pane already has focus and update the index accordingly.
181 const views::View* focused_view = GetFocusedView();
182 if (focused_view) {
183 for (int i = 0; i < count; i++) {
184 if (panes[i] && panes[i]->Contains(focused_view)) {
185 index = i;
186 break;
187 }
188 }
189 }
190
191 // Rotate focus.
192 int start_index = index;
193 for (;;) {
194 if (direction == kBackward)
195 index--;
196 else
197 index++;
198
199 if (wrap == kNoWrap && (index >= count || index < 0))
200 return false;
201 index = (index + count) % count;
202
203 // Ensure that we don't loop more than once.
204 if (index == start_index)
205 break;
206
207 views::View* pane = panes[index];
208 DCHECK(pane);
209
210 if (!pane->visible())
211 continue;
212
213 pane->RequestFocus();
214 focused_view = GetFocusedView();
215 if (pane == focused_view || pane->Contains(focused_view))
216 return true;
217 }
218
219 return false;
220 }
221
GetNextFocusableView(View * original_starting_view,Widget * starting_widget,bool reverse,bool dont_loop)222 View* FocusManager::GetNextFocusableView(View* original_starting_view,
223 Widget* starting_widget,
224 bool reverse,
225 bool dont_loop) {
226 FocusTraversable* focus_traversable = NULL;
227
228 // Let's revalidate the focused view.
229 ValidateFocusedView();
230
231 View* starting_view = NULL;
232 if (original_starting_view) {
233 // Search up the containment hierarchy to see if a view is acting as
234 // a pane, and wants to implement its own focus traversable to keep
235 // the focus trapped within that pane.
236 View* pane_search = original_starting_view;
237 while (pane_search) {
238 focus_traversable = pane_search->GetPaneFocusTraversable();
239 if (focus_traversable) {
240 starting_view = original_starting_view;
241 break;
242 }
243 pane_search = pane_search->parent();
244 }
245
246 if (!focus_traversable) {
247 if (!reverse) {
248 // If the starting view has a focus traversable, use it.
249 // This is the case with NativeWidgetWins for example.
250 focus_traversable = original_starting_view->GetFocusTraversable();
251
252 // Otherwise default to the root view.
253 if (!focus_traversable) {
254 focus_traversable =
255 original_starting_view->GetWidget()->GetFocusTraversable();
256 starting_view = original_starting_view;
257 }
258 } else {
259 // When you are going back, starting view's FocusTraversable
260 // should not be used.
261 focus_traversable =
262 original_starting_view->GetWidget()->GetFocusTraversable();
263 starting_view = original_starting_view;
264 }
265 }
266 } else {
267 Widget* widget = starting_widget ? starting_widget : widget_;
268 focus_traversable = widget->GetFocusTraversable();
269 }
270
271 // Traverse the FocusTraversable tree down to find the focusable view.
272 View* v = FindFocusableView(focus_traversable, starting_view, reverse);
273 if (v) {
274 return v;
275 } else {
276 // Let's go up in the FocusTraversable tree.
277 FocusTraversable* parent_focus_traversable =
278 focus_traversable->GetFocusTraversableParent();
279 starting_view = focus_traversable->GetFocusTraversableParentView();
280 while (parent_focus_traversable) {
281 FocusTraversable* new_focus_traversable = NULL;
282 View* new_starting_view = NULL;
283 // When we are going backward, the parent view might gain the next focus.
284 bool check_starting_view = reverse;
285 v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
286 starting_view, reverse, FocusSearch::UP,
287 check_starting_view, &new_focus_traversable, &new_starting_view);
288
289 if (new_focus_traversable) {
290 DCHECK(!v);
291
292 // There is a FocusTraversable, traverse it down.
293 v = FindFocusableView(new_focus_traversable, NULL, reverse);
294 }
295
296 if (v)
297 return v;
298
299 starting_view = focus_traversable->GetFocusTraversableParentView();
300 parent_focus_traversable =
301 parent_focus_traversable->GetFocusTraversableParent();
302 }
303
304 // If we get here, we have reached the end of the focus hierarchy, let's
305 // loop. Make sure there was at least a view to start with, to prevent
306 // infinitely looping in empty windows.
307 if (!dont_loop && original_starting_view) {
308 // Easy, just clear the selection and press tab again.
309 // By calling with NULL as the starting view, we'll start from either
310 // the starting views widget or |widget_|.
311 Widget* widget = original_starting_view->GetWidget();
312 if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
313 widget = widget_;
314 return GetNextFocusableView(NULL, widget, reverse, true);
315 }
316 }
317 return NULL;
318 }
319
SetFocusedViewWithReason(View * view,FocusChangeReason reason)320 void FocusManager::SetFocusedViewWithReason(
321 View* view, FocusChangeReason reason) {
322 if (focused_view_ == view)
323 return;
324
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));
331
332 View* old_focused_view = focused_view_;
333 focused_view_ = view;
334 if (old_focused_view)
335 old_focused_view->Blur();
336 // Also make |focused_view_| the stored focus view. This way the stored focus
337 // view is remembered if focus changes are requested prior to a show or while
338 // hidden.
339 SetStoredFocusView(focused_view_);
340 if (focused_view_)
341 focused_view_->Focus();
342
343 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
344 OnDidChangeFocus(old_focused_view, focused_view_));
345 }
346
ClearFocus()347 void FocusManager::ClearFocus() {
348 // SetFocusedView(NULL) is going to clear out the stored view to. We need to
349 // persist it in this case.
350 views::View* focused_view = GetStoredFocusView();
351 SetFocusedView(NULL);
352 ClearNativeFocus();
353 SetStoredFocusView(focused_view);
354 }
355
StoreFocusedView(bool clear_native_focus)356 void FocusManager::StoreFocusedView(bool clear_native_focus) {
357 View* focused_view = focused_view_;
358 // Don't do anything if no focused view. Storing the view (which is NULL), in
359 // this case, would clobber the view that was previously saved.
360 if (!focused_view_)
361 return;
362
363 View* v = focused_view_;
364
365 if (clear_native_focus) {
366 // Temporarily disable notification. ClearFocus() will set the focus to the
367 // main browser window. This extra focus bounce which happens during
368 // deactivation can confuse registered WidgetFocusListeners, as the focus
369 // is not changing due to a user-initiated event.
370 AutoNativeNotificationDisabler local_notification_disabler;
371 // ClearFocus() also stores the focused view.
372 ClearFocus();
373 } else {
374 SetFocusedView(NULL);
375 SetStoredFocusView(focused_view);
376 }
377
378 if (v)
379 v->SchedulePaint(); // Remove focus border.
380 }
381
RestoreFocusedView()382 bool FocusManager::RestoreFocusedView() {
383 View* view = GetStoredFocusView();
384 if (view) {
385 if (ContainsView(view)) {
386 if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
387 // RequestFocus would fail, but we want to restore focus to controls
388 // that had focus in accessibility mode.
389 SetFocusedViewWithReason(view, kReasonFocusRestore);
390 } else {
391 // This usually just sets the focus if this view is focusable, but
392 // let the view override RequestFocus if necessary.
393 view->RequestFocus();
394
395 // If it succeeded, the reason would be incorrect; set it to
396 // focus restore.
397 if (focused_view_ == view)
398 focus_change_reason_ = kReasonFocusRestore;
399 }
400 }
401 return true;
402 }
403 return false;
404 }
405
SetStoredFocusView(View * focus_view)406 void FocusManager::SetStoredFocusView(View* focus_view) {
407 ViewStorage* view_storage = ViewStorage::GetInstance();
408 if (!view_storage) {
409 // This should never happen but bug 981648 seems to indicate it could.
410 NOTREACHED();
411 return;
412 }
413
414 // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
415 // is stored twice causing an assert. We should find a better alternative than
416 // removing the view from the storage explicitly.
417 view_storage->RemoveView(stored_focused_view_storage_id_);
418
419 if (!focus_view)
420 return;
421
422 view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
423 }
424
GetStoredFocusView()425 View* FocusManager::GetStoredFocusView() {
426 ViewStorage* view_storage = ViewStorage::GetInstance();
427 if (!view_storage) {
428 // This should never happen but bug 981648 seems to indicate it could.
429 NOTREACHED();
430 return NULL;
431 }
432
433 return view_storage->RetrieveView(stored_focused_view_storage_id_);
434 }
435
ClearStoredFocusedView()436 void FocusManager::ClearStoredFocusedView() {
437 SetStoredFocusView(NULL);
438 }
439
440 // Find the next (previous if reverse is true) focusable view for the specified
441 // FocusTraversable, starting at the specified view, traversing down the
442 // FocusTraversable hierarchy.
FindFocusableView(FocusTraversable * focus_traversable,View * starting_view,bool reverse)443 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
444 View* starting_view,
445 bool reverse) {
446 FocusTraversable* new_focus_traversable = NULL;
447 View* new_starting_view = NULL;
448 View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
449 starting_view,
450 reverse,
451 FocusSearch::DOWN,
452 false,
453 &new_focus_traversable,
454 &new_starting_view);
455
456 // Let's go down the FocusTraversable tree as much as we can.
457 while (new_focus_traversable) {
458 DCHECK(!v);
459 focus_traversable = new_focus_traversable;
460 new_focus_traversable = NULL;
461 starting_view = NULL;
462 v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
463 starting_view,
464 reverse,
465 FocusSearch::DOWN,
466 false,
467 &new_focus_traversable,
468 &new_starting_view);
469 }
470 return v;
471 }
472
RegisterAccelerator(const ui::Accelerator & accelerator,ui::AcceleratorManager::HandlerPriority priority,ui::AcceleratorTarget * target)473 void FocusManager::RegisterAccelerator(
474 const ui::Accelerator& accelerator,
475 ui::AcceleratorManager::HandlerPriority priority,
476 ui::AcceleratorTarget* target) {
477 accelerator_manager_->Register(accelerator, priority, target);
478 }
479
UnregisterAccelerator(const ui::Accelerator & accelerator,ui::AcceleratorTarget * target)480 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
481 ui::AcceleratorTarget* target) {
482 accelerator_manager_->Unregister(accelerator, target);
483 }
484
UnregisterAccelerators(ui::AcceleratorTarget * target)485 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
486 accelerator_manager_->UnregisterAll(target);
487 }
488
ProcessAccelerator(const ui::Accelerator & accelerator)489 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
490 if (accelerator_manager_->Process(accelerator))
491 return true;
492 if (delegate_.get())
493 return delegate_->ProcessAccelerator(accelerator);
494 return false;
495 }
496
GetCurrentTargetForAccelerator(const ui::Accelerator & accelerator) const497 ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
498 const ui::Accelerator& accelerator) const {
499 ui::AcceleratorTarget* target =
500 accelerator_manager_->GetCurrentTarget(accelerator);
501 if (!target && delegate_.get())
502 target = delegate_->GetCurrentTargetForAccelerator(accelerator);
503 return target;
504 }
505
HasPriorityHandler(const ui::Accelerator & accelerator) const506 bool FocusManager::HasPriorityHandler(
507 const ui::Accelerator& accelerator) const {
508 return accelerator_manager_->HasPriorityHandler(accelerator);
509 }
510
511 // static
IsTabTraversalKeyEvent(const ui::KeyEvent & key_event)512 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
513 return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
514 }
515
ViewRemoved(View * removed)516 void FocusManager::ViewRemoved(View* removed) {
517 // If the view being removed contains (or is) the focused view,
518 // clear the focus. However, it's not safe to call ClearFocus()
519 // (and in turn ClearNativeFocus()) here because ViewRemoved() can
520 // be called while the top level widget is being destroyed.
521 if (focused_view_ && removed->Contains(focused_view_))
522 SetFocusedView(NULL);
523 }
524
AddFocusChangeListener(FocusChangeListener * listener)525 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
526 focus_change_listeners_.AddObserver(listener);
527 }
528
RemoveFocusChangeListener(FocusChangeListener * listener)529 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
530 focus_change_listeners_.RemoveObserver(listener);
531 }
532
ProcessArrowKeyTraversal(const ui::KeyEvent & event)533 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
534 if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
535 return false;
536
537 const int key_code = event.key_code();
538 if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
539 AdvanceFocus(true);
540 return true;
541 }
542 if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
543 AdvanceFocus(false);
544 return true;
545 }
546
547 return false;
548 }
549
550 } // namespace views
551