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