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/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"
28
29 namespace views {
30
31 namespace {
32
33 } // namespace
34
35 bool FocusManager::shortcut_handling_suspended_ = false;
36 bool FocusManager::arrow_key_traversal_enabled_ = false;
37
FocusManager(Widget * widget,FocusManagerDelegate * delegate)38 FocusManager::FocusManager(Widget* widget, FocusManagerDelegate* delegate)
39 : widget_(widget),
40 delegate_(delegate),
41 focused_view_(NULL),
42 accelerator_manager_(new ui::AcceleratorManager),
43 focus_change_reason_(kReasonDirectFocusChange),
44 is_changing_focus_(false) {
45 DCHECK(widget_);
46 stored_focused_view_storage_id_ =
47 ViewStorage::GetInstance()->CreateStorageID();
48 }
49
~FocusManager()50 FocusManager::~FocusManager() {
51 }
52
OnKeyEvent(const ui::KeyEvent & event)53 bool FocusManager::OnKeyEvent(const ui::KeyEvent& event) {
54 const int key_code = event.key_code();
55
56 if (event.type() != ui::ET_KEY_PRESSED && event.type() != ui::ET_KEY_RELEASED)
57 return false;
58
59 if (shortcut_handling_suspended())
60 return true;
61
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());
72
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))
77 return true;
78
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());
85 return false;
86 }
87
88 if (arrow_key_traversal_enabled_ && ProcessArrowKeyTraversal(event))
89 return false;
90
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);
96 View::Views views;
97 focused_view_->parent()->GetViewsInGroup(focused_view_->GetGroup(),
98 &views);
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;
104 if (index < 0) {
105 index = static_cast<int>(views.size()) - 1;
106 } else if (index >= static_cast<int>(views.size())) {
107 index = 0;
108 }
109 SetFocusedViewWithReason(views[index], kReasonFocusTraversal);
110 return false;
111 }
112 }
113
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.
120 return false;
121 }
122 return true;
123 }
124
ValidateFocusedView()125 void FocusManager::ValidateFocusedView() {
126 if (focused_view_ && !ContainsView(focused_view_))
127 ClearFocus();
128 }
129
130 // Tests whether a view is valid, whether it still belongs to the window
131 // hierarchy of the FocusManager.
ContainsView(View * view)132 bool FocusManager::ContainsView(View* view) {
133 Widget* widget = view->GetWidget();
134 return widget ? widget->GetFocusManager() == this : false;
135 }
136
AdvanceFocus(bool reverse)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.
144 if (v) {
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);
151 }
152 }
153
ClearNativeFocus()154 void FocusManager::ClearNativeFocus() {
155 // Keep the top root window focused so we get keyboard events.
156 widget_->ClearNativeFocus();
157 }
158
RotatePaneFocus(Direction direction,FocusCycleWrappingBehavior wrap)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);
164
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());
168 if (count == 0)
169 return false;
170
171 // Initialize |index| to an appropriate starting index if nothing is
172 // focused initially.
173 int index = direction == kBackward ? 0 : count - 1;
174
175 // Check to see if a pane already has focus and update the index accordingly.
176 const views::View* focused_view = GetFocusedView();
177 if (focused_view) {
178 for (int i = 0; i < count; i++) {
179 if (panes[i] && panes[i]->Contains(focused_view)) {
180 index = i;
181 break;
182 }
183 }
184 }
185
186 // Rotate focus.
187 int start_index = index;
188 for (;;) {
189 if (direction == kBackward)
190 index--;
191 else
192 index++;
193
194 if (wrap == kNoWrap && (index >= count || index < 0))
195 return false;
196 index = (index + count) % count;
197
198 // Ensure that we don't loop more than once.
199 if (index == start_index)
200 break;
201
202 views::View* pane = panes[index];
203 DCHECK(pane);
204
205 if (!pane->visible())
206 continue;
207
208 pane->RequestFocus();
209 focused_view = GetFocusedView();
210 if (pane == focused_view || pane->Contains(focused_view))
211 return true;
212 }
213
214 return false;
215 }
216
GetNextFocusableView(View * original_starting_view,Widget * starting_widget,bool reverse,bool dont_loop)217 View* FocusManager::GetNextFocusableView(View* original_starting_view,
218 Widget* starting_widget,
219 bool reverse,
220 bool dont_loop) {
221 FocusTraversable* focus_traversable = NULL;
222
223 // Let's revalidate the focused view.
224 ValidateFocusedView();
225
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;
236 break;
237 }
238 pane_search = pane_search->parent();
239 }
240
241 if (!focus_traversable) {
242 if (!reverse) {
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();
246
247 // Otherwise default to the root view.
248 if (!focus_traversable) {
249 focus_traversable =
250 original_starting_view->GetWidget()->GetFocusTraversable();
251 starting_view = original_starting_view;
252 }
253 } else {
254 // When you are going back, starting view's FocusTraversable
255 // should not be used.
256 focus_traversable =
257 original_starting_view->GetWidget()->GetFocusTraversable();
258 starting_view = original_starting_view;
259 }
260 }
261 } else {
262 Widget* widget = starting_widget ? starting_widget : widget_;
263 focus_traversable = widget->GetFocusTraversable();
264 }
265
266 // Traverse the FocusTraversable tree down to find the focusable view.
267 View* v = FindFocusableView(focus_traversable, starting_view, reverse);
268 if (v) {
269 return v;
270 } else {
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);
283
284 if (new_focus_traversable) {
285 DCHECK(!v);
286
287 // There is a FocusTraversable, traverse it down.
288 v = FindFocusableView(new_focus_traversable, NULL, reverse);
289 }
290
291 if (v)
292 return v;
293
294 starting_view = focus_traversable->GetFocusTraversableParentView();
295 parent_focus_traversable =
296 parent_focus_traversable->GetFocusTraversableParent();
297 }
298
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())
308 widget = widget_;
309 return GetNextFocusableView(NULL, widget, reverse, true);
310 }
311 }
312 return NULL;
313 }
314
SetFocusedViewWithReason(View * view,FocusChangeReason reason)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_);
322 return;
323 }
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 BlurTextInputClient(old_focused_view);
337 }
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
340 // hidden.
341 SetStoredFocusView(focused_view_);
342 if (focused_view_) {
343 FocusTextInputClient(focused_view_);
344 focused_view_->Focus();
345 }
346
347 FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
348 OnDidChangeFocus(old_focused_view, focused_view_));
349 }
350
ClearFocus()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);
356 ClearNativeFocus();
357 SetStoredFocusView(focused_view);
358 }
359
StoreFocusedView(bool clear_native_focus)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.
364 if (!focused_view_)
365 return;
366
367 View* v = focused_view_;
368
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.
376 ClearFocus();
377 } else {
378 SetFocusedView(NULL);
379 SetStoredFocusView(focused_view);
380 }
381
382 if (v)
383 v->SchedulePaint(); // Remove focus border.
384 }
385
RestoreFocusedView()386 bool FocusManager::RestoreFocusedView() {
387 View* view = GetStoredFocusView();
388 if (view) {
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);
394 } else {
395 // This usually just sets the focus if this view is focusable, but
396 // let the view override RequestFocus if necessary.
397 view->RequestFocus();
398
399 // If it succeeded, the reason would be incorrect; set it to
400 // focus restore.
401 if (focused_view_ == view)
402 focus_change_reason_ = kReasonFocusRestore;
403 }
404 }
405 return true;
406 }
407 return false;
408 }
409
SetStoredFocusView(View * focus_view)410 void FocusManager::SetStoredFocusView(View* focus_view) {
411 ViewStorage* view_storage = ViewStorage::GetInstance();
412 if (!view_storage) {
413 // This should never happen but bug 981648 seems to indicate it could.
414 NOTREACHED();
415 return;
416 }
417
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_);
422
423 if (!focus_view)
424 return;
425
426 view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
427 }
428
GetStoredFocusView()429 View* FocusManager::GetStoredFocusView() {
430 ViewStorage* view_storage = ViewStorage::GetInstance();
431 if (!view_storage) {
432 // This should never happen but bug 981648 seems to indicate it could.
433 NOTREACHED();
434 return NULL;
435 }
436
437 return view_storage->RetrieveView(stored_focused_view_storage_id_);
438 }
439
ClearStoredFocusedView()440 void FocusManager::ClearStoredFocusedView() {
441 SetStoredFocusView(NULL);
442 }
443
OnTextInputClientChanged(View * view)444 void FocusManager::OnTextInputClientChanged(View* view) {
445 if (view == focused_view_)
446 FocusTextInputClient(view);
447 }
448
FocusTextInputClient(View * view)449 void FocusManager::FocusTextInputClient(View* view) {
450 if (!switches::IsTextInputFocusManagerEnabled())
451 return;
452
453 // If the widget is not active, do not steal the text input focus.
454 if (!widget_->IsActive())
455 return;
456
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();
462 if (input_method) {
463 input_method->OnTextInputTypeChanged(text_input_client);
464 input_method->OnCaretBoundsChanged(text_input_client);
465 }
466 }
467
BlurTextInputClient(View * view)468 void FocusManager::BlurTextInputClient(View* view) {
469 if (!switches::IsTextInputFocusManagerEnabled())
470 return;
471
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);
479 }
480 ui::TextInputFocusManager::GetInstance()->
481 BlurTextInputClient(text_input_client);
482 }
483
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.
FindFocusableView(FocusTraversable * focus_traversable,View * starting_view,bool reverse)487 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
488 View* starting_view,
489 bool reverse) {
490 FocusTraversable* new_focus_traversable = NULL;
491 View* new_starting_view = NULL;
492 View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
493 starting_view,
494 reverse,
495 FocusSearch::DOWN,
496 false,
497 &new_focus_traversable,
498 &new_starting_view);
499
500 // Let's go down the FocusTraversable tree as much as we can.
501 while (new_focus_traversable) {
502 DCHECK(!v);
503 focus_traversable = new_focus_traversable;
504 new_focus_traversable = NULL;
505 starting_view = NULL;
506 v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
507 starting_view,
508 reverse,
509 FocusSearch::DOWN,
510 false,
511 &new_focus_traversable,
512 &new_starting_view);
513 }
514 return v;
515 }
516
RegisterAccelerator(const ui::Accelerator & accelerator,ui::AcceleratorManager::HandlerPriority priority,ui::AcceleratorTarget * target)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);
522 }
523
UnregisterAccelerator(const ui::Accelerator & accelerator,ui::AcceleratorTarget * target)524 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
525 ui::AcceleratorTarget* target) {
526 accelerator_manager_->Unregister(accelerator, target);
527 }
528
UnregisterAccelerators(ui::AcceleratorTarget * target)529 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
530 accelerator_manager_->UnregisterAll(target);
531 }
532
ProcessAccelerator(const ui::Accelerator & accelerator)533 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
534 if (accelerator_manager_->Process(accelerator))
535 return true;
536 if (delegate_.get())
537 return delegate_->ProcessAccelerator(accelerator);
538 return false;
539 }
540
GetCurrentTargetForAccelerator(const ui::Accelerator & accelerator) const541 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);
547 return target;
548 }
549
HasPriorityHandler(const ui::Accelerator & accelerator) const550 bool FocusManager::HasPriorityHandler(
551 const ui::Accelerator& accelerator) const {
552 return accelerator_manager_->HasPriorityHandler(accelerator);
553 }
554
555 // static
IsTabTraversalKeyEvent(const ui::KeyEvent & key_event)556 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
557 return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
558 }
559
ViewRemoved(View * removed)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);
567 }
568
AddFocusChangeListener(FocusChangeListener * listener)569 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
570 focus_change_listeners_.AddObserver(listener);
571 }
572
RemoveFocusChangeListener(FocusChangeListener * listener)573 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
574 focus_change_listeners_.RemoveObserver(listener);
575 }
576
ProcessArrowKeyTraversal(const ui::KeyEvent & event)577 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
578 if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
579 return false;
580
581 const int key_code = event.key_code();
582 if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
583 AdvanceFocus(true);
584 return true;
585 }
586 if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
587 AdvanceFocus(false);
588 return true;
589 }
590
591 return false;
592 }
593
594 } // namespace views
595