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