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