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