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/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 
     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 
     50 FocusManager::~FocusManager() {
     51 }
     52 
     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 
    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.
    132 bool FocusManager::ContainsView(View* view) {
    133   Widget* widget = view->GetWidget();
    134   return widget ? widget->GetFocusManager() == this : false;
    135 }
    136 
    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 
    154 void FocusManager::ClearNativeFocus() {
    155   // Keep the top root window focused so we get keyboard events.
    156   widget_->ClearNativeFocus();
    157 }
    158 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    440 void FocusManager::ClearStoredFocusedView() {
    441   SetStoredFocusView(NULL);
    442 }
    443 
    444 void FocusManager::OnTextInputClientChanged(View* view) {
    445   if (view == focused_view_)
    446     FocusTextInputClient(view);
    447 }
    448 
    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 
    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.
    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 
    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 
    524 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
    525                                          ui::AcceleratorTarget* target) {
    526   accelerator_manager_->Unregister(accelerator, target);
    527 }
    528 
    529 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
    530   accelerator_manager_->UnregisterAll(target);
    531 }
    532 
    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 
    541 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 
    550 bool FocusManager::HasPriorityHandler(
    551     const ui::Accelerator& accelerator) const {
    552   return accelerator_manager_->HasPriorityHandler(accelerator);
    553 }
    554 
    555 // static
    556 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
    557   return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
    558 }
    559 
    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 
    569 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
    570   focus_change_listeners_.AddObserver(listener);
    571 }
    572 
    573 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
    574   focus_change_listeners_.RemoveObserver(listener);
    575 }
    576 
    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