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 #if defined(OS_MACOSX) || defined(OS_CHROMEOS)
     70   if (event.IsCommandDown())
     71     modifiers |= ui::EF_COMMAND_DOWN;
     72 #endif
     73   ui::Accelerator accelerator(event.key_code(), modifiers);
     74   accelerator.set_type(event.type());
     75   accelerator.set_is_repeat(event.IsRepeat());
     76 
     77   if (event.type() == ui::ET_KEY_PRESSED) {
     78     // If the focused view wants to process the key event as is, let it be.
     79     if (focused_view_ && focused_view_->SkipDefaultKeyEventProcessing(event) &&
     80         !accelerator_manager_->HasPriorityHandler(accelerator))
     81       return true;
     82 
     83     // Intercept Tab related messages for focus traversal.
     84     // Note that we don't do focus traversal if the root window is not part of
     85     // the active window hierarchy as this would mean we have no focused view
     86     // and would focus the first focusable view.
     87     if (IsTabTraversalKeyEvent(event)) {
     88       AdvanceFocus(event.IsShiftDown());
     89       return false;
     90     }
     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_, NULL, 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                                          Widget* starting_widget,
    223                                          bool reverse,
    224                                          bool dont_loop) {
    225   FocusTraversable* focus_traversable = NULL;
    226 
    227   // Let's revalidate the focused view.
    228   ValidateFocusedView();
    229 
    230   View* starting_view = NULL;
    231   if (original_starting_view) {
    232     // Search up the containment hierarchy to see if a view is acting as
    233     // a pane, and wants to implement its own focus traversable to keep
    234     // the focus trapped within that pane.
    235     View* pane_search = original_starting_view;
    236     while (pane_search) {
    237       focus_traversable = pane_search->GetPaneFocusTraversable();
    238       if (focus_traversable) {
    239         starting_view = original_starting_view;
    240         break;
    241       }
    242       pane_search = pane_search->parent();
    243     }
    244 
    245     if (!focus_traversable) {
    246       if (!reverse) {
    247         // If the starting view has a focus traversable, use it.
    248         // This is the case with NativeWidgetWins for example.
    249         focus_traversable = original_starting_view->GetFocusTraversable();
    250 
    251         // Otherwise default to the root view.
    252         if (!focus_traversable) {
    253           focus_traversable =
    254               original_starting_view->GetWidget()->GetFocusTraversable();
    255           starting_view = original_starting_view;
    256         }
    257       } else {
    258         // When you are going back, starting view's FocusTraversable
    259         // should not be used.
    260         focus_traversable =
    261             original_starting_view->GetWidget()->GetFocusTraversable();
    262         starting_view = original_starting_view;
    263       }
    264     }
    265   } else {
    266     Widget* widget = starting_widget ? starting_widget : widget_;
    267     focus_traversable = widget->GetFocusTraversable();
    268   }
    269 
    270   // Traverse the FocusTraversable tree down to find the focusable view.
    271   View* v = FindFocusableView(focus_traversable, starting_view, reverse);
    272   if (v) {
    273     return v;
    274   } else {
    275     // Let's go up in the FocusTraversable tree.
    276     FocusTraversable* parent_focus_traversable =
    277         focus_traversable->GetFocusTraversableParent();
    278     starting_view = focus_traversable->GetFocusTraversableParentView();
    279     while (parent_focus_traversable) {
    280       FocusTraversable* new_focus_traversable = NULL;
    281       View* new_starting_view = NULL;
    282       // When we are going backward, the parent view might gain the next focus.
    283       bool check_starting_view = reverse;
    284       v = parent_focus_traversable->GetFocusSearch()->FindNextFocusableView(
    285           starting_view, reverse, FocusSearch::UP,
    286           check_starting_view, &new_focus_traversable, &new_starting_view);
    287 
    288       if (new_focus_traversable) {
    289         DCHECK(!v);
    290 
    291         // There is a FocusTraversable, traverse it down.
    292         v = FindFocusableView(new_focus_traversable, NULL, reverse);
    293       }
    294 
    295       if (v)
    296         return v;
    297 
    298       starting_view = focus_traversable->GetFocusTraversableParentView();
    299       parent_focus_traversable =
    300           parent_focus_traversable->GetFocusTraversableParent();
    301     }
    302 
    303     // If we get here, we have reached the end of the focus hierarchy, let's
    304     // loop. Make sure there was at least a view to start with, to prevent
    305     // infinitely looping in empty windows.
    306     if (!dont_loop && original_starting_view) {
    307       // Easy, just clear the selection and press tab again.
    308       // By calling with NULL as the starting view, we'll start from either
    309       // the starting views widget or |widget_|.
    310       Widget* widget = original_starting_view->GetWidget();
    311       if (widget->widget_delegate()->ShouldAdvanceFocusToTopLevelWidget())
    312         widget = widget_;
    313       return GetNextFocusableView(NULL, widget, reverse, true);
    314     }
    315   }
    316   return NULL;
    317 }
    318 
    319 void FocusManager::SetFocusedViewWithReason(
    320     View* view, FocusChangeReason reason) {
    321   if (focused_view_ == view) {
    322     // In the case that the widget lost the focus and gained it back without
    323     // changing the focused view, we have to make the text input client focused.
    324     // TODO(yukishiino): Remove this hack once we fix http://crbug.com/383236
    325     FocusTextInputClient(focused_view_);
    326     return;
    327   }
    328 
    329   base::AutoReset<bool> auto_changing_focus(&is_changing_focus_, true);
    330   // Update the reason for the focus change (since this is checked by
    331   // some listeners), then notify all listeners.
    332   focus_change_reason_ = reason;
    333   FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
    334                     OnWillChangeFocus(focused_view_, view));
    335 
    336   View* old_focused_view = focused_view_;
    337   focused_view_ = view;
    338   if (old_focused_view) {
    339     old_focused_view->Blur();
    340     BlurTextInputClient(old_focused_view);
    341   }
    342   // Also make |focused_view_| the stored focus view. This way the stored focus
    343   // view is remembered if focus changes are requested prior to a show or while
    344   // hidden.
    345   SetStoredFocusView(focused_view_);
    346   if (focused_view_) {
    347     FocusTextInputClient(focused_view_);
    348     focused_view_->Focus();
    349   }
    350 
    351   FOR_EACH_OBSERVER(FocusChangeListener, focus_change_listeners_,
    352                     OnDidChangeFocus(old_focused_view, focused_view_));
    353 }
    354 
    355 void FocusManager::ClearFocus() {
    356   // SetFocusedView(NULL) is going to clear out the stored view to. We need to
    357   // persist it in this case.
    358   views::View* focused_view = GetStoredFocusView();
    359   SetFocusedView(NULL);
    360   ClearNativeFocus();
    361   SetStoredFocusView(focused_view);
    362 }
    363 
    364 void FocusManager::AdvanceFocusIfNecessary() {
    365   // If widget is inactive, there is no focused view to check. The stored view
    366   // will also be checked for focusability when it is being restored.
    367   if (!widget_->IsActive())
    368     return;
    369 
    370   // If widget is active and focused view is not focusable, advance focus or,
    371   // if not possible, clear focus.
    372   if (focused_view_ && !focused_view_->IsAccessibilityFocusable()) {
    373     AdvanceFocus(false);
    374     if (focused_view_ && !focused_view_->IsAccessibilityFocusable())
    375       ClearFocus();
    376   }
    377 }
    378 
    379 void FocusManager::StoreFocusedView(bool clear_native_focus) {
    380   View* focused_view = focused_view_;
    381   // Don't do anything if no focused view. Storing the view (which is NULL), in
    382   // this case, would clobber the view that was previously saved.
    383   if (!focused_view_)
    384     return;
    385 
    386   View* v = focused_view_;
    387 
    388   if (clear_native_focus) {
    389     // Temporarily disable notification.  ClearFocus() will set the focus to the
    390     // main browser window.  This extra focus bounce which happens during
    391     // deactivation can confuse registered WidgetFocusListeners, as the focus
    392     // is not changing due to a user-initiated event.
    393     AutoNativeNotificationDisabler local_notification_disabler;
    394     // ClearFocus() also stores the focused view.
    395     ClearFocus();
    396   } else {
    397     SetFocusedView(NULL);
    398     SetStoredFocusView(focused_view);
    399   }
    400 
    401   if (v)
    402     v->SchedulePaint();  // Remove focus border.
    403 }
    404 
    405 bool FocusManager::RestoreFocusedView() {
    406   View* view = GetStoredFocusView();
    407   if (view) {
    408     if (ContainsView(view)) {
    409       if (!view->IsFocusable() && view->IsAccessibilityFocusable()) {
    410         // RequestFocus would fail, but we want to restore focus to controls
    411         // that had focus in accessibility mode.
    412         SetFocusedViewWithReason(view, kReasonFocusRestore);
    413       } else {
    414         // This usually just sets the focus if this view is focusable, but
    415         // let the view override RequestFocus if necessary.
    416         view->RequestFocus();
    417 
    418         // If it succeeded, the reason would be incorrect; set it to
    419         // focus restore.
    420         if (focused_view_ == view)
    421           focus_change_reason_ = kReasonFocusRestore;
    422       }
    423     }
    424     return true;
    425   }
    426   return false;
    427 }
    428 
    429 void FocusManager::SetStoredFocusView(View* focus_view) {
    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;
    435   }
    436 
    437   // TODO(jcivelli): when a TabContents containing a popup is closed, the focus
    438   // is stored twice causing an assert. We should find a better alternative than
    439   // removing the view from the storage explicitly.
    440   view_storage->RemoveView(stored_focused_view_storage_id_);
    441 
    442   if (!focus_view)
    443     return;
    444 
    445   view_storage->StoreView(stored_focused_view_storage_id_, focus_view);
    446 }
    447 
    448 View* FocusManager::GetStoredFocusView() {
    449   ViewStorage* view_storage = ViewStorage::GetInstance();
    450   if (!view_storage) {
    451     // This should never happen but bug 981648 seems to indicate it could.
    452     NOTREACHED();
    453     return NULL;
    454   }
    455 
    456   return view_storage->RetrieveView(stored_focused_view_storage_id_);
    457 }
    458 
    459 void FocusManager::ClearStoredFocusedView() {
    460   SetStoredFocusView(NULL);
    461 }
    462 
    463 void FocusManager::OnTextInputClientChanged(View* view) {
    464   if (view == focused_view_)
    465     FocusTextInputClient(view);
    466 }
    467 
    468 void FocusManager::FocusTextInputClient(View* view) {
    469   if (!switches::IsTextInputFocusManagerEnabled())
    470     return;
    471 
    472   // If the widget is not active, do not steal the text input focus.
    473   if (!widget_->IsActive())
    474     return;
    475 
    476   ui::TextInputClient* text_input_client =
    477       view ? view->GetTextInputClient() : NULL;
    478   ui::TextInputFocusManager::GetInstance()->
    479       FocusTextInputClient(text_input_client);
    480   ui::InputMethod* input_method = widget_->GetHostInputMethod();
    481   if (input_method) {
    482     input_method->OnTextInputTypeChanged(text_input_client);
    483     input_method->OnCaretBoundsChanged(text_input_client);
    484   }
    485 }
    486 
    487 void FocusManager::BlurTextInputClient(View* view) {
    488   if (!switches::IsTextInputFocusManagerEnabled())
    489     return;
    490 
    491   ui::TextInputClient* text_input_client =
    492       view ? view->GetTextInputClient() : NULL;
    493   if (text_input_client && text_input_client->HasCompositionText()) {
    494     text_input_client->ConfirmCompositionText();
    495     ui::InputMethod* input_method = widget_->GetHostInputMethod();
    496     if (input_method && input_method->GetTextInputClient() == text_input_client)
    497       input_method->CancelComposition(text_input_client);
    498   }
    499   ui::TextInputFocusManager::GetInstance()->
    500       BlurTextInputClient(text_input_client);
    501 }
    502 
    503 // Find the next (previous if reverse is true) focusable view for the specified
    504 // FocusTraversable, starting at the specified view, traversing down the
    505 // FocusTraversable hierarchy.
    506 View* FocusManager::FindFocusableView(FocusTraversable* focus_traversable,
    507                                       View* starting_view,
    508                                       bool reverse) {
    509   FocusTraversable* new_focus_traversable = NULL;
    510   View* new_starting_view = NULL;
    511   View* v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
    512       starting_view,
    513       reverse,
    514       FocusSearch::DOWN,
    515       false,
    516       &new_focus_traversable,
    517       &new_starting_view);
    518 
    519   // Let's go down the FocusTraversable tree as much as we can.
    520   while (new_focus_traversable) {
    521     DCHECK(!v);
    522     focus_traversable = new_focus_traversable;
    523     new_focus_traversable = NULL;
    524     starting_view = NULL;
    525     v = focus_traversable->GetFocusSearch()->FindNextFocusableView(
    526         starting_view,
    527         reverse,
    528         FocusSearch::DOWN,
    529         false,
    530         &new_focus_traversable,
    531         &new_starting_view);
    532   }
    533   return v;
    534 }
    535 
    536 void FocusManager::RegisterAccelerator(
    537     const ui::Accelerator& accelerator,
    538     ui::AcceleratorManager::HandlerPriority priority,
    539     ui::AcceleratorTarget* target) {
    540   accelerator_manager_->Register(accelerator, priority, target);
    541 }
    542 
    543 void FocusManager::UnregisterAccelerator(const ui::Accelerator& accelerator,
    544                                          ui::AcceleratorTarget* target) {
    545   accelerator_manager_->Unregister(accelerator, target);
    546 }
    547 
    548 void FocusManager::UnregisterAccelerators(ui::AcceleratorTarget* target) {
    549   accelerator_manager_->UnregisterAll(target);
    550 }
    551 
    552 bool FocusManager::ProcessAccelerator(const ui::Accelerator& accelerator) {
    553   if (accelerator_manager_->Process(accelerator))
    554     return true;
    555   if (delegate_.get())
    556     return delegate_->ProcessAccelerator(accelerator);
    557   return false;
    558 }
    559 
    560 ui::AcceleratorTarget* FocusManager::GetCurrentTargetForAccelerator(
    561     const ui::Accelerator& accelerator) const {
    562   ui::AcceleratorTarget* target =
    563       accelerator_manager_->GetCurrentTarget(accelerator);
    564   if (!target && delegate_.get())
    565     target = delegate_->GetCurrentTargetForAccelerator(accelerator);
    566   return target;
    567 }
    568 
    569 bool FocusManager::HasPriorityHandler(
    570     const ui::Accelerator& accelerator) const {
    571   return accelerator_manager_->HasPriorityHandler(accelerator);
    572 }
    573 
    574 // static
    575 bool FocusManager::IsTabTraversalKeyEvent(const ui::KeyEvent& key_event) {
    576   return key_event.key_code() == ui::VKEY_TAB && !key_event.IsControlDown();
    577 }
    578 
    579 void FocusManager::ViewRemoved(View* removed) {
    580   // If the view being removed contains (or is) the focused view,
    581   // clear the focus.  However, it's not safe to call ClearFocus()
    582   // (and in turn ClearNativeFocus()) here because ViewRemoved() can
    583   // be called while the top level widget is being destroyed.
    584   if (focused_view_ && removed->Contains(focused_view_))
    585     SetFocusedView(NULL);
    586 }
    587 
    588 void FocusManager::AddFocusChangeListener(FocusChangeListener* listener) {
    589   focus_change_listeners_.AddObserver(listener);
    590 }
    591 
    592 void FocusManager::RemoveFocusChangeListener(FocusChangeListener* listener) {
    593   focus_change_listeners_.RemoveObserver(listener);
    594 }
    595 
    596 bool FocusManager::ProcessArrowKeyTraversal(const ui::KeyEvent& event) {
    597   if (event.IsShiftDown() || event.IsControlDown() || event.IsAltDown())
    598     return false;
    599 
    600   const int key_code = event.key_code();
    601   if (key_code == ui::VKEY_LEFT || key_code == ui::VKEY_UP) {
    602     AdvanceFocus(true);
    603     return true;
    604   }
    605   if (key_code == ui::VKEY_RIGHT || key_code == ui::VKEY_DOWN) {
    606     AdvanceFocus(false);
    607     return true;
    608   }
    609 
    610   return false;
    611 }
    612 
    613 }  // namespace views
    614