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