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