accelerator_controller.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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 "ash/accelerators/accelerator_controller.h" 6 7#include <algorithm> 8#include <cmath> 9#include <iostream> 10#include <string> 11 12#include "ash/accelerators/accelerator_commands.h" 13#include "ash/accelerators/accelerator_table.h" 14#include "ash/accelerators/debug_commands.h" 15#include "ash/ash_switches.h" 16#include "ash/caps_lock_delegate.h" 17#include "ash/debug.h" 18#include "ash/display/display_controller.h" 19#include "ash/display/display_manager.h" 20#include "ash/focus_cycler.h" 21#include "ash/ime_control_delegate.h" 22#include "ash/launcher/launcher.h" 23#include "ash/launcher/launcher_delegate.h" 24#include "ash/launcher/launcher_model.h" 25#include "ash/magnifier/magnification_controller.h" 26#include "ash/magnifier/partial_magnification_controller.h" 27#include "ash/multi_profile_uma.h" 28#include "ash/new_window_delegate.h" 29#include "ash/root_window_controller.h" 30#include "ash/rotator/screen_rotation.h" 31#include "ash/screenshot_delegate.h" 32#include "ash/session_state_delegate.h" 33#include "ash/shelf/shelf_widget.h" 34#include "ash/shell.h" 35#include "ash/shell_delegate.h" 36#include "ash/shell_window_ids.h" 37#include "ash/system/brightness_control_delegate.h" 38#include "ash/system/keyboard_brightness/keyboard_brightness_control_delegate.h" 39#include "ash/system/status_area_widget.h" 40#include "ash/system/tray/system_tray.h" 41#include "ash/system/tray/system_tray_delegate.h" 42#include "ash/system/tray/system_tray_notifier.h" 43#include "ash/system/web_notification/web_notification_tray.h" 44#include "ash/touch/touch_hud_debug.h" 45#include "ash/volume_control_delegate.h" 46#include "ash/wm/overview/window_selector_controller.h" 47#include "ash/wm/partial_screenshot_view.h" 48#include "ash/wm/power_button_controller.h" 49#include "ash/wm/window_cycle_controller.h" 50#include "ash/wm/window_state.h" 51#include "ash/wm/window_util.h" 52#include "ash/wm/workspace/snap_sizer.h" 53#include "base/bind.h" 54#include "base/command_line.h" 55#include "content/public/browser/gpu_data_manager.h" 56#include "ui/aura/env.h" 57#include "ui/aura/root_window.h" 58#include "ui/base/accelerators/accelerator.h" 59#include "ui/base/accelerators/accelerator_manager.h" 60#include "ui/compositor/debug_utils.h" 61#include "ui/compositor/layer.h" 62#include "ui/compositor/layer_animation_sequence.h" 63#include "ui/compositor/layer_animator.h" 64#include "ui/events/event.h" 65#include "ui/events/keycodes/keyboard_codes.h" 66#include "ui/gfx/screen.h" 67#include "ui/oak/oak.h" 68#include "ui/views/controls/webview/webview.h" 69#include "ui/views/debug_utils.h" 70#include "ui/views/widget/widget.h" 71 72#if defined(OS_CHROMEOS) 73#include "ash/session_state_delegate.h" 74#include "ash/system/chromeos/keyboard_brightness_controller.h" 75#include "base/sys_info.h" 76#endif // defined(OS_CHROMEOS) 77 78namespace ash { 79namespace { 80 81using internal::DisplayInfo; 82 83bool DebugShortcutsEnabled() { 84#if defined(NDEBUG) 85 return CommandLine::ForCurrentProcess()->HasSwitch( 86 switches::kAshDebugShortcuts); 87#else 88 return true; 89#endif 90} 91 92void HandleCycleBackwardMRU(const ui::Accelerator& accelerator) { 93 Shell* shell = Shell::GetInstance(); 94 95 if (accelerator.key_code() == ui::VKEY_TAB) 96 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_PREVWINDOW_TAB); 97 98 if (switches::UseOverviewMode()) { 99 shell->window_selector_controller()->HandleCycleWindow( 100 WindowSelector::BACKWARD); 101 return; 102 } 103 shell->window_cycle_controller()->HandleCycleWindow( 104 WindowCycleController::BACKWARD, accelerator.IsAltDown()); 105} 106 107void HandleCycleForwardMRU(const ui::Accelerator& accelerator) { 108 Shell* shell = Shell::GetInstance(); 109 110 if (accelerator.key_code() == ui::VKEY_TAB) 111 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEXTWINDOW_TAB); 112 113 if (switches::UseOverviewMode()) { 114 shell->window_selector_controller()->HandleCycleWindow( 115 WindowSelector::FORWARD); 116 return; 117 } 118 shell->window_cycle_controller()->HandleCycleWindow( 119 WindowCycleController::FORWARD, accelerator.IsAltDown()); 120} 121 122void HandleCycleLinear(const ui::Accelerator& accelerator) { 123 Shell* shell = Shell::GetInstance(); 124 125 // TODO(jamescook): When overview becomes the default the AcceleratorAction 126 // should be renamed from CYCLE_LINEAR to TOGGLE_OVERVIEW. 127 if (switches::UseOverviewMode()) { 128 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_OVERVIEW_F5); 129 shell->window_selector_controller()->ToggleOverview(); 130 return; 131 } 132 if (accelerator.key_code() == ui::VKEY_MEDIA_LAUNCH_APP1) 133 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEXTWINDOW_F5); 134 shell->window_cycle_controller()->HandleLinearCycleWindow(); 135} 136 137bool HandleAccessibleFocusCycle(bool reverse) { 138 if (!Shell::GetInstance()->accessibility_delegate()-> 139 IsSpokenFeedbackEnabled()) { 140 return false; 141 } 142 aura::Window* active_window = ash::wm::GetActiveWindow(); 143 if (!active_window) 144 return false; 145 views::Widget* widget = 146 views::Widget::GetWidgetForNativeWindow(active_window); 147 if (!widget) 148 return false; 149 views::FocusManager* focus_manager = widget->GetFocusManager(); 150 if (!focus_manager) 151 return false; 152 views::View* view = focus_manager->GetFocusedView(); 153 if (!view) 154 return false; 155 if (!strcmp(view->GetClassName(), views::WebView::kViewClassName)) 156 return false; 157 158 focus_manager->AdvanceFocus(reverse); 159 return true; 160} 161 162void HandleSilenceSpokenFeedback() { 163 AccessibilityDelegate* delegate = 164 Shell::GetInstance()->accessibility_delegate(); 165 if (!delegate->IsSpokenFeedbackEnabled()) 166 return; 167 delegate->SilenceSpokenFeedback(); 168} 169 170#if defined(OS_CHROMEOS) 171bool HandleLock() { 172 Shell::GetInstance()->session_state_delegate()->LockScreen(); 173 return true; 174} 175 176bool HandleFileManager() { 177 Shell::GetInstance()->new_window_delegate()->OpenFileManager(); 178 return true; 179} 180 181bool HandleCrosh() { 182 Shell::GetInstance()->new_window_delegate()->OpenCrosh(); 183 return true; 184} 185 186bool HandleToggleSpokenFeedback() { 187 Shell::GetInstance()->accessibility_delegate()-> 188 ToggleSpokenFeedback(A11Y_NOTIFICATION_SHOW); 189 return true; 190} 191 192bool SwitchToNextUser() { 193 if (!Shell::GetInstance()->delegate()->IsMultiProfilesEnabled()) 194 return false; 195 ash::SessionStateDelegate* delegate = 196 ash::Shell::GetInstance()->session_state_delegate(); 197 if (delegate->NumberOfLoggedInUsers() <= 1) 198 return false; 199 MultiProfileUMA::RecordSwitchActiveUser( 200 MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR); 201 delegate->SwitchActiveUserToNext(); 202 return true; 203} 204 205#endif // defined(OS_CHROMEOS) 206 207bool HandleRotatePaneFocus(Shell::Direction direction) { 208 Shell* shell = Shell::GetInstance(); 209 switch (direction) { 210 case Shell::FORWARD: 211 shell->focus_cycler()->RotateFocus(internal::FocusCycler::FORWARD); 212 break; 213 case Shell::BACKWARD: 214 shell->focus_cycler()->RotateFocus(internal::FocusCycler::BACKWARD); 215 break; 216 } 217 return true; 218} 219 220// Rotate the active window. 221bool HandleRotateActiveWindow() { 222 aura::Window* active_window = wm::GetActiveWindow(); 223 if (active_window) { 224 // The rotation animation bases its target transform on the current 225 // rotation and position. Since there could be an animation in progress 226 // right now, queue this animation so when it starts it picks up a neutral 227 // rotation and position. Use replace so we only enqueue one at a time. 228 active_window->layer()->GetAnimator()-> 229 set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); 230 active_window->layer()->GetAnimator()->StartAnimation( 231 new ui::LayerAnimationSequence( 232 new ash::ScreenRotation(360, active_window->layer()))); 233 } 234 return true; 235} 236 237gfx::Display::Rotation GetNextRotation(gfx::Display::Rotation current) { 238 switch (current) { 239 case gfx::Display::ROTATE_0: 240 return gfx::Display::ROTATE_90; 241 case gfx::Display::ROTATE_90: 242 return gfx::Display::ROTATE_180; 243 case gfx::Display::ROTATE_180: 244 return gfx::Display::ROTATE_270; 245 case gfx::Display::ROTATE_270: 246 return gfx::Display::ROTATE_0; 247 } 248 NOTREACHED() << "Unknown rotation:" << current; 249 return gfx::Display::ROTATE_0; 250} 251 252bool HandleScaleUI(bool up) { 253 internal::DisplayManager* display_manager = 254 Shell::GetInstance()->display_manager(); 255 int64 display_id = display_manager->GetDisplayIdForUIScaling(); 256 if (display_id == gfx::Display::kInvalidDisplayID) 257 return false; 258 const DisplayInfo& display_info = display_manager->GetDisplayInfo(display_id); 259 float next_scale = 260 internal::DisplayManager::GetNextUIScale(display_info, up); 261 display_manager->SetDisplayUIScale(display_id, next_scale); 262 return true; 263} 264 265bool HandleScaleReset() { 266 internal::DisplayManager* display_manager = 267 Shell::GetInstance()->display_manager(); 268 int64 display_id = display_manager->GetDisplayIdForUIScaling(); 269 if (display_id == gfx::Display::kInvalidDisplayID) 270 return false; 271 display_manager->SetDisplayUIScale(display_id, 1.0f); 272 return true; 273} 274 275// Rotates the screen. 276bool HandleRotateScreen() { 277 gfx::Point point = Shell::GetScreen()->GetCursorScreenPoint(); 278 gfx::Display display = Shell::GetScreen()->GetDisplayNearestPoint(point); 279 const DisplayInfo& display_info = 280 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); 281 Shell::GetInstance()->display_manager()->SetDisplayRotation( 282 display.id(), GetNextRotation(display_info.rotation())); 283 return true; 284} 285 286bool HandleToggleRootWindowFullScreen() { 287 Shell::GetPrimaryRootWindow()->GetDispatcher()->ToggleFullScreen(); 288 return true; 289} 290 291// Magnify the screen 292bool HandleMagnifyScreen(int delta_index) { 293 if (ash::Shell::GetInstance()->magnification_controller()->IsEnabled()) { 294 // TODO(yoshiki): Move the following logic to MagnificationController. 295 float scale = 296 ash::Shell::GetInstance()->magnification_controller()->GetScale(); 297 // Calculate rounded logarithm (base kMagnificationScaleFactor) of scale. 298 int scale_index = 299 std::floor(std::log(scale) / std::log(kMagnificationScaleFactor) + 0.5); 300 301 int new_scale_index = std::max(0, std::min(8, scale_index + delta_index)); 302 303 ash::Shell::GetInstance()->magnification_controller()-> 304 SetScale(std::pow(kMagnificationScaleFactor, new_scale_index), true); 305 } else if (ash::Shell::GetInstance()-> 306 partial_magnification_controller()->is_enabled()) { 307 float scale = delta_index > 0 ? kDefaultPartialMagnifiedScale : 1; 308 ash::Shell::GetInstance()->partial_magnification_controller()-> 309 SetScale(scale); 310 } 311 312 return true; 313} 314 315bool HandleMediaNextTrack() { 316 Shell::GetInstance()->delegate()->HandleMediaNextTrack(); 317 return true; 318} 319 320bool HandleMediaPlayPause() { 321 Shell::GetInstance()->delegate()->HandleMediaPlayPause(); 322 return true; 323} 324 325bool HandleMediaPrevTrack() { 326 Shell::GetInstance()->delegate()->HandleMediaPrevTrack(); 327 return true; 328} 329 330bool HandlePrintLayerHierarchy() { 331 Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); 332 for (size_t i = 0; i < root_windows.size(); ++i) { 333 ui::PrintLayerHierarchy(root_windows[i]->layer(), 334 root_windows[i]->GetLastMouseLocationInRoot()); 335 } 336 return true; 337} 338 339bool HandlePrintViewHierarchy() { 340 aura::Window* active_window = ash::wm::GetActiveWindow(); 341 if (!active_window) 342 return true; 343 views::Widget* browser_widget = 344 views::Widget::GetWidgetForNativeWindow(active_window); 345 if (!browser_widget) 346 return true; 347 views::PrintViewHierarchy(browser_widget->GetRootView()); 348 return true; 349} 350 351void PrintWindowHierarchy(aura::Window* window, 352 int indent, 353 std::ostringstream* out) { 354 std::string indent_str(indent, ' '); 355 std::string name(window->name()); 356 if (name.empty()) 357 name = "\"\""; 358 *out << indent_str << name << " (" << window << ")" 359 << " type=" << window->type() 360 << (wm::IsActiveWindow(window) ? " [active] " : " ") 361 << (window->IsVisible() ? " visible " : " ") 362 << window->bounds().ToString() 363 << '\n'; 364 365 for (size_t i = 0; i < window->children().size(); ++i) 366 PrintWindowHierarchy(window->children()[i], indent + 3, out); 367} 368 369bool HandlePrintWindowHierarchy() { 370 Shell::RootWindowControllerList controllers = 371 Shell::GetAllRootWindowControllers(); 372 for (size_t i = 0; i < controllers.size(); ++i) { 373 std::ostringstream out; 374 out << "RootWindow " << i << ":\n"; 375 PrintWindowHierarchy(controllers[i]->root_window(), 0, &out); 376 // Error so logs can be collected from end-users. 377 LOG(ERROR) << out.str(); 378 } 379 return true; 380} 381 382bool HandlePrintUIHierarchies() { 383 // This is a separate command so the user only has to hit one key to generate 384 // all the logs. Developers use the individual dumps repeatedly, so keep 385 // those as separate commands to avoid spamming their logs. 386 HandlePrintLayerHierarchy(); 387 HandlePrintWindowHierarchy(); 388 HandlePrintViewHierarchy(); 389 return true; 390} 391 392} // namespace 393 394//////////////////////////////////////////////////////////////////////////////// 395// AcceleratorControllerContext, public: 396 397AcceleratorControllerContext::AcceleratorControllerContext() { 398 current_accelerator_.set_type(ui::ET_UNKNOWN); 399 previous_accelerator_.set_type(ui::ET_UNKNOWN); 400} 401 402void AcceleratorControllerContext::UpdateContext( 403 const ui::Accelerator& accelerator) { 404 previous_accelerator_ = current_accelerator_; 405 current_accelerator_ = accelerator; 406} 407 408//////////////////////////////////////////////////////////////////////////////// 409// AcceleratorController, public: 410 411AcceleratorController::AcceleratorController() 412 : accelerator_manager_(new ui::AcceleratorManager) { 413 Init(); 414} 415 416AcceleratorController::~AcceleratorController() { 417} 418 419void AcceleratorController::Init() { 420 for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { 421 actions_allowed_at_login_screen_.insert( 422 kActionsAllowedAtLoginOrLockScreen[i]); 423 actions_allowed_at_lock_screen_.insert( 424 kActionsAllowedAtLoginOrLockScreen[i]); 425 } 426 for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) 427 actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]); 428 for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) 429 actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]); 430 for (size_t i = 0; i < kReservedActionsLength; ++i) 431 reserved_actions_.insert(kReservedActions[i]); 432 for (size_t i = 0; i < kNonrepeatableActionsLength; ++i) 433 nonrepeatable_actions_.insert(kNonrepeatableActions[i]); 434 for (size_t i = 0; i < kActionsAllowedInAppModeLength; ++i) 435 actions_allowed_in_app_mode_.insert(kActionsAllowedInAppMode[i]); 436 437 RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength); 438 439#if !defined(NDEBUG) 440 RegisterAccelerators(kDesktopAcceleratorData, kDesktopAcceleratorDataLength); 441#endif 442 443 if (DebugShortcutsEnabled()) { 444 RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength); 445 for (size_t i = 0; i < kReservedDebugActionsLength; ++i) 446 reserved_actions_.insert(kReservedDebugActions[i]); 447 } 448 449#if defined(OS_CHROMEOS) 450 keyboard_brightness_control_delegate_.reset( 451 new KeyboardBrightnessController()); 452#endif 453} 454 455void AcceleratorController::Register(const ui::Accelerator& accelerator, 456 ui::AcceleratorTarget* target) { 457 accelerator_manager_->Register(accelerator, 458 ui::AcceleratorManager::kNormalPriority, 459 target); 460} 461 462void AcceleratorController::Unregister(const ui::Accelerator& accelerator, 463 ui::AcceleratorTarget* target) { 464 accelerator_manager_->Unregister(accelerator, target); 465} 466 467void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) { 468 accelerator_manager_->UnregisterAll(target); 469} 470 471bool AcceleratorController::Process(const ui::Accelerator& accelerator) { 472 if (ime_control_delegate_) { 473 return accelerator_manager_->Process( 474 ime_control_delegate_->RemapAccelerator(accelerator)); 475 } 476 return accelerator_manager_->Process(accelerator); 477} 478 479bool AcceleratorController::IsRegistered( 480 const ui::Accelerator& accelerator) const { 481 return accelerator_manager_->GetCurrentTarget(accelerator) != NULL; 482} 483 484bool AcceleratorController::IsReservedAccelerator( 485 const ui::Accelerator& accelerator) const { 486 const ui::Accelerator remapped_accelerator = ime_control_delegate_.get() ? 487 ime_control_delegate_->RemapAccelerator(accelerator) : accelerator; 488 489 std::map<ui::Accelerator, int>::const_iterator iter = 490 accelerators_.find(remapped_accelerator); 491 if (iter == accelerators_.end()) 492 return false; // not an accelerator. 493 494 return reserved_actions_.find(iter->second) != reserved_actions_.end(); 495} 496 497bool AcceleratorController::PerformAction(int action, 498 const ui::Accelerator& accelerator) { 499 ash::Shell* shell = ash::Shell::GetInstance(); 500 if (!shell->session_state_delegate()->IsActiveUserSessionStarted() && 501 actions_allowed_at_login_screen_.find(action) == 502 actions_allowed_at_login_screen_.end()) { 503 return false; 504 } 505 if (shell->session_state_delegate()->IsScreenLocked() && 506 actions_allowed_at_lock_screen_.find(action) == 507 actions_allowed_at_lock_screen_.end()) { 508 return false; 509 } 510 if (shell->IsSystemModalWindowOpen() && 511 actions_allowed_at_modal_window_.find(action) == 512 actions_allowed_at_modal_window_.end()) { 513 // Note: we return true. This indicates the shortcut is handled 514 // and will not be passed to the modal window. This is important 515 // for things like Alt+Tab that would cause an undesired effect 516 // in the modal window by cycling through its window elements. 517 return true; 518 } 519 if (shell->delegate()->IsRunningInForcedAppMode() && 520 actions_allowed_in_app_mode_.find(action) == 521 actions_allowed_in_app_mode_.end()) { 522 return false; 523 } 524 525 const ui::KeyboardCode key_code = accelerator.key_code(); 526 // PerformAction() is performed from gesture controllers and passes 527 // empty Accelerator() instance as the second argument. Such events 528 // should never be suspended. 529 const bool gesture_event = key_code == ui::VKEY_UNKNOWN; 530 531 // Ignore accelerators invoked as repeated (while holding a key for a long 532 // time, if their handling is nonrepeatable. 533 if (nonrepeatable_actions_.find(action) != nonrepeatable_actions_.end() && 534 context_.repeated() && !gesture_event) { 535 return true; 536 } 537 // Type of the previous accelerator. Used by NEXT_IME and DISABLE_CAPS_LOCK. 538 const ui::EventType previous_event_type = 539 context_.previous_accelerator().type(); 540 const ui::KeyboardCode previous_key_code = 541 context_.previous_accelerator().key_code(); 542 543 // You *MUST* return true when some action is performed. Otherwise, this 544 // function might be called *twice*, via BrowserView::PreHandleKeyboardEvent 545 // and BrowserView::HandleKeyboardEvent, for a single accelerator press. 546 // 547 // If your accelerator invokes more than one line of code, please either 548 // implement it in your module's controller code (like TOGGLE_MIRROR_MODE 549 // below) or pull it into a HandleFoo() function above. 550 switch (action) { 551 case ACCESSIBLE_FOCUS_NEXT: 552 return HandleAccessibleFocusCycle(false); 553 case ACCESSIBLE_FOCUS_PREVIOUS: 554 return HandleAccessibleFocusCycle(true); 555 case CYCLE_BACKWARD_MRU: 556 HandleCycleBackwardMRU(accelerator); 557 return true; 558 case CYCLE_FORWARD_MRU: 559 HandleCycleForwardMRU(accelerator); 560 return true; 561 case CYCLE_LINEAR: 562 HandleCycleLinear(accelerator); 563 return true; 564#if defined(OS_CHROMEOS) 565 case ADD_REMOVE_DISPLAY: 566 Shell::GetInstance()->display_manager()->AddRemoveDisplay(); 567 return true; 568 case TOGGLE_MIRROR_MODE: 569 Shell::GetInstance()->display_controller()->ToggleMirrorMode(); 570 return true; 571 case LOCK_SCREEN: 572 if (key_code == ui::VKEY_L) 573 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_LOCK_SCREEN_L); 574 return HandleLock(); 575 case OPEN_FILE_MANAGER: 576 return HandleFileManager(); 577 case OPEN_CROSH: 578 return HandleCrosh(); 579 case SILENCE_SPOKEN_FEEDBACK: 580 HandleSilenceSpokenFeedback(); 581 break; 582 case SWAP_PRIMARY_DISPLAY: 583 Shell::GetInstance()->display_controller()->SwapPrimaryDisplay(); 584 return true; 585 case SWITCH_TO_NEXT_USER: 586 return SwitchToNextUser(); 587 case TOGGLE_SPOKEN_FEEDBACK: 588 return HandleToggleSpokenFeedback(); 589 case TOGGLE_WIFI: 590 Shell::GetInstance()->system_tray_notifier()->NotifyRequestToggleWifi(); 591 return true; 592 case TOUCH_HUD_CLEAR: { 593 internal::RootWindowController* controller = 594 internal::RootWindowController::ForTargetRootWindow(); 595 if (controller->touch_hud_debug()) { 596 controller->touch_hud_debug()->Clear(); 597 return true; 598 } 599 return false; 600 } 601 case TOUCH_HUD_MODE_CHANGE: { 602 internal::RootWindowController* controller = 603 internal::RootWindowController::ForTargetRootWindow(); 604 if (controller->touch_hud_debug()) { 605 controller->touch_hud_debug()->ChangeToNextMode(); 606 return true; 607 } 608 return false; 609 } 610 case TOUCH_HUD_PROJECTION_TOGGLE: { 611 bool enabled = Shell::GetInstance()->is_touch_hud_projection_enabled(); 612 Shell::GetInstance()->SetTouchHudProjectionEnabled(!enabled); 613 return true; 614 } 615 case DISABLE_GPU_WATCHDOG: 616 content::GpuDataManager::GetInstance()->DisableGpuWatchdog(); 617 return true; 618#endif 619 case OPEN_FEEDBACK_PAGE: 620 ash::Shell::GetInstance()->new_window_delegate()->OpenFeedbackPage(); 621 return true; 622 case EXIT: 623 // UMA metrics are recorded in the handler. 624 exit_warning_handler_.HandleAccelerator(); 625 return true; 626 case NEW_INCOGNITO_WINDOW: 627 Shell::GetInstance()->new_window_delegate()->NewWindow( 628 true /* is_incognito */); 629 return true; 630 case NEW_TAB: 631 if (key_code == ui::VKEY_T) 632 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEWTAB_T); 633 Shell::GetInstance()->new_window_delegate()->NewTab(); 634 return true; 635 case NEW_WINDOW: 636 Shell::GetInstance()->new_window_delegate()->NewWindow( 637 false /* is_incognito */); 638 return true; 639 case RESTORE_TAB: 640 Shell::GetInstance()->new_window_delegate()->RestoreTab(); 641 return true; 642 case TAKE_SCREENSHOT: 643 if (screenshot_delegate_.get() && 644 screenshot_delegate_->CanTakeScreenshot()) { 645 screenshot_delegate_->HandleTakeScreenshotForAllRootWindows(); 646 } 647 // Return true to prevent propagation of the key event. 648 return true; 649 case TAKE_PARTIAL_SCREENSHOT: 650 if (screenshot_delegate_) { 651 ash::PartialScreenshotView::StartPartialScreenshot( 652 screenshot_delegate_.get()); 653 } 654 // Return true to prevent propagation of the key event because 655 // this key combination is reserved for partial screenshot. 656 return true; 657 case TOGGLE_APP_LIST: 658 // If something else was pressed between the Search key (LWIN) 659 // being pressed and released, then ignore the release of the 660 // Search key. 661 if (key_code == ui::VKEY_LWIN && 662 (previous_event_type == ui::ET_KEY_RELEASED || 663 previous_key_code != ui::VKEY_LWIN)) 664 return false; 665 if (key_code == ui::VKEY_LWIN) 666 shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_SEARCH_LWIN); 667 // When spoken feedback is enabled, we should neither toggle the list nor 668 // consume the key since Search+Shift is one of the shortcuts the a11y 669 // feature uses. crbug.com/132296 670 DCHECK_EQ(ui::VKEY_LWIN, accelerator.key_code()); 671 if (Shell::GetInstance()->accessibility_delegate()-> 672 IsSpokenFeedbackEnabled()) 673 return false; 674 ash::Shell::GetInstance()->ToggleAppList(NULL); 675 return true; 676 case DISABLE_CAPS_LOCK: 677 if (previous_event_type == ui::ET_KEY_RELEASED || 678 (previous_key_code != ui::VKEY_LSHIFT && 679 previous_key_code != ui::VKEY_SHIFT && 680 previous_key_code != ui::VKEY_RSHIFT)) { 681 // If something else was pressed between the Shift key being pressed 682 // and released, then ignore the release of the Shift key. 683 return false; 684 } 685 if (shell->caps_lock_delegate()->IsCapsLockEnabled()) { 686 shell->caps_lock_delegate()->SetCapsLockEnabled(false); 687 return true; 688 } 689 return false; 690 case TOGGLE_CAPS_LOCK: 691 if (key_code == ui::VKEY_LWIN) { 692 // If something else was pressed between the Search key (LWIN) 693 // being pressed and released, then ignore the release of the 694 // Search key. 695 // TODO(danakj): Releasing Alt first breaks this: crbug.com/166495 696 if (previous_event_type == ui::ET_KEY_RELEASED || 697 previous_key_code != ui::VKEY_LWIN) 698 return false; 699 } 700 shell->caps_lock_delegate()->ToggleCapsLock(); 701 return true; 702 case BRIGHTNESS_DOWN: 703 if (brightness_control_delegate_) 704 return brightness_control_delegate_->HandleBrightnessDown(accelerator); 705 break; 706 case BRIGHTNESS_UP: 707 if (brightness_control_delegate_) 708 return brightness_control_delegate_->HandleBrightnessUp(accelerator); 709 break; 710 case KEYBOARD_BRIGHTNESS_DOWN: 711 if (keyboard_brightness_control_delegate_) 712 return keyboard_brightness_control_delegate_-> 713 HandleKeyboardBrightnessDown(accelerator); 714 break; 715 case KEYBOARD_BRIGHTNESS_UP: 716 if (keyboard_brightness_control_delegate_) 717 return keyboard_brightness_control_delegate_-> 718 HandleKeyboardBrightnessUp(accelerator); 719 break; 720 case VOLUME_MUTE: { 721 ash::VolumeControlDelegate* volume_delegate = 722 shell->system_tray_delegate()->GetVolumeControlDelegate(); 723 return volume_delegate && volume_delegate->HandleVolumeMute(accelerator); 724 } 725 case VOLUME_DOWN: { 726 ash::VolumeControlDelegate* volume_delegate = 727 shell->system_tray_delegate()->GetVolumeControlDelegate(); 728 return volume_delegate && volume_delegate->HandleVolumeDown(accelerator); 729 } 730 case VOLUME_UP: { 731 ash::VolumeControlDelegate* volume_delegate = 732 shell->system_tray_delegate()->GetVolumeControlDelegate(); 733 return volume_delegate && volume_delegate->HandleVolumeUp(accelerator); 734 } 735 case FOCUS_LAUNCHER: 736 return shell->focus_cycler()->FocusWidget( 737 Launcher::ForPrimaryDisplay()->shelf_widget()); 738 case FOCUS_NEXT_PANE: 739 return HandleRotatePaneFocus(Shell::FORWARD); 740 case FOCUS_PREVIOUS_PANE: 741 return HandleRotatePaneFocus(Shell::BACKWARD); 742 case SHOW_KEYBOARD_OVERLAY: 743 ash::Shell::GetInstance()->new_window_delegate()->ShowKeyboardOverlay(); 744 return true; 745 case SHOW_OAK: 746 if (CommandLine::ForCurrentProcess()->HasSwitch( 747 switches::kAshEnableOak)) { 748 oak::ShowOakWindowWithContext(Shell::GetPrimaryRootWindow()); 749 return true; 750 } 751 break; 752 case SHOW_SYSTEM_TRAY_BUBBLE: { 753 internal::RootWindowController* controller = 754 internal::RootWindowController::ForTargetRootWindow(); 755 if (!controller->GetSystemTray()->HasSystemBubble()) { 756 controller->GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); 757 return true; 758 } 759 break; 760 } 761 case SHOW_MESSAGE_CENTER_BUBBLE: { 762 internal::RootWindowController* controller = 763 internal::RootWindowController::ForTargetRootWindow(); 764 internal::StatusAreaWidget* status_area_widget = 765 controller->shelf()->status_area_widget(); 766 if (status_area_widget) { 767 WebNotificationTray* notification_tray = 768 status_area_widget->web_notification_tray(); 769 if (notification_tray->visible()) 770 notification_tray->ShowMessageCenterBubble(); 771 } 772 break; 773 } 774 case SHOW_TASK_MANAGER: 775 Shell::GetInstance()->new_window_delegate()->ShowTaskManager(); 776 return true; 777 case NEXT_IME: 778 // This check is necessary e.g. not to process the Shift+Alt+ 779 // ET_KEY_RELEASED accelerator for Chrome OS (see ash/accelerators/ 780 // accelerator_controller.cc) when Shift+Alt+Tab is pressed and then Tab 781 // is released. 782 if (previous_event_type == ui::ET_KEY_RELEASED && 783 // Workaround for crbug.com/139556. CJK IME users tend to press 784 // Enter (or Space) and Shift+Alt almost at the same time to commit 785 // an IME string and then switch from the IME to the English layout. 786 // This workaround allows the user to trigger NEXT_IME even if the 787 // user presses Shift+Alt before releasing Enter. 788 // TODO(nona|mazda): Fix crbug.com/139556 in a cleaner way. 789 previous_key_code != ui::VKEY_RETURN && 790 previous_key_code != ui::VKEY_SPACE) { 791 // We totally ignore this accelerator. 792 // TODO(mazda): Fix crbug.com/158217 793 return false; 794 } 795 if (ime_control_delegate_) 796 return ime_control_delegate_->HandleNextIme(); 797 break; 798 case PREVIOUS_IME: 799 if (ime_control_delegate_) 800 return ime_control_delegate_->HandlePreviousIme(accelerator); 801 break; 802 case PRINT_UI_HIERARCHIES: 803 return HandlePrintUIHierarchies(); 804 case SWITCH_IME: 805 if (ime_control_delegate_) 806 return ime_control_delegate_->HandleSwitchIme(accelerator); 807 break; 808 case LAUNCH_APP_0: 809 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(0); 810 return true; 811 case LAUNCH_APP_1: 812 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(1); 813 return true; 814 case LAUNCH_APP_2: 815 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(2); 816 return true; 817 case LAUNCH_APP_3: 818 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(3); 819 return true; 820 case LAUNCH_APP_4: 821 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(4); 822 return true; 823 case LAUNCH_APP_5: 824 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(5); 825 return true; 826 case LAUNCH_APP_6: 827 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(6); 828 return true; 829 case LAUNCH_APP_7: 830 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(7); 831 return true; 832 case LAUNCH_LAST_APP: 833 Launcher::ForPrimaryDisplay()->LaunchAppIndexAt(-1); 834 return true; 835 case WINDOW_SNAP_LEFT: 836 case WINDOW_SNAP_RIGHT: { 837 wm::WindowState* window_state = wm::GetActiveWindowState(); 838 // Disable window docking shortcut key for full screen window due to 839 // http://crbug.com/135487. 840 if (!window_state || 841 window_state->window()->type() != aura::client::WINDOW_TYPE_NORMAL || 842 window_state->IsFullscreen()) { 843 break; 844 } 845 846 internal::SnapSizer::SnapWindow(window_state, 847 action == WINDOW_SNAP_LEFT ? internal::SnapSizer::LEFT_EDGE : 848 internal::SnapSizer::RIGHT_EDGE); 849 return true; 850 } 851 case WINDOW_MINIMIZE: 852 return accelerators::ToggleMinimized(); 853 case TOGGLE_FULLSCREEN: { 854 if (key_code == ui::VKEY_MEDIA_LAUNCH_APP2) { 855 shell->delegate()->RecordUserMetricsAction( 856 UMA_ACCEL_FULLSCREEN_F4); 857 } 858 accelerators::ToggleFullscreen(); 859 return true; 860 } 861 case TOGGLE_MAXIMIZED: { 862 accelerators::ToggleMaximized(); 863 return true; 864 } 865 case WINDOW_POSITION_CENTER: { 866 aura::Window* window = wm::GetActiveWindow(); 867 if (window) { 868 wm::CenterWindow(window); 869 return true; 870 } 871 break; 872 } 873 case SCALE_UI_UP: 874 return HandleScaleUI(true /* up */); 875 case SCALE_UI_DOWN: 876 return HandleScaleUI(false /* down */); 877 case SCALE_UI_RESET: 878 return HandleScaleReset(); 879 case ROTATE_WINDOW: 880 return HandleRotateActiveWindow(); 881 case ROTATE_SCREEN: 882 return HandleRotateScreen(); 883 case TOGGLE_DESKTOP_BACKGROUND_MODE: 884 return debug::CycleDesktopBackgroundMode(); 885 case TOGGLE_ROOT_WINDOW_FULL_SCREEN: 886 return HandleToggleRootWindowFullScreen(); 887 case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR: 888 Shell::GetInstance()->display_manager()->ToggleDisplayScaleFactor(); 889 return true; 890 case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS: 891 ash::debug::ToggleShowDebugBorders(); 892 return true; 893 case DEBUG_TOGGLE_SHOW_FPS_COUNTER: 894 ash::debug::ToggleShowFpsCounter(); 895 return true; 896 case DEBUG_TOGGLE_SHOW_PAINT_RECTS: 897 ash::debug::ToggleShowPaintRects(); 898 return true; 899 case MAGNIFY_SCREEN_ZOOM_IN: 900 return HandleMagnifyScreen(1); 901 case MAGNIFY_SCREEN_ZOOM_OUT: 902 return HandleMagnifyScreen(-1); 903 case MEDIA_NEXT_TRACK: 904 return HandleMediaNextTrack(); 905 case MEDIA_PLAY_PAUSE: 906 return HandleMediaPlayPause(); 907 case MEDIA_PREV_TRACK: 908 return HandleMediaPrevTrack(); 909 case POWER_PRESSED: // fallthrough 910 case POWER_RELEASED: 911#if defined(OS_CHROMEOS) 912 if (!base::SysInfo::IsRunningOnChromeOS()) { 913 // There is no powerd in linux desktop, so call the 914 // PowerButtonController here. 915 Shell::GetInstance()->power_button_controller()-> 916 OnPowerButtonEvent(action == POWER_PRESSED, base::TimeTicks()); 917 } 918#endif 919 // We don't do anything with these at present on the device, 920 // (power button events are reported to us from powerm via 921 // D-BUS), but we consume them to prevent them from getting 922 // passed to apps -- see http://crbug.com/146609. 923 return true; 924 case LOCK_PRESSED: 925 case LOCK_RELEASED: 926 Shell::GetInstance()->power_button_controller()-> 927 OnLockButtonEvent(action == LOCK_PRESSED, base::TimeTicks()); 928 return true; 929 case PRINT_LAYER_HIERARCHY: 930 return HandlePrintLayerHierarchy(); 931 case PRINT_VIEW_HIERARCHY: 932 return HandlePrintViewHierarchy(); 933 case PRINT_WINDOW_HIERARCHY: 934 return HandlePrintWindowHierarchy(); 935 default: 936 NOTREACHED() << "Unhandled action " << action; 937 } 938 return false; 939} 940 941void AcceleratorController::SetBrightnessControlDelegate( 942 scoped_ptr<BrightnessControlDelegate> brightness_control_delegate) { 943 // Install brightness control delegate only when internal 944 // display exists. 945 if (Shell::GetInstance()->display_manager()->HasInternalDisplay() || 946 CommandLine::ForCurrentProcess()->HasSwitch( 947 switches::kAshEnableBrightnessControl)) { 948 brightness_control_delegate_ = brightness_control_delegate.Pass(); 949 } 950} 951 952void AcceleratorController::SetImeControlDelegate( 953 scoped_ptr<ImeControlDelegate> ime_control_delegate) { 954 ime_control_delegate_ = ime_control_delegate.Pass(); 955} 956 957void AcceleratorController::SetScreenshotDelegate( 958 scoped_ptr<ScreenshotDelegate> screenshot_delegate) { 959 screenshot_delegate_ = screenshot_delegate.Pass(); 960} 961 962//////////////////////////////////////////////////////////////////////////////// 963// AcceleratorController, ui::AcceleratorTarget implementation: 964 965bool AcceleratorController::AcceleratorPressed( 966 const ui::Accelerator& accelerator) { 967 std::map<ui::Accelerator, int>::const_iterator it = 968 accelerators_.find(accelerator); 969 DCHECK(it != accelerators_.end()); 970 return PerformAction(static_cast<AcceleratorAction>(it->second), accelerator); 971} 972 973void AcceleratorController::RegisterAccelerators( 974 const AcceleratorData accelerators[], 975 size_t accelerators_length) { 976 for (size_t i = 0; i < accelerators_length; ++i) { 977 ui::Accelerator accelerator(accelerators[i].keycode, 978 accelerators[i].modifiers); 979 accelerator.set_type(accelerators[i].trigger_on_press ? 980 ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED); 981 Register(accelerator, this); 982 accelerators_.insert( 983 std::make_pair(accelerator, accelerators[i].action)); 984 } 985} 986 987void AcceleratorController::SetKeyboardBrightnessControlDelegate( 988 scoped_ptr<KeyboardBrightnessControlDelegate> 989 keyboard_brightness_control_delegate) { 990 keyboard_brightness_control_delegate_ = 991 keyboard_brightness_control_delegate.Pass(); 992} 993 994bool AcceleratorController::CanHandleAccelerators() const { 995 return true; 996} 997 998} // namespace ash 999