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