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