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/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 
     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 
     46 FocusManager::~FocusManager() {
     47 }
     48 
     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 
    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.
    137 bool FocusManager::ContainsView(View* view) {
    138   Widget* widget = view->GetWidget();
    139   return widget ? widget->GetFocusManager() == this : false;
    140 }
    141 
    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 
    159 void FocusManager::ClearNativeFocus() {
    160   // Keep the top root window focused so we get keyboard events.
    161   widget_->ClearNativeFocus();
    162 }
    163 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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.
    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 
    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 
    480 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
    481                                          ui::AcceleratorTarget* target) {
    482   accelerator_manager_->Unregister(accelerator, target);
    483 }
    484 
    485 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
    486   accelerator_manager_->UnregisterAll(target);
    487 }
    488 
    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 
    497 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 
    506 bool FocusManager::HasPriorityHandler(
    507     const ui::Accelerator& accelerator) const {
    508   return accelerator_manager_->HasPriorityHandler(accelerator);
    509 }
    510 
    511 // static
    512 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
    513   return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
    514 }
    515 
    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 
    525 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
    526   focus_change_listeners_.AddObserver(listener);
    527 }
    528 
    529 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
    530   focus_change_listeners_.RemoveObserver(listener);
    531 }
    532 
    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