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