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