• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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