accelerator_controller.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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 <string>
10
11#include "ash/accelerators/accelerator_commands.h"
12#include "ash/accelerators/accelerator_table.h"
13#include "ash/accelerators/debug_commands.h"
14#include "ash/ash_switches.h"
15#include "ash/debug.h"
16#include "ash/display/display_controller.h"
17#include "ash/display/display_manager.h"
18#include "ash/focus_cycler.h"
19#include "ash/gpu_support.h"
20#include "ash/host/ash_window_tree_host.h"
21#include "ash/ime_control_delegate.h"
22#include "ash/magnifier/magnification_controller.h"
23#include "ash/magnifier/partial_magnification_controller.h"
24#include "ash/media_delegate.h"
25#include "ash/multi_profile_uma.h"
26#include "ash/new_window_delegate.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/session_state_delegate.h"
31#include "ash/shelf/shelf.h"
32#include "ash/shelf/shelf_delegate.h"
33#include "ash/shelf/shelf_model.h"
34#include "ash/shelf/shelf_widget.h"
35#include "ash/shell.h"
36#include "ash/shell_delegate.h"
37#include "ash/shell_window_ids.h"
38#include "ash/system/brightness_control_delegate.h"
39#include "ash/system/keyboard_brightness/keyboard_brightness_control_delegate.h"
40#include "ash/system/status_area_widget.h"
41#include "ash/system/tray/system_tray.h"
42#include "ash/system/tray/system_tray_delegate.h"
43#include "ash/system/tray/system_tray_notifier.h"
44#include "ash/system/web_notification/web_notification_tray.h"
45#include "ash/touch/touch_hud_debug.h"
46#include "ash/volume_control_delegate.h"
47#include "ash/wm/maximize_mode/maximize_mode_controller.h"
48#include "ash/wm/mru_window_tracker.h"
49#include "ash/wm/overview/window_selector_controller.h"
50#include "ash/wm/partial_screenshot_view.h"
51#include "ash/wm/power_button_controller.h"
52#include "ash/wm/window_cycle_controller.h"
53#include "ash/wm/window_state.h"
54#include "ash/wm/window_util.h"
55#include "ash/wm/wm_event.h"
56#include "base/bind.h"
57#include "base/command_line.h"
58#include "base/metrics/user_metrics.h"
59#include "ui/aura/env.h"
60#include "ui/aura/window_event_dispatcher.h"
61#include "ui/base/accelerators/accelerator.h"
62#include "ui/base/accelerators/accelerator_manager.h"
63#include "ui/compositor/debug_utils.h"
64#include "ui/compositor/layer.h"
65#include "ui/compositor/layer_animation_sequence.h"
66#include "ui/compositor/layer_animator.h"
67#include "ui/events/event.h"
68#include "ui/events/keycodes/keyboard_codes.h"
69#include "ui/gfx/screen.h"
70#include "ui/views/controls/webview/webview.h"
71#include "ui/views/debug_utils.h"
72#include "ui/views/widget/widget.h"
73
74#if defined(OS_CHROMEOS)
75#include "ash/system/chromeos/keyboard_brightness_controller.h"
76#include "base/sys_info.h"
77#include "chromeos/ime/ime_keyboard.h"
78#include "chromeos/ime/input_method_manager.h"
79#endif  // defined(OS_CHROMEOS)
80
81namespace ash {
82namespace {
83
84using base::UserMetricsAction;
85
86bool DebugShortcutsEnabled() {
87#if defined(NDEBUG)
88  return CommandLine::ForCurrentProcess()->HasSwitch(
89          switches::kAshDebugShortcuts);
90#else
91  return true;
92#endif
93}
94
95bool HandleAccessibleFocusCycle(bool reverse) {
96  if (reverse) {
97    base::RecordAction(UserMetricsAction("Accel_Accessible_Focus_Previous"));
98  } else {
99    base::RecordAction(UserMetricsAction("Accel_Accessible_Focus_Next"));
100  }
101
102  if (!Shell::GetInstance()->accessibility_delegate()->
103      IsSpokenFeedbackEnabled()) {
104    return false;
105  }
106  aura::Window* active_window = ash::wm::GetActiveWindow();
107  if (!active_window)
108    return false;
109  views::Widget* widget =
110      views::Widget::GetWidgetForNativeWindow(active_window);
111  if (!widget)
112    return false;
113  views::FocusManager* focus_manager = widget->GetFocusManager();
114  if (!focus_manager)
115    return false;
116  views::View* view = focus_manager->GetFocusedView();
117  if (!view)
118    return false;
119  if (!strcmp(view->GetClassName(), views::WebView::kViewClassName))
120    return false;
121
122  focus_manager->AdvanceFocus(reverse);
123  return true;
124}
125
126bool HandleCycleBackwardMRU(const ui::Accelerator& accelerator) {
127  if (accelerator.key_code() == ui::VKEY_TAB)
128    base::RecordAction(base::UserMetricsAction("Accel_PrevWindow_Tab"));
129
130  Shell::GetInstance()->window_cycle_controller()->HandleCycleWindow(
131      WindowCycleController::BACKWARD);
132  return true;
133}
134
135bool HandleCycleForwardMRU(const ui::Accelerator& accelerator) {
136  if (accelerator.key_code() == ui::VKEY_TAB)
137    base::RecordAction(base::UserMetricsAction("Accel_NextWindow_Tab"));
138
139  Shell::GetInstance()->window_cycle_controller()->HandleCycleWindow(
140      WindowCycleController::FORWARD);
141  return true;
142}
143
144bool ToggleOverview(const ui::Accelerator& accelerator) {
145  base::RecordAction(base::UserMetricsAction("Accel_Overview_F5"));
146  Shell::GetInstance()->window_selector_controller()->ToggleOverview();
147  return true;
148}
149
150bool HandleFocusLauncher() {
151  Shell* shell = Shell::GetInstance();
152  base::RecordAction(base::UserMetricsAction("Accel_Focus_Launcher"));
153  return shell->focus_cycler()->FocusWidget(
154      Shelf::ForPrimaryDisplay()->shelf_widget());
155}
156
157bool HandleLaunchAppN(int n) {
158  base::RecordAction(UserMetricsAction("Accel_Launch_App"));
159  Shelf::ForPrimaryDisplay()->LaunchAppIndexAt(n);
160  return true;
161}
162
163bool HandleLaunchLastApp() {
164  base::RecordAction(UserMetricsAction("Accel_Launch_Last_App"));
165  Shelf::ForPrimaryDisplay()->LaunchAppIndexAt(-1);
166  return true;
167}
168
169// Magnify the screen
170bool HandleMagnifyScreen(int delta_index) {
171  if (ash::Shell::GetInstance()->magnification_controller()->IsEnabled()) {
172    // TODO(yoshiki): Move the following logic to MagnificationController.
173    float scale =
174        ash::Shell::GetInstance()->magnification_controller()->GetScale();
175    // Calculate rounded logarithm (base kMagnificationScaleFactor) of scale.
176    int scale_index =
177        std::floor(std::log(scale) / std::log(kMagnificationScaleFactor) + 0.5);
178
179    int new_scale_index = std::max(0, std::min(8, scale_index + delta_index));
180
181    ash::Shell::GetInstance()->magnification_controller()->
182        SetScale(std::pow(kMagnificationScaleFactor, new_scale_index), true);
183  } else if (ash::Shell::GetInstance()->
184             partial_magnification_controller()->is_enabled()) {
185    float scale = delta_index > 0 ? kDefaultPartialMagnifiedScale : 1;
186    ash::Shell::GetInstance()->partial_magnification_controller()->
187        SetScale(scale);
188  }
189
190  return true;
191}
192
193bool HandleMediaNextTrack() {
194  Shell::GetInstance()->media_delegate()->HandleMediaNextTrack();
195  return true;
196}
197
198bool HandleMediaPlayPause() {
199  Shell::GetInstance()->media_delegate()->HandleMediaPlayPause();
200  return true;
201}
202
203bool HandleMediaPrevTrack() {
204  Shell::GetInstance()->media_delegate()->HandleMediaPrevTrack();
205  return true;
206}
207
208bool HandleNewIncognitoWindow() {
209  base::RecordAction(UserMetricsAction("Accel_New_Incognito_Window"));
210  bool incognito_allowed =
211    Shell::GetInstance()->delegate()->IsIncognitoAllowed();
212  if (incognito_allowed)
213    Shell::GetInstance()->new_window_delegate()->NewWindow(
214        true /* is_incognito */);
215  return incognito_allowed;
216}
217
218bool HandleNewTab(ui::KeyboardCode key_code) {
219  if (key_code == ui::VKEY_T)
220    base::RecordAction(base::UserMetricsAction("Accel_NewTab_T"));
221  Shell::GetInstance()->new_window_delegate()->NewTab();
222  return true;
223}
224
225bool HandleNewWindow() {
226  base::RecordAction(base::UserMetricsAction("Accel_New_Window"));
227  Shell::GetInstance()->new_window_delegate()->NewWindow(
228      false /* is_incognito */);
229  return true;
230}
231
232bool HandleNextIme(ImeControlDelegate* ime_control_delegate,
233                   ui::EventType previous_event_type,
234                   ui::KeyboardCode previous_key_code) {
235  // This check is necessary e.g. not to process the Shift+Alt+
236  // ET_KEY_RELEASED accelerator for Chrome OS (see ash/accelerators/
237  // accelerator_controller.cc) when Shift+Alt+Tab is pressed and then Tab
238  // is released.
239  if (previous_event_type == ui::ET_KEY_RELEASED &&
240      // Workaround for crbug.com/139556. CJK IME users tend to press
241      // Enter (or Space) and Shift+Alt almost at the same time to commit
242      // an IME string and then switch from the IME to the English layout.
243      // This workaround allows the user to trigger NEXT_IME even if the
244      // user presses Shift+Alt before releasing Enter.
245      // TODO(nona|mazda): Fix crbug.com/139556 in a cleaner way.
246      previous_key_code != ui::VKEY_RETURN &&
247      previous_key_code != ui::VKEY_SPACE) {
248    // We totally ignore this accelerator.
249    // TODO(mazda): Fix crbug.com/158217
250    return false;
251  }
252  base::RecordAction(UserMetricsAction("Accel_Next_Ime"));
253  if (ime_control_delegate)
254    return ime_control_delegate->HandleNextIme();
255  return false;
256}
257
258bool HandleOpenFeedbackPage() {
259  base::RecordAction(UserMetricsAction("Accel_Open_Feedback_Page"));
260  ash::Shell::GetInstance()->new_window_delegate()->OpenFeedbackPage();
261  return true;
262}
263
264bool HandlePositionCenter() {
265  base::RecordAction(UserMetricsAction("Accel_Window_Position_Center"));
266  aura::Window* window = wm::GetActiveWindow();
267  // Docked windows do not support centering and ignore accelerator.
268  if (window && !wm::GetWindowState(window)->IsDocked()) {
269    wm::CenterWindow(window);
270    return true;
271  }
272  return false;
273}
274
275bool HandlePreviousIme(ImeControlDelegate* ime_control_delegate,
276                       const ui::Accelerator& accelerator) {
277  base::RecordAction(UserMetricsAction("Accel_Previous_Ime"));
278  if (ime_control_delegate)
279    return ime_control_delegate->HandlePreviousIme(accelerator);
280  return false;
281}
282
283bool HandleRestoreTab() {
284  base::RecordAction(base::UserMetricsAction("Accel_Restore_Tab"));
285  Shell::GetInstance()->new_window_delegate()->RestoreTab();
286  return true;
287}
288
289bool HandleRotatePaneFocus(Shell::Direction direction) {
290  Shell* shell = Shell::GetInstance();
291  switch (direction) {
292    // TODO(stevet): Not sure if this is the same as IDC_FOCUS_NEXT_PANE.
293    case Shell::FORWARD: {
294      base::RecordAction(UserMetricsAction("Accel_Focus_Next_Pane"));
295      shell->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
296      break;
297    }
298    case Shell::BACKWARD: {
299      base::RecordAction(UserMetricsAction("Accel_Focus_Previous_Pane"));
300      shell->focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
301      break;
302    }
303  }
304  return true;
305}
306
307// Rotate the active window.
308bool HandleRotateActiveWindow() {
309  base::RecordAction(UserMetricsAction("Accel_Rotate_Window"));
310  aura::Window* active_window = wm::GetActiveWindow();
311  if (active_window) {
312    // The rotation animation bases its target transform on the current
313    // rotation and position. Since there could be an animation in progress
314    // right now, queue this animation so when it starts it picks up a neutral
315    // rotation and position. Use replace so we only enqueue one at a time.
316    active_window->layer()->GetAnimator()->
317        set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
318    active_window->layer()->GetAnimator()->StartAnimation(
319        new ui::LayerAnimationSequence(
320            new ash::ScreenRotation(360, active_window->layer())));
321  }
322  return true;
323}
324
325gfx::Display::Rotation GetNextRotation(gfx::Display::Rotation current) {
326  switch (current) {
327    case gfx::Display::ROTATE_0:
328      return gfx::Display::ROTATE_90;
329    case gfx::Display::ROTATE_90:
330      return gfx::Display::ROTATE_180;
331    case gfx::Display::ROTATE_180:
332      return gfx::Display::ROTATE_270;
333    case gfx::Display::ROTATE_270:
334      return gfx::Display::ROTATE_0;
335  }
336  NOTREACHED() << "Unknown rotation:" << current;
337  return gfx::Display::ROTATE_0;
338}
339
340// Rotates the screen.
341bool HandleRotateScreen() {
342  base::RecordAction(UserMetricsAction("Accel_Rotate_Window"));
343  gfx::Point point = Shell::GetScreen()->GetCursorScreenPoint();
344  gfx::Display display = Shell::GetScreen()->GetDisplayNearestPoint(point);
345  const DisplayInfo& display_info =
346      Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
347  Shell::GetInstance()->display_manager()->SetDisplayRotation(
348      display.id(), GetNextRotation(display_info.rotation()));
349  return true;
350}
351
352bool HandleScaleReset() {
353  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
354  int64 display_id = display_manager->GetDisplayIdForUIScaling();
355  if (display_id == gfx::Display::kInvalidDisplayID)
356    return false;
357
358  base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Reset"));
359
360  display_manager->SetDisplayUIScale(display_id, 1.0f);
361  return true;
362}
363
364bool HandleScaleUI(bool up) {
365  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
366  int64 display_id = display_manager->GetDisplayIdForUIScaling();
367  if (display_id == gfx::Display::kInvalidDisplayID)
368    return false;
369
370  if (up) {
371    base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Up"));
372  } else {
373    base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Down"));
374  }
375
376  const DisplayInfo& display_info = display_manager->GetDisplayInfo(display_id);
377  float next_scale = DisplayManager::GetNextUIScale(display_info, up);
378  display_manager->SetDisplayUIScale(display_id, next_scale);
379  return true;
380}
381
382#if defined(OS_CHROMEOS)
383bool HandleSwapPrimaryDisplay() {
384  base::RecordAction(UserMetricsAction("Accel_Swap_Primary_Display"));
385  Shell::GetInstance()->display_controller()->SwapPrimaryDisplay();
386  return true;
387}
388#endif
389
390bool HandleShowKeyboardOverlay() {
391  base::RecordAction(UserMetricsAction("Accel_Show_Keyboard_Overlay"));
392  ash::Shell::GetInstance()->new_window_delegate()->ShowKeyboardOverlay();
393
394  return true;
395}
396
397void HandleShowMessageCenterBubble() {
398  base::RecordAction(UserMetricsAction("Accel_Show_Message_Center_Bubble"));
399  RootWindowController* controller =
400      RootWindowController::ForTargetRootWindow();
401  StatusAreaWidget* status_area_widget =
402      controller->shelf()->status_area_widget();
403  if (status_area_widget) {
404    WebNotificationTray* notification_tray =
405      status_area_widget->web_notification_tray();
406    if (notification_tray->visible())
407      notification_tray->ShowMessageCenterBubble();
408  }
409}
410
411bool HandleShowSystemTrayBubble() {
412  base::RecordAction(UserMetricsAction("Accel_Show_System_Tray_Bubble"));
413  RootWindowController* controller =
414      RootWindowController::ForTargetRootWindow();
415  if (!controller->GetSystemTray()->HasSystemBubble()) {
416    controller->GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW);
417    return true;
418  }
419  return false;
420}
421
422bool HandleShowTaskManager() {
423  base::RecordAction(UserMetricsAction("Accel_Show_Task_Manager"));
424  Shell::GetInstance()->new_window_delegate()->ShowTaskManager();
425  return true;
426}
427
428#if defined(OS_CHROMEOS)
429void HandleSilenceSpokenFeedback() {
430  base::RecordAction(UserMetricsAction("Accel_Silence_Spoken_Feedback"));
431
432  AccessibilityDelegate* delegate =
433      Shell::GetInstance()->accessibility_delegate();
434  if (!delegate->IsSpokenFeedbackEnabled())
435    return;
436  delegate->SilenceSpokenFeedback();
437}
438#endif
439
440bool HandleSwitchIme(ImeControlDelegate* ime_control_delegate,
441                     const ui::Accelerator& accelerator) {
442  base::RecordAction(UserMetricsAction("Accel_Switch_Ime"));
443  if (ime_control_delegate)
444    return ime_control_delegate->HandleSwitchIme(accelerator);
445  return false;
446}
447
448bool HandleTakePartialScreenshot(ScreenshotDelegate* screenshot_delegate) {
449  base::RecordAction(UserMetricsAction("Accel_Take_Partial_Screenshot"));
450  if (screenshot_delegate) {
451    ash::PartialScreenshotView::StartPartialScreenshot(
452        screenshot_delegate);
453  }
454  // Return true to prevent propagation of the key event because
455  // this key combination is reserved for partial screenshot.
456  return true;
457}
458
459bool HandleTakeScreenshot(ScreenshotDelegate* screenshot_delegate) {
460  base::RecordAction(UserMetricsAction("Accel_Take_Screenshot"));
461  if (screenshot_delegate &&
462      screenshot_delegate->CanTakeScreenshot()) {
463    screenshot_delegate->HandleTakeScreenshotForAllRootWindows();
464  }
465  // Return true to prevent propagation of the key event.
466  return true;
467}
468
469bool HandleToggleAppList(ui::KeyboardCode key_code,
470                         ui::EventType previous_event_type,
471                         ui::KeyboardCode previous_key_code,
472                         const ui::Accelerator& accelerator) {
473  // If something else was pressed between the Search key (LWIN)
474  // being pressed and released, then ignore the release of the
475  // Search key.
476  if (key_code == ui::VKEY_LWIN &&
477      (previous_event_type == ui::ET_KEY_RELEASED ||
478       previous_key_code != ui::VKEY_LWIN))
479    return false;
480  if (key_code == ui::VKEY_LWIN)
481    base::RecordAction(base::UserMetricsAction("Accel_Search_LWin"));
482  // When spoken feedback is enabled, we should neither toggle the list nor
483  // consume the key since Search+Shift is one of the shortcuts the a11y
484  // feature uses. crbug.com/132296
485  DCHECK_EQ(ui::VKEY_LWIN, accelerator.key_code());
486  if (Shell::GetInstance()->accessibility_delegate()->
487      IsSpokenFeedbackEnabled())
488    return false;
489  ash::Shell::GetInstance()->ToggleAppList(NULL);
490  return true;
491}
492
493bool HandleToggleFullscreen(ui::KeyboardCode key_code) {
494  if (key_code == ui::VKEY_MEDIA_LAUNCH_APP2) {
495    base::RecordAction(UserMetricsAction("Accel_Fullscreen_F4"));
496  }
497  accelerators::ToggleFullscreen();
498  return true;
499}
500
501bool HandleToggleRootWindowFullScreen() {
502  Shell::GetPrimaryRootWindowController()->ash_host()->ToggleFullScreen();
503  return true;
504}
505
506bool HandleWindowSnap(int action) {
507  wm::WindowState* window_state = wm::GetActiveWindowState();
508  // Disable window snapping shortcut key for full screen window due to
509  // http://crbug.com/135487.
510  if (!window_state ||
511      window_state->window()->type() != ui::wm::WINDOW_TYPE_NORMAL ||
512      window_state->IsFullscreen() ||
513      !window_state->CanSnap()) {
514    return false;
515  }
516
517  if (action == WINDOW_SNAP_LEFT) {
518    base::RecordAction(UserMetricsAction("Accel_Window_Snap_Left"));
519  } else {
520    base::RecordAction(UserMetricsAction("Accel_Window_Snap_Right"));
521  }
522  const wm::WMEvent event(action == WINDOW_SNAP_LEFT ?
523                          wm::WM_EVENT_SNAP_LEFT : wm::WM_EVENT_SNAP_RIGHT);
524  window_state->OnWMEvent(&event);
525  return true;
526}
527
528bool HandleWindowMinimize() {
529  base::RecordAction(
530      base::UserMetricsAction("Accel_Toggle_Minimized_Minus"));
531  return accelerators::ToggleMinimized();
532}
533
534#if defined(OS_CHROMEOS)
535bool HandleAddRemoveDisplay() {
536  base::RecordAction(UserMetricsAction("Accel_Add_Remove_Display"));
537  Shell::GetInstance()->display_manager()->AddRemoveDisplay();
538  return true;
539}
540
541bool HandleCrosh() {
542  base::RecordAction(UserMetricsAction("Accel_Open_Crosh"));
543
544  Shell::GetInstance()->new_window_delegate()->OpenCrosh();
545  return true;
546}
547
548bool HandleFileManager() {
549  base::RecordAction(UserMetricsAction("Accel_Open_File_Manager"));
550
551  Shell::GetInstance()->new_window_delegate()->OpenFileManager();
552  return true;
553}
554
555bool HandleLock(ui::KeyboardCode key_code) {
556  base::RecordAction(UserMetricsAction("Accel_LockScreen_L"));
557  Shell::GetInstance()->session_state_delegate()->LockScreen();
558  return true;
559}
560
561bool HandleCycleUser(SessionStateDelegate::CycleUser cycle_user) {
562  if (!Shell::GetInstance()->delegate()->IsMultiProfilesEnabled())
563    return false;
564  ash::SessionStateDelegate* delegate =
565      ash::Shell::GetInstance()->session_state_delegate();
566  if (delegate->NumberOfLoggedInUsers() <= 1)
567    return false;
568  MultiProfileUMA::RecordSwitchActiveUser(
569      MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR);
570  switch (cycle_user) {
571    case SessionStateDelegate::CYCLE_TO_NEXT_USER:
572      base::RecordAction(UserMetricsAction("Accel_Switch_To_Next_User"));
573      break;
574    case SessionStateDelegate::CYCLE_TO_PREVIOUS_USER:
575      base::RecordAction(UserMetricsAction("Accel_Switch_To_Previous_User"));
576      break;
577  }
578  delegate->CycleActiveUser(cycle_user);
579  return true;
580}
581
582bool HandleToggleMirrorMode() {
583  base::RecordAction(UserMetricsAction("Accel_Toggle_Mirror_Mode"));
584  Shell::GetInstance()->display_controller()->ToggleMirrorMode();
585  return true;
586}
587
588bool HandleToggleSpokenFeedback() {
589  base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback"));
590
591  Shell::GetInstance()->accessibility_delegate()->
592      ToggleSpokenFeedback(A11Y_NOTIFICATION_SHOW);
593  return true;
594}
595
596bool HandleToggleTouchViewTesting() {
597  // TODO(skuhne): This is only temporary! Remove this!
598  if (CommandLine::ForCurrentProcess()->HasSwitch(
599          switches::kAshEnableTouchViewTesting)) {
600    MaximizeModeController* controller = Shell::GetInstance()->
601        maximize_mode_controller();
602    controller->EnableMaximizeModeWindowManager(
603        !controller->IsMaximizeModeWindowManagerEnabled());
604    return true;
605  }
606  return false;
607}
608
609bool HandleTouchHudClear() {
610  RootWindowController* controller =
611      RootWindowController::ForTargetRootWindow();
612  if (controller->touch_hud_debug()) {
613    controller->touch_hud_debug()->Clear();
614    return true;
615  }
616  return false;
617}
618
619bool HandleTouchHudModeChange() {
620  RootWindowController* controller =
621      RootWindowController::ForTargetRootWindow();
622  if (controller->touch_hud_debug()) {
623    controller->touch_hud_debug()->ChangeToNextMode();
624    return true;
625  }
626  return false;
627}
628
629bool HandleTouchHudProjectToggle() {
630  base::RecordAction(UserMetricsAction("Accel_Touch_Hud_Clear"));
631  bool enabled = Shell::GetInstance()->is_touch_hud_projection_enabled();
632  Shell::GetInstance()->SetTouchHudProjectionEnabled(!enabled);
633  return true;
634}
635
636bool HandleDisableCapsLock(ui::KeyboardCode key_code,
637                           ui::EventType previous_event_type,
638                           ui::KeyboardCode previous_key_code) {
639  if (previous_event_type == ui::ET_KEY_RELEASED ||
640      (previous_key_code != ui::VKEY_LSHIFT &&
641       previous_key_code != ui::VKEY_SHIFT &&
642       previous_key_code != ui::VKEY_RSHIFT)) {
643    // If something else was pressed between the Shift key being pressed
644    // and released, then ignore the release of the Shift key.
645    return false;
646  }
647  base::RecordAction(UserMetricsAction("Accel_Disable_Caps_Lock"));
648  chromeos::input_method::InputMethodManager* ime =
649      chromeos::input_method::InputMethodManager::Get();
650  chromeos::input_method::ImeKeyboard* keyboard =
651      ime ? ime->GetImeKeyboard() : NULL;
652  if (keyboard && keyboard->CapsLockIsEnabled()) {
653    keyboard->SetCapsLockEnabled(false);
654    return true;
655  }
656  return false;
657}
658
659bool HandleToggleCapsLock(ui::KeyboardCode key_code,
660                          ui::EventType previous_event_type,
661                          ui::KeyboardCode previous_key_code) {
662  if (key_code == ui::VKEY_LWIN) {
663    // If something else was pressed between the Search key (LWIN)
664    // being pressed and released, then ignore the release of the
665    // Search key.
666    // TODO(danakj): Releasing Alt first breaks this: crbug.com/166495
667    if (previous_event_type == ui::ET_KEY_RELEASED ||
668        previous_key_code != ui::VKEY_LWIN)
669      return false;
670  }
671  base::RecordAction(UserMetricsAction("Accel_Toggle_Caps_Lock"));
672  chromeos::input_method::InputMethodManager* ime =
673      chromeos::input_method::InputMethodManager::Get();
674  chromeos::input_method::ImeKeyboard* keyboard =
675      ime ? ime->GetImeKeyboard() : NULL;
676  if (keyboard)
677    keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled());
678  return true;
679}
680
681#endif  // defined(OS_CHROMEOS)
682
683// Debug print methods.
684
685bool HandlePrintLayerHierarchy() {
686  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
687  for (size_t i = 0; i < root_windows.size(); ++i) {
688    ui::PrintLayerHierarchy(
689        root_windows[i]->layer(),
690        root_windows[i]->GetHost()->dispatcher()->GetLastMouseLocationInRoot());
691  }
692  return true;
693}
694
695bool HandlePrintViewHierarchy() {
696  aura::Window* active_window = ash::wm::GetActiveWindow();
697  if (!active_window)
698    return true;
699  views::Widget* browser_widget =
700      views::Widget::GetWidgetForNativeWindow(active_window);
701  if (!browser_widget)
702    return true;
703  views::PrintViewHierarchy(browser_widget->GetRootView());
704  return true;
705}
706
707void PrintWindowHierarchy(aura::Window* window,
708                          int indent,
709                          std::ostringstream* out) {
710  std::string indent_str(indent, ' ');
711  std::string name(window->name());
712  if (name.empty())
713    name = "\"\"";
714  *out << indent_str << name << " (" << window << ")"
715       << " type=" << window->type()
716       << (wm::IsActiveWindow(window) ? " [active] " : " ")
717       << (window->IsVisible() ? " visible " : " ")
718       << window->bounds().ToString()
719       << '\n';
720
721  for (size_t i = 0; i < window->children().size(); ++i)
722    PrintWindowHierarchy(window->children()[i], indent + 3, out);
723}
724
725bool HandlePrintWindowHierarchy() {
726  Shell::RootWindowControllerList controllers =
727      Shell::GetAllRootWindowControllers();
728  for (size_t i = 0; i < controllers.size(); ++i) {
729    std::ostringstream out;
730    out << "RootWindow " << i << ":\n";
731    PrintWindowHierarchy(controllers[i]->GetRootWindow(), 0, &out);
732    // Error so logs can be collected from end-users.
733    LOG(ERROR) << out.str();
734  }
735  return true;
736}
737
738bool HandlePrintUIHierarchies() {
739  // This is a separate command so the user only has to hit one key to generate
740  // all the logs. Developers use the individual dumps repeatedly, so keep
741  // those as separate commands to avoid spamming their logs.
742  HandlePrintLayerHierarchy();
743  HandlePrintWindowHierarchy();
744  HandlePrintViewHierarchy();
745  return true;
746}
747
748class AutoSet {
749 public:
750  AutoSet(ui::Accelerator* scoped, ui::Accelerator new_value)
751      : scoped_(scoped), new_value_(new_value) {}
752  ~AutoSet() { *scoped_ = new_value_; }
753
754 private:
755  ui::Accelerator* scoped_;
756  const ui::Accelerator new_value_;
757
758  DISALLOW_COPY_AND_ASSIGN(AutoSet);
759};
760
761}  // namespace
762
763////////////////////////////////////////////////////////////////////////////////
764// AcceleratorController, public:
765
766AcceleratorController::AcceleratorController()
767    : accelerator_manager_(new ui::AcceleratorManager) {
768  Init();
769}
770
771AcceleratorController::~AcceleratorController() {
772}
773
774void AcceleratorController::Init() {
775  previous_accelerator_.set_type(ui::ET_UNKNOWN);
776  for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) {
777    actions_allowed_at_login_screen_.insert(
778        kActionsAllowedAtLoginOrLockScreen[i]);
779    actions_allowed_at_lock_screen_.insert(
780        kActionsAllowedAtLoginOrLockScreen[i]);
781  }
782  for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i)
783    actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]);
784  for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i)
785    actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]);
786  for (size_t i = 0; i < kReservedActionsLength; ++i)
787    reserved_actions_.insert(kReservedActions[i]);
788  for (size_t i = 0; i < kNonrepeatableActionsLength; ++i)
789    nonrepeatable_actions_.insert(kNonrepeatableActions[i]);
790  for (size_t i = 0; i < kActionsAllowedInAppModeLength; ++i)
791    actions_allowed_in_app_mode_.insert(kActionsAllowedInAppMode[i]);
792  for (size_t i = 0; i < kActionsNeedingWindowLength; ++i)
793    actions_needing_window_.insert(kActionsNeedingWindow[i]);
794
795  RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength);
796
797#if !defined(NDEBUG)
798  RegisterAccelerators(kDesktopAcceleratorData, kDesktopAcceleratorDataLength);
799#endif
800
801  if (DebugShortcutsEnabled()) {
802    RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength);
803    for (size_t i = 0; i < kReservedDebugActionsLength; ++i)
804      reserved_actions_.insert(kReservedDebugActions[i]);
805  }
806
807#if defined(OS_CHROMEOS)
808  keyboard_brightness_control_delegate_.reset(
809      new KeyboardBrightnessController());
810#endif
811}
812
813void AcceleratorController::Register(const ui::Accelerator& accelerator,
814                                     ui::AcceleratorTarget* target) {
815  accelerator_manager_->Register(accelerator,
816                                 ui::AcceleratorManager::kNormalPriority,
817                                 target);
818}
819
820void AcceleratorController::Unregister(const ui::Accelerator& accelerator,
821                                       ui::AcceleratorTarget* target) {
822  accelerator_manager_->Unregister(accelerator, target);
823}
824
825void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) {
826  accelerator_manager_->UnregisterAll(target);
827}
828
829bool AcceleratorController::Process(const ui::Accelerator& accelerator) {
830  AutoSet auto_set(&previous_accelerator_, accelerator);
831
832  if (ime_control_delegate_) {
833    return accelerator_manager_->Process(
834        ime_control_delegate_->RemapAccelerator(accelerator));
835  }
836  return accelerator_manager_->Process(accelerator);
837}
838
839bool AcceleratorController::IsRegistered(
840    const ui::Accelerator& accelerator) const {
841  return accelerator_manager_->GetCurrentTarget(accelerator) != NULL;
842}
843
844bool AcceleratorController::IsReservedAccelerator(
845    const ui::Accelerator& accelerator) const {
846  const ui::Accelerator remapped_accelerator = ime_control_delegate_.get() ?
847      ime_control_delegate_->RemapAccelerator(accelerator) : accelerator;
848
849  std::map<ui::Accelerator, int>::const_iterator iter =
850      accelerators_.find(remapped_accelerator);
851  if (iter == accelerators_.end())
852    return false;  // not an accelerator.
853
854  return reserved_actions_.find(iter->second) != reserved_actions_.end();
855}
856
857bool AcceleratorController::PerformAction(int action,
858                                          const ui::Accelerator& accelerator) {
859  ash::Shell* shell = ash::Shell::GetInstance();
860  if (!shell->session_state_delegate()->IsActiveUserSessionStarted() &&
861      actions_allowed_at_login_screen_.find(action) ==
862      actions_allowed_at_login_screen_.end()) {
863    return false;
864  }
865  if (shell->session_state_delegate()->IsScreenLocked() &&
866      actions_allowed_at_lock_screen_.find(action) ==
867      actions_allowed_at_lock_screen_.end()) {
868    return false;
869  }
870  if (shell->IsSystemModalWindowOpen() &&
871      actions_allowed_at_modal_window_.find(action) ==
872      actions_allowed_at_modal_window_.end()) {
873    // Note: we return true. This indicates the shortcut is handled
874    // and will not be passed to the modal window. This is important
875    // for things like Alt+Tab that would cause an undesired effect
876    // in the modal window by cycling through its window elements.
877    return true;
878  }
879  if (shell->delegate()->IsRunningInForcedAppMode() &&
880      actions_allowed_in_app_mode_.find(action) ==
881      actions_allowed_in_app_mode_.end()) {
882    return false;
883  }
884  if (MruWindowTracker::BuildWindowList(false).empty() &&
885      actions_needing_window_.find(action) != actions_needing_window_.end()) {
886    Shell::GetInstance()->accessibility_delegate()->TriggerAccessibilityAlert(
887        A11Y_ALERT_WINDOW_NEEDED);
888    return true;
889  }
890
891  const ui::KeyboardCode key_code = accelerator.key_code();
892  // PerformAction() is performed from gesture controllers and passes
893  // empty Accelerator() instance as the second argument. Such events
894  // should never be suspended.
895  const bool gesture_event = key_code == ui::VKEY_UNKNOWN;
896  // Ignore accelerators invoked as repeated (while holding a key for a long
897  // time, if their handling is nonrepeatable.
898  if (nonrepeatable_actions_.find(action) != nonrepeatable_actions_.end() &&
899      accelerator.IsRepeat() && !gesture_event) {
900    return true;
901  }
902  // Type of the previous accelerator. Used by NEXT_IME and DISABLE_CAPS_LOCK.
903  const ui::EventType previous_event_type = previous_accelerator_.type();
904  const ui::KeyboardCode previous_key_code = previous_accelerator_.key_code();
905
906  // You *MUST* return true when some action is performed. Otherwise, this
907  // function might be called *twice*, via BrowserView::PreHandleKeyboardEvent
908  // and BrowserView::HandleKeyboardEvent, for a single accelerator press.
909  //
910  // If your accelerator invokes more than one line of code, please either
911  // implement it in your module's controller code (like TOGGLE_MIRROR_MODE
912  // below) or pull it into a HandleFoo() function above.
913  switch (action) {
914    case ACCESSIBLE_FOCUS_NEXT:
915      return HandleAccessibleFocusCycle(false);
916    case ACCESSIBLE_FOCUS_PREVIOUS:
917      return HandleAccessibleFocusCycle(true);
918    case CYCLE_BACKWARD_MRU:
919      return HandleCycleBackwardMRU(accelerator);
920    case CYCLE_FORWARD_MRU:
921      return HandleCycleForwardMRU(accelerator);
922    case TOGGLE_OVERVIEW:
923      return ToggleOverview(accelerator);
924#if defined(OS_CHROMEOS)
925    case ADD_REMOVE_DISPLAY:
926      return HandleAddRemoveDisplay();
927    case TOGGLE_MIRROR_MODE:
928      return HandleToggleMirrorMode();
929    case LOCK_SCREEN:
930      return HandleLock(key_code);
931    case OPEN_FILE_MANAGER:
932      return HandleFileManager();
933    case OPEN_CROSH:
934      return HandleCrosh();
935    case SILENCE_SPOKEN_FEEDBACK:
936      HandleSilenceSpokenFeedback();
937      break;
938    case SWAP_PRIMARY_DISPLAY:
939      return HandleSwapPrimaryDisplay();
940    case SWITCH_TO_NEXT_USER:
941      return HandleCycleUser(SessionStateDelegate::CYCLE_TO_NEXT_USER);
942    case SWITCH_TO_PREVIOUS_USER:
943      return HandleCycleUser(SessionStateDelegate::CYCLE_TO_PREVIOUS_USER);
944    case TOGGLE_SPOKEN_FEEDBACK:
945      return HandleToggleSpokenFeedback();
946    case TOGGLE_TOUCH_VIEW_TESTING:
947      return HandleToggleTouchViewTesting();
948    case TOGGLE_WIFI:
949      Shell::GetInstance()->system_tray_notifier()->NotifyRequestToggleWifi();
950      return true;
951    case TOUCH_HUD_CLEAR:
952      return HandleTouchHudClear();
953    case TOUCH_HUD_MODE_CHANGE:
954      return HandleTouchHudModeChange();
955    case TOUCH_HUD_PROJECTION_TOGGLE:
956      return HandleTouchHudProjectToggle();
957    case DISABLE_GPU_WATCHDOG:
958      Shell::GetInstance()->gpu_support()->DisableGpuWatchdog();
959      return true;
960    case DISABLE_CAPS_LOCK:
961      return HandleDisableCapsLock(
962          key_code, previous_event_type, previous_key_code);
963    case TOGGLE_CAPS_LOCK:
964      return HandleToggleCapsLock(
965          key_code, previous_event_type, previous_key_code);
966#endif  // OS_CHROMEOS
967    case OPEN_FEEDBACK_PAGE:
968      return HandleOpenFeedbackPage();
969    case EXIT:
970      // UMA metrics are recorded in the handler.
971      exit_warning_handler_.HandleAccelerator();
972      return true;
973    case NEW_INCOGNITO_WINDOW:
974      return HandleNewIncognitoWindow();
975    case NEW_TAB:
976      return HandleNewTab(key_code);
977    case NEW_WINDOW:
978      return HandleNewWindow();
979    case RESTORE_TAB:
980      return HandleRestoreTab();
981    case TAKE_SCREENSHOT:
982      return HandleTakeScreenshot(screenshot_delegate_.get());
983    case TAKE_PARTIAL_SCREENSHOT:
984      return HandleTakePartialScreenshot(screenshot_delegate_.get());
985    case TOGGLE_APP_LIST:
986      return HandleToggleAppList(
987          key_code, previous_event_type, previous_key_code, accelerator);
988    case BRIGHTNESS_DOWN:
989      if (brightness_control_delegate_)
990        return brightness_control_delegate_->HandleBrightnessDown(accelerator);
991      break;
992    case BRIGHTNESS_UP:
993      if (brightness_control_delegate_)
994        return brightness_control_delegate_->HandleBrightnessUp(accelerator);
995      break;
996    case KEYBOARD_BRIGHTNESS_DOWN:
997      if (keyboard_brightness_control_delegate_)
998        return keyboard_brightness_control_delegate_->
999            HandleKeyboardBrightnessDown(accelerator);
1000      break;
1001    case KEYBOARD_BRIGHTNESS_UP:
1002      if (keyboard_brightness_control_delegate_)
1003        return keyboard_brightness_control_delegate_->
1004            HandleKeyboardBrightnessUp(accelerator);
1005      break;
1006    case VOLUME_MUTE: {
1007      ash::VolumeControlDelegate* volume_delegate =
1008          shell->system_tray_delegate()->GetVolumeControlDelegate();
1009      return volume_delegate && volume_delegate->HandleVolumeMute(accelerator);
1010    }
1011    case VOLUME_DOWN: {
1012      ash::VolumeControlDelegate* volume_delegate =
1013          shell->system_tray_delegate()->GetVolumeControlDelegate();
1014      return volume_delegate && volume_delegate->HandleVolumeDown(accelerator);
1015    }
1016    case VOLUME_UP: {
1017      ash::VolumeControlDelegate* volume_delegate =
1018          shell->system_tray_delegate()->GetVolumeControlDelegate();
1019      return volume_delegate && volume_delegate->HandleVolumeUp(accelerator);
1020    }
1021    case FOCUS_LAUNCHER:
1022      return HandleFocusLauncher();
1023    case FOCUS_NEXT_PANE:
1024      return HandleRotatePaneFocus(Shell::FORWARD);
1025    case FOCUS_PREVIOUS_PANE:
1026      return HandleRotatePaneFocus(Shell::BACKWARD);
1027    case SHOW_KEYBOARD_OVERLAY:
1028      return HandleShowKeyboardOverlay();
1029    case SHOW_SYSTEM_TRAY_BUBBLE:
1030      return HandleShowSystemTrayBubble();
1031    case SHOW_MESSAGE_CENTER_BUBBLE:
1032      HandleShowMessageCenterBubble();
1033      break;
1034    case SHOW_TASK_MANAGER:
1035      return HandleShowTaskManager();
1036    case NEXT_IME:
1037      return HandleNextIme(
1038          ime_control_delegate_.get(), previous_event_type, previous_key_code);
1039    case PREVIOUS_IME:
1040      return HandlePreviousIme(ime_control_delegate_.get(), accelerator);
1041    case PRINT_UI_HIERARCHIES:
1042      return HandlePrintUIHierarchies();
1043    case SWITCH_IME:
1044      return HandleSwitchIme(ime_control_delegate_.get(), accelerator);
1045    case LAUNCH_APP_0:
1046      return HandleLaunchAppN(0);
1047    case LAUNCH_APP_1:
1048      return HandleLaunchAppN(1);
1049    case LAUNCH_APP_2:
1050      return HandleLaunchAppN(2);
1051    case LAUNCH_APP_3:
1052      return HandleLaunchAppN(3);
1053    case LAUNCH_APP_4:
1054      return HandleLaunchAppN(4);
1055    case LAUNCH_APP_5:
1056      return HandleLaunchAppN(5);
1057    case LAUNCH_APP_6:
1058      return HandleLaunchAppN(6);
1059    case LAUNCH_APP_7:
1060      return HandleLaunchAppN(7);
1061    case LAUNCH_LAST_APP:
1062      return HandleLaunchLastApp();
1063    case WINDOW_SNAP_LEFT:
1064    case WINDOW_SNAP_RIGHT:
1065      return HandleWindowSnap(action);
1066    case WINDOW_MINIMIZE:
1067      return HandleWindowMinimize();
1068    case TOGGLE_FULLSCREEN:
1069      return HandleToggleFullscreen(key_code);
1070    case TOGGLE_MAXIMIZED:
1071      accelerators::ToggleMaximized();
1072      return true;
1073    case WINDOW_POSITION_CENTER:
1074     return HandlePositionCenter();
1075    case SCALE_UI_UP:
1076      return HandleScaleUI(true /* up */);
1077    case SCALE_UI_DOWN:
1078      return HandleScaleUI(false /* down */);
1079    case SCALE_UI_RESET:
1080      return HandleScaleReset();
1081    case ROTATE_WINDOW:
1082      return HandleRotateActiveWindow();
1083    case ROTATE_SCREEN:
1084      return HandleRotateScreen();
1085    case TOGGLE_DESKTOP_BACKGROUND_MODE:
1086      return debug::CycleDesktopBackgroundMode();
1087    case TOGGLE_ROOT_WINDOW_FULL_SCREEN:
1088      return HandleToggleRootWindowFullScreen();
1089    case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR:
1090      Shell::GetInstance()->display_manager()->ToggleDisplayScaleFactor();
1091      return true;
1092    case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS:
1093      ash::debug::ToggleShowDebugBorders();
1094      return true;
1095    case DEBUG_TOGGLE_SHOW_FPS_COUNTER:
1096      ash::debug::ToggleShowFpsCounter();
1097      return true;
1098    case DEBUG_TOGGLE_SHOW_PAINT_RECTS:
1099      ash::debug::ToggleShowPaintRects();
1100      return true;
1101    case MAGNIFY_SCREEN_ZOOM_IN:
1102      return HandleMagnifyScreen(1);
1103    case MAGNIFY_SCREEN_ZOOM_OUT:
1104      return HandleMagnifyScreen(-1);
1105    case MEDIA_NEXT_TRACK:
1106      return HandleMediaNextTrack();
1107    case MEDIA_PLAY_PAUSE:
1108       return HandleMediaPlayPause();
1109    case MEDIA_PREV_TRACK:
1110       return HandleMediaPrevTrack();
1111    case POWER_PRESSED:  // fallthrough
1112    case POWER_RELEASED:
1113#if defined(OS_CHROMEOS)
1114      if (!base::SysInfo::IsRunningOnChromeOS()) {
1115        // There is no powerd in linux desktop, so call the
1116        // PowerButtonController here.
1117        Shell::GetInstance()->power_button_controller()->
1118            OnPowerButtonEvent(action == POWER_PRESSED, base::TimeTicks());
1119      }
1120#endif
1121      // We don't do anything with these at present on the device,
1122      // (power button events are reported to us from powerm via
1123      // D-BUS), but we consume them to prevent them from getting
1124      // passed to apps -- see http://crbug.com/146609.
1125      return true;
1126    case LOCK_PRESSED:
1127    case LOCK_RELEASED:
1128      Shell::GetInstance()->power_button_controller()->
1129          OnLockButtonEvent(action == LOCK_PRESSED, base::TimeTicks());
1130      return true;
1131    case PRINT_LAYER_HIERARCHY:
1132      return HandlePrintLayerHierarchy();
1133    case PRINT_VIEW_HIERARCHY:
1134      return HandlePrintViewHierarchy();
1135    case PRINT_WINDOW_HIERARCHY:
1136      return HandlePrintWindowHierarchy();
1137    default:
1138      NOTREACHED() << "Unhandled action " << action;
1139  }
1140  return false;
1141}
1142
1143void AcceleratorController::SetBrightnessControlDelegate(
1144    scoped_ptr<BrightnessControlDelegate> brightness_control_delegate) {
1145  brightness_control_delegate_ = brightness_control_delegate.Pass();
1146}
1147
1148void AcceleratorController::SetImeControlDelegate(
1149    scoped_ptr<ImeControlDelegate> ime_control_delegate) {
1150  ime_control_delegate_ = ime_control_delegate.Pass();
1151}
1152
1153void AcceleratorController::SetScreenshotDelegate(
1154    scoped_ptr<ScreenshotDelegate> screenshot_delegate) {
1155  screenshot_delegate_ = screenshot_delegate.Pass();
1156}
1157
1158////////////////////////////////////////////////////////////////////////////////
1159// AcceleratorController, ui::AcceleratorTarget implementation:
1160
1161bool AcceleratorController::AcceleratorPressed(
1162    const ui::Accelerator& accelerator) {
1163  std::map<ui::Accelerator, int>::const_iterator it =
1164      accelerators_.find(accelerator);
1165  DCHECK(it != accelerators_.end());
1166  return PerformAction(static_cast<AcceleratorAction>(it->second), accelerator);
1167}
1168
1169void AcceleratorController::RegisterAccelerators(
1170    const AcceleratorData accelerators[],
1171    size_t accelerators_length) {
1172  for (size_t i = 0; i < accelerators_length; ++i) {
1173    ui::Accelerator accelerator(accelerators[i].keycode,
1174                                accelerators[i].modifiers);
1175    accelerator.set_type(accelerators[i].trigger_on_press ?
1176                         ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED);
1177    Register(accelerator, this);
1178    accelerators_.insert(
1179        std::make_pair(accelerator, accelerators[i].action));
1180  }
1181}
1182
1183void AcceleratorController::SetKeyboardBrightnessControlDelegate(
1184    scoped_ptr<KeyboardBrightnessControlDelegate>
1185    keyboard_brightness_control_delegate) {
1186  keyboard_brightness_control_delegate_ =
1187      keyboard_brightness_control_delegate.Pass();
1188}
1189
1190bool AcceleratorController::CanHandleAccelerators() const {
1191  return true;
1192}
1193
1194}  // namespace ash
1195