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