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