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.
5 #include "ash/accelerators/accelerator_controller.h"
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/ime_control_delegate.h"
21 #include "ash/magnifier/magnification_controller.h"
22 #include "ash/magnifier/partial_magnification_controller.h"
23 #include "ash/media_delegate.h"
24 #include "ash/multi_profile_uma.h"
25 #include "ash/new_window_delegate.h"
26 #include "ash/root_window_controller.h"
27 #include "ash/rotator/screen_rotation.h"
28 #include "ash/screenshot_delegate.h"
29 #include "ash/session/session_state_delegate.h"
30 #include "ash/shelf/shelf.h"
31 #include "ash/shelf/shelf_delegate.h"
32 #include "ash/shelf/shelf_model.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/maximize_mode/maximize_mode_controller.h"
47 #include "ash/wm/mru_window_tracker.h"
48 #include "ash/wm/overview/window_selector_controller.h"
49 #include "ash/wm/partial_screenshot_view.h"
50 #include "ash/wm/power_button_controller.h"
51 #include "ash/wm/window_cycle_controller.h"
52 #include "ash/wm/window_state.h"
53 #include "ash/wm/window_util.h"
54 #include "ash/wm/wm_event.h"
55 #include "base/bind.h"
56 #include "base/command_line.h"
57 #include "base/metrics/user_metrics.h"
58 #include "ui/aura/env.h"
59 #include "ui/base/accelerators/accelerator.h"
60 #include "ui/base/accelerators/accelerator_manager.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/views/controls/webview/webview.h"
69 #if defined(OS_CHROMEOS)
70 #include "ash/system/chromeos/keyboard_brightness_controller.h"
71 #include "base/sys_info.h"
72 #include "chromeos/ime/ime_keyboard.h"
73 #include "chromeos/ime/input_method_manager.h"
74 #endif // defined(OS_CHROMEOS)
79 using base::UserMetricsAction;
81 bool HandleAccessibleFocusCycle(bool reverse) {
83 base::RecordAction(UserMetricsAction("Accel_Accessible_Focus_Previous"));
85 base::RecordAction(UserMetricsAction("Accel_Accessible_Focus_Next"));
88 if (!Shell::GetInstance()->accessibility_delegate()->
89 IsSpokenFeedbackEnabled()) {
92 aura::Window* active_window = ash::wm::GetActiveWindow();
95 views::Widget* widget =
96 views::Widget::GetWidgetForNativeWindow(active_window);
99 views::FocusManager* focus_manager = widget->GetFocusManager();
102 views::View* view = focus_manager->GetFocusedView();
105 if (!strcmp(view->GetClassName(), views::WebView::kViewClassName))
108 focus_manager->AdvanceFocus(reverse);
112 bool HandleCycleBackwardMRU(const ui::Accelerator& accelerator) {
113 if (accelerator.key_code() == ui::VKEY_TAB)
114 base::RecordAction(base::UserMetricsAction("Accel_PrevWindow_Tab"));
116 Shell::GetInstance()->window_cycle_controller()->HandleCycleWindow(
117 WindowCycleController::BACKWARD);
121 bool HandleCycleForwardMRU(const ui::Accelerator& accelerator) {
122 if (accelerator.key_code() == ui::VKEY_TAB)
123 base::RecordAction(base::UserMetricsAction("Accel_NextWindow_Tab"));
125 Shell::GetInstance()->window_cycle_controller()->HandleCycleWindow(
126 WindowCycleController::FORWARD);
130 bool ToggleOverview(const ui::Accelerator& accelerator) {
131 base::RecordAction(base::UserMetricsAction("Accel_Overview_F5"));
132 Shell::GetInstance()->window_selector_controller()->ToggleOverview();
136 bool HandleFocusShelf() {
137 Shell* shell = Shell::GetInstance();
138 base::RecordAction(base::UserMetricsAction("Accel_Focus_Shelf"));
139 return shell->focus_cycler()->FocusWidget(
140 Shelf::ForPrimaryDisplay()->shelf_widget());
143 bool HandleLaunchAppN(int n) {
144 base::RecordAction(UserMetricsAction("Accel_Launch_App"));
145 Shelf::ForPrimaryDisplay()->LaunchAppIndexAt(n);
149 bool HandleLaunchLastApp() {
150 base::RecordAction(UserMetricsAction("Accel_Launch_Last_App"));
151 Shelf::ForPrimaryDisplay()->LaunchAppIndexAt(-1);
155 // Magnify the screen
156 bool HandleMagnifyScreen(int delta_index) {
157 if (ash::Shell::GetInstance()->magnification_controller()->IsEnabled()) {
158 // TODO(yoshiki): Move the following logic to MagnificationController.
160 ash::Shell::GetInstance()->magnification_controller()->GetScale();
161 // Calculate rounded logarithm (base kMagnificationScaleFactor) of scale.
162 int scale_index = std::floor(
163 std::log(scale) / std::log(ui::kMagnificationScaleFactor) + 0.5);
165 int new_scale_index = std::max(0, std::min(8, scale_index + delta_index));
167 ash::Shell::GetInstance()->magnification_controller()->SetScale(
168 std::pow(ui::kMagnificationScaleFactor, new_scale_index), true);
170 } else if (ash::Shell::GetInstance()->
171 partial_magnification_controller()->is_enabled()) {
172 float scale = delta_index > 0 ? kDefaultPartialMagnifiedScale : 1;
173 ash::Shell::GetInstance()->partial_magnification_controller()->
180 bool HandleMediaNextTrack() {
181 Shell::GetInstance()->media_delegate()->HandleMediaNextTrack();
185 bool HandleMediaPlayPause() {
186 Shell::GetInstance()->media_delegate()->HandleMediaPlayPause();
190 bool HandleMediaPrevTrack() {
191 Shell::GetInstance()->media_delegate()->HandleMediaPrevTrack();
195 bool HandleNewIncognitoWindow() {
196 base::RecordAction(UserMetricsAction("Accel_New_Incognito_Window"));
197 bool incognito_allowed =
198 Shell::GetInstance()->delegate()->IsIncognitoAllowed();
199 if (incognito_allowed)
200 Shell::GetInstance()->new_window_delegate()->NewWindow(
201 true /* is_incognito */);
202 return incognito_allowed;
205 bool HandleNewTab(ui::KeyboardCode key_code) {
206 if (key_code == ui::VKEY_T)
207 base::RecordAction(base::UserMetricsAction("Accel_NewTab_T"));
208 Shell::GetInstance()->new_window_delegate()->NewTab();
212 bool HandleNewWindow() {
213 base::RecordAction(base::UserMetricsAction("Accel_New_Window"));
214 Shell::GetInstance()->new_window_delegate()->NewWindow(
215 false /* is_incognito */);
219 void HandleNextIme(ImeControlDelegate* ime_control_delegate,
220 ui::EventType previous_event_type,
221 ui::KeyboardCode previous_key_code) {
222 // This check is necessary e.g. not to process the Shift+Alt+
223 // ET_KEY_RELEASED accelerator for Chrome OS (see ash/accelerators/
224 // accelerator_controller.cc) when Shift+Alt+Tab is pressed and then Tab
226 if (previous_event_type == ui::ET_KEY_RELEASED &&
227 // Workaround for crbug.com/139556. CJK IME users tend to press
228 // Enter (or Space) and Shift+Alt almost at the same time to commit
229 // an IME string and then switch from the IME to the English layout.
230 // This workaround allows the user to trigger NEXT_IME even if the
231 // user presses Shift+Alt before releasing Enter.
232 // TODO(nona|mazda): Fix crbug.com/139556 in a cleaner way.
233 previous_key_code != ui::VKEY_RETURN &&
234 previous_key_code != ui::VKEY_SPACE) {
235 // We totally ignore this accelerator.
236 // TODO(mazda): Fix crbug.com/158217
239 base::RecordAction(UserMetricsAction("Accel_Next_Ime"));
240 if (ime_control_delegate)
241 ime_control_delegate->HandleNextIme();
244 bool HandleOpenFeedbackPage() {
245 base::RecordAction(UserMetricsAction("Accel_Open_Feedback_Page"));
246 ash::Shell::GetInstance()->new_window_delegate()->OpenFeedbackPage();
250 bool HandlePositionCenter() {
251 base::RecordAction(UserMetricsAction("Accel_Window_Position_Center"));
252 aura::Window* window = wm::GetActiveWindow();
253 // Docked windows do not support centering and ignore accelerator.
254 if (window && !wm::GetWindowState(window)->IsDocked()) {
255 wm::CenterWindow(window);
261 bool HandlePreviousIme(ImeControlDelegate* ime_control_delegate,
262 const ui::Accelerator& accelerator) {
263 base::RecordAction(UserMetricsAction("Accel_Previous_Ime"));
264 if (ime_control_delegate)
265 return ime_control_delegate->HandlePreviousIme(accelerator);
269 bool HandleRestoreTab() {
270 base::RecordAction(base::UserMetricsAction("Accel_Restore_Tab"));
271 Shell::GetInstance()->new_window_delegate()->RestoreTab();
275 bool HandleRotatePaneFocus(Shell::Direction direction) {
276 Shell* shell = Shell::GetInstance();
278 // TODO(stevet): Not sure if this is the same as IDC_FOCUS_NEXT_PANE.
279 case Shell::FORWARD: {
280 base::RecordAction(UserMetricsAction("Accel_Focus_Next_Pane"));
281 shell->focus_cycler()->RotateFocus(FocusCycler::FORWARD);
284 case Shell::BACKWARD: {
285 base::RecordAction(UserMetricsAction("Accel_Focus_Previous_Pane"));
286 shell->focus_cycler()->RotateFocus(FocusCycler::BACKWARD);
293 // Rotate the active window.
294 bool HandleRotateActiveWindow() {
295 base::RecordAction(UserMetricsAction("Accel_Rotate_Window"));
296 aura::Window* active_window = wm::GetActiveWindow();
298 // The rotation animation bases its target transform on the current
299 // rotation and position. Since there could be an animation in progress
300 // right now, queue this animation so when it starts it picks up a neutral
301 // rotation and position. Use replace so we only enqueue one at a time.
302 active_window->layer()->GetAnimator()->
303 set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
304 active_window->layer()->GetAnimator()->StartAnimation(
305 new ui::LayerAnimationSequence(
306 new ash::ScreenRotation(360, active_window->layer())));
311 gfx::Display::Rotation GetNextRotation(gfx::Display::Rotation current) {
313 case gfx::Display::ROTATE_0:
314 return gfx::Display::ROTATE_90;
315 case gfx::Display::ROTATE_90:
316 return gfx::Display::ROTATE_180;
317 case gfx::Display::ROTATE_180:
318 return gfx::Display::ROTATE_270;
319 case gfx::Display::ROTATE_270:
320 return gfx::Display::ROTATE_0;
322 NOTREACHED() << "Unknown rotation:" << current;
323 return gfx::Display::ROTATE_0;
326 // Rotates the screen.
327 bool HandleRotateScreen() {
328 base::RecordAction(UserMetricsAction("Accel_Rotate_Window"));
329 gfx::Point point = Shell::GetScreen()->GetCursorScreenPoint();
330 gfx::Display display = Shell::GetScreen()->GetDisplayNearestPoint(point);
331 const DisplayInfo& display_info =
332 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
333 Shell::GetInstance()->display_manager()->SetDisplayRotation(
334 display.id(), GetNextRotation(display_info.rotation()));
338 bool HandleScaleReset() {
339 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
340 int64 display_id = display_manager->GetDisplayIdForUIScaling();
341 if (display_id == gfx::Display::kInvalidDisplayID)
344 base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Reset"));
347 display_manager->GetDisplayInfo(display_id).configured_ui_scale();
348 if (ui_scale != 1.0f) {
349 display_manager->SetDisplayUIScale(display_id, 1.0f);
355 bool HandleScaleUI(bool up) {
356 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
357 int64 display_id = display_manager->GetDisplayIdForUIScaling();
358 if (display_id == gfx::Display::kInvalidDisplayID)
362 base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Up"));
364 base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Down"));
367 const DisplayInfo& display_info = display_manager->GetDisplayInfo(display_id);
368 float next_scale = DisplayManager::GetNextUIScale(display_info, up);
369 display_manager->SetDisplayUIScale(display_id, next_scale);
373 #if defined(OS_CHROMEOS)
374 bool HandleSwapPrimaryDisplay() {
375 base::RecordAction(UserMetricsAction("Accel_Swap_Primary_Display"));
376 Shell::GetInstance()->display_controller()->SwapPrimaryDisplay();
381 bool HandleShowKeyboardOverlay() {
382 base::RecordAction(UserMetricsAction("Accel_Show_Keyboard_Overlay"));
383 ash::Shell::GetInstance()->new_window_delegate()->ShowKeyboardOverlay();
388 bool HandleShowMessageCenterBubble() {
389 base::RecordAction(UserMetricsAction("Accel_Show_Message_Center_Bubble"));
390 RootWindowController* controller =
391 RootWindowController::ForTargetRootWindow();
392 StatusAreaWidget* status_area_widget =
393 controller->shelf()->status_area_widget();
394 if (status_area_widget) {
395 WebNotificationTray* notification_tray =
396 status_area_widget->web_notification_tray();
397 if (notification_tray->visible()) {
398 notification_tray->ShowMessageCenterBubble();
405 bool HandleShowSystemTrayBubble() {
406 base::RecordAction(UserMetricsAction("Accel_Show_System_Tray_Bubble"));
407 RootWindowController* controller =
408 RootWindowController::ForTargetRootWindow();
409 if (!controller->GetSystemTray()->HasSystemBubble()) {
410 controller->GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW);
416 bool HandleShowTaskManager() {
417 base::RecordAction(UserMetricsAction("Accel_Show_Task_Manager"));
418 Shell::GetInstance()->new_window_delegate()->ShowTaskManager();
422 #if defined(OS_CHROMEOS)
423 void HandleSilenceSpokenFeedback() {
424 base::RecordAction(UserMetricsAction("Accel_Silence_Spoken_Feedback"));
426 AccessibilityDelegate* delegate =
427 Shell::GetInstance()->accessibility_delegate();
428 if (!delegate->IsSpokenFeedbackEnabled())
430 delegate->SilenceSpokenFeedback();
434 bool HandleSwitchIme(ImeControlDelegate* ime_control_delegate,
435 const ui::Accelerator& accelerator) {
436 base::RecordAction(UserMetricsAction("Accel_Switch_Ime"));
437 if (ime_control_delegate)
438 return ime_control_delegate->HandleSwitchIme(accelerator);
442 bool HandleTakePartialScreenshot(ScreenshotDelegate* screenshot_delegate) {
443 base::RecordAction(UserMetricsAction("Accel_Take_Partial_Screenshot"));
444 if (screenshot_delegate) {
445 ash::PartialScreenshotView::StartPartialScreenshot(
446 screenshot_delegate);
448 // Return true to prevent propagation of the key event because
449 // this key combination is reserved for partial screenshot.
453 bool HandleTakeScreenshot(ScreenshotDelegate* screenshot_delegate) {
454 base::RecordAction(UserMetricsAction("Accel_Take_Screenshot"));
455 if (screenshot_delegate &&
456 screenshot_delegate->CanTakeScreenshot()) {
457 screenshot_delegate->HandleTakeScreenshotForAllRootWindows();
459 // Return true to prevent propagation of the key event.
463 bool HandleToggleAppList(ui::KeyboardCode key_code,
464 ui::EventType previous_event_type,
465 ui::KeyboardCode previous_key_code,
466 const ui::Accelerator& accelerator) {
467 // If something else was pressed between the Search key (LWIN)
468 // being pressed and released, then ignore the release of the
470 if (key_code == ui::VKEY_LWIN &&
471 (previous_event_type == ui::ET_KEY_RELEASED ||
472 previous_key_code != ui::VKEY_LWIN))
474 if (key_code == ui::VKEY_LWIN)
475 base::RecordAction(base::UserMetricsAction("Accel_Search_LWin"));
476 // When spoken feedback is enabled, we should neither toggle the list nor
477 // consume the key since Search+Shift is one of the shortcuts the a11y
478 // feature uses. crbug.com/132296
479 DCHECK_EQ(ui::VKEY_LWIN, accelerator.key_code());
480 if (Shell::GetInstance()->accessibility_delegate()->
481 IsSpokenFeedbackEnabled())
483 ash::Shell::GetInstance()->ToggleAppList(NULL);
487 bool HandleToggleFullscreen(ui::KeyboardCode key_code) {
488 if (key_code == ui::VKEY_MEDIA_LAUNCH_APP2) {
489 base::RecordAction(UserMetricsAction("Accel_Fullscreen_F4"));
491 accelerators::ToggleFullscreen();
495 bool HandleWindowSnapOrDock(int action) {
496 wm::WindowState* window_state = wm::GetActiveWindowState();
497 // Disable window snapping shortcut key for full screen window due to
498 // http://crbug.com/135487.
500 (window_state->window()->type() != ui::wm::WINDOW_TYPE_NORMAL &&
501 window_state->window()->type() != ui::wm::WINDOW_TYPE_PANEL) ||
502 window_state->IsFullscreen()) {
506 if (action == WINDOW_CYCLE_SNAP_DOCK_LEFT)
507 base::RecordAction(UserMetricsAction("Accel_Window_Snap_Left"));
509 base::RecordAction(UserMetricsAction("Accel_Window_Snap_Right"));
511 const wm::WMEvent event(action == WINDOW_CYCLE_SNAP_DOCK_LEFT ?
512 wm::WM_EVENT_CYCLE_SNAP_DOCK_LEFT :
513 wm::WM_EVENT_CYCLE_SNAP_DOCK_RIGHT);
514 window_state->OnWMEvent(&event);
518 bool HandleWindowMinimize() {
520 base::UserMetricsAction("Accel_Toggle_Minimized_Minus"));
521 return accelerators::ToggleMinimized();
524 #if defined(OS_CHROMEOS)
526 base::RecordAction(UserMetricsAction("Accel_Open_Crosh"));
528 Shell::GetInstance()->new_window_delegate()->OpenCrosh();
532 bool HandleFileManager() {
533 base::RecordAction(UserMetricsAction("Accel_Open_File_Manager"));
535 Shell::GetInstance()->new_window_delegate()->OpenFileManager();
539 bool HandleLock(ui::KeyboardCode key_code) {
540 base::RecordAction(UserMetricsAction("Accel_LockScreen_L"));
541 Shell::GetInstance()->session_state_delegate()->LockScreen();
545 bool HandleCycleUser(SessionStateDelegate::CycleUser cycle_user) {
546 if (!Shell::GetInstance()->delegate()->IsMultiProfilesEnabled())
548 ash::SessionStateDelegate* delegate =
549 ash::Shell::GetInstance()->session_state_delegate();
550 if (delegate->NumberOfLoggedInUsers() <= 1)
552 MultiProfileUMA::RecordSwitchActiveUser(
553 MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR);
554 switch (cycle_user) {
555 case SessionStateDelegate::CYCLE_TO_NEXT_USER:
556 base::RecordAction(UserMetricsAction("Accel_Switch_To_Next_User"));
558 case SessionStateDelegate::CYCLE_TO_PREVIOUS_USER:
559 base::RecordAction(UserMetricsAction("Accel_Switch_To_Previous_User"));
562 delegate->CycleActiveUser(cycle_user);
566 bool HandleToggleMirrorMode() {
567 base::RecordAction(UserMetricsAction("Accel_Toggle_Mirror_Mode"));
568 Shell::GetInstance()->display_controller()->ToggleMirrorMode();
572 bool HandleToggleSpokenFeedback() {
573 base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback"));
575 Shell::GetInstance()->accessibility_delegate()->
576 ToggleSpokenFeedback(ui::A11Y_NOTIFICATION_SHOW);
580 bool HandleToggleTouchViewTesting() {
581 // TODO(skuhne): This is only temporary! Remove this!
582 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
583 switches::kAshEnableTouchViewTesting)) {
584 MaximizeModeController* controller = Shell::GetInstance()->
585 maximize_mode_controller();
586 controller->EnableMaximizeModeWindowManager(
587 !controller->IsMaximizeModeWindowManagerEnabled());
593 bool HandleTouchHudClear() {
594 RootWindowController* controller =
595 RootWindowController::ForTargetRootWindow();
596 if (controller->touch_hud_debug()) {
597 controller->touch_hud_debug()->Clear();
603 bool HandleTouchHudModeChange() {
604 RootWindowController* controller =
605 RootWindowController::ForTargetRootWindow();
606 if (controller->touch_hud_debug()) {
607 controller->touch_hud_debug()->ChangeToNextMode();
613 bool HandleDisableCapsLock(ui::KeyboardCode key_code,
614 ui::EventType previous_event_type,
615 ui::KeyboardCode previous_key_code) {
616 if (previous_event_type == ui::ET_KEY_RELEASED ||
617 (previous_key_code != ui::VKEY_LSHIFT &&
618 previous_key_code != ui::VKEY_SHIFT &&
619 previous_key_code != ui::VKEY_RSHIFT)) {
620 // If something else was pressed between the Shift key being pressed
621 // and released, then ignore the release of the Shift key.
624 base::RecordAction(UserMetricsAction("Accel_Disable_Caps_Lock"));
625 chromeos::input_method::InputMethodManager* ime =
626 chromeos::input_method::InputMethodManager::Get();
627 chromeos::input_method::ImeKeyboard* keyboard =
628 ime ? ime->GetImeKeyboard() : NULL;
629 if (keyboard && keyboard->CapsLockIsEnabled()) {
630 keyboard->SetCapsLockEnabled(false);
636 bool HandleToggleCapsLock(ui::KeyboardCode key_code,
637 ui::EventType previous_event_type,
638 ui::KeyboardCode previous_key_code) {
639 if (key_code == ui::VKEY_LWIN) {
640 // If something else was pressed between the Search key (LWIN)
641 // being pressed and released, then ignore the release of the
643 // TODO(danakj): Releasing Alt first breaks this: crbug.com/166495
644 if (previous_event_type == ui::ET_KEY_RELEASED ||
645 previous_key_code != ui::VKEY_LWIN)
648 base::RecordAction(UserMetricsAction("Accel_Toggle_Caps_Lock"));
649 chromeos::input_method::InputMethodManager* ime =
650 chromeos::input_method::InputMethodManager::Get();
651 chromeos::input_method::ImeKeyboard* keyboard =
652 ime ? ime->GetImeKeyboard() : NULL;
654 keyboard->SetCapsLockEnabled(!keyboard->CapsLockIsEnabled());
658 #endif // defined(OS_CHROMEOS)
662 AutoSet(ui::Accelerator* scoped, ui::Accelerator new_value)
663 : scoped_(scoped), new_value_(new_value) {}
664 ~AutoSet() { *scoped_ = new_value_; }
667 ui::Accelerator* scoped_;
668 const ui::Accelerator new_value_;
670 DISALLOW_COPY_AND_ASSIGN(AutoSet);
675 ////////////////////////////////////////////////////////////////////////////////
676 // AcceleratorController, public:
678 AcceleratorController::AcceleratorController()
679 : accelerator_manager_(new ui::AcceleratorManager) {
683 AcceleratorController::~AcceleratorController() {
686 void AcceleratorController::Init() {
687 previous_accelerator_.set_type(ui::ET_UNKNOWN);
688 for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) {
689 actions_allowed_at_login_screen_.insert(
690 kActionsAllowedAtLoginOrLockScreen[i]);
691 actions_allowed_at_lock_screen_.insert(
692 kActionsAllowedAtLoginOrLockScreen[i]);
694 for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i)
695 actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]);
696 for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i)
697 actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]);
698 for (size_t i = 0; i < kPreferredActionsLength; ++i)
699 preferred_actions_.insert(kPreferredActions[i]);
700 for (size_t i = 0; i < kReservedActionsLength; ++i)
701 reserved_actions_.insert(kReservedActions[i]);
702 for (size_t i = 0; i < kNonrepeatableActionsLength; ++i)
703 nonrepeatable_actions_.insert(kNonrepeatableActions[i]);
704 for (size_t i = 0; i < kActionsAllowedInAppModeLength; ++i)
705 actions_allowed_in_app_mode_.insert(kActionsAllowedInAppMode[i]);
706 for (size_t i = 0; i < kActionsNeedingWindowLength; ++i)
707 actions_needing_window_.insert(kActionsNeedingWindow[i]);
709 RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength);
711 if (debug::DebugAcceleratorsEnabled()) {
712 RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength);
713 // All debug accelerators are reserved.
714 for (size_t i = 0; i < kDebugAcceleratorDataLength; ++i)
715 reserved_actions_.insert(kDebugAcceleratorData[i].action);
718 #if defined(OS_CHROMEOS)
719 keyboard_brightness_control_delegate_.reset(
720 new KeyboardBrightnessController());
724 void AcceleratorController::Register(const ui::Accelerator& accelerator,
725 ui::AcceleratorTarget* target) {
726 accelerator_manager_->Register(accelerator,
727 ui::AcceleratorManager::kNormalPriority,
731 void AcceleratorController::Unregister(const ui::Accelerator& accelerator,
732 ui::AcceleratorTarget* target) {
733 accelerator_manager_->Unregister(accelerator, target);
736 void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) {
737 accelerator_manager_->UnregisterAll(target);
740 bool AcceleratorController::Process(const ui::Accelerator& accelerator) {
741 AutoSet auto_set(&previous_accelerator_, accelerator);
743 if (ime_control_delegate_) {
744 return accelerator_manager_->Process(
745 ime_control_delegate_->RemapAccelerator(accelerator));
747 return accelerator_manager_->Process(accelerator);
750 bool AcceleratorController::IsRegistered(
751 const ui::Accelerator& accelerator) const {
752 return accelerator_manager_->GetCurrentTarget(accelerator) != NULL;
755 bool AcceleratorController::IsPreferred(
756 const ui::Accelerator& accelerator) const {
757 const ui::Accelerator remapped_accelerator = ime_control_delegate_.get() ?
758 ime_control_delegate_->RemapAccelerator(accelerator) : accelerator;
760 std::map<ui::Accelerator, int>::const_iterator iter =
761 accelerators_.find(remapped_accelerator);
762 if (iter == accelerators_.end())
763 return false; // not an accelerator.
765 return preferred_actions_.find(iter->second) != preferred_actions_.end();
768 bool AcceleratorController::IsReserved(
769 const ui::Accelerator& accelerator) const {
770 const ui::Accelerator remapped_accelerator = ime_control_delegate_.get() ?
771 ime_control_delegate_->RemapAccelerator(accelerator) : accelerator;
773 std::map<ui::Accelerator, int>::const_iterator iter =
774 accelerators_.find(remapped_accelerator);
775 if (iter == accelerators_.end())
776 return false; // not an accelerator.
778 return reserved_actions_.find(iter->second) != reserved_actions_.end();
781 bool AcceleratorController::PerformAction(int action,
782 const ui::Accelerator& accelerator) {
783 ash::Shell* shell = ash::Shell::GetInstance();
784 AcceleratorProcessingRestriction restriction =
785 GetAcceleratorProcessingRestriction(action);
786 if (restriction != RESTRICTION_NONE)
787 return restriction == RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
789 const ui::KeyboardCode key_code = accelerator.key_code();
790 // PerformAction() is performed from gesture controllers and passes
791 // empty Accelerator() instance as the second argument. Such events
792 // should never be suspended.
793 const bool gesture_event = key_code == ui::VKEY_UNKNOWN;
794 // Ignore accelerators invoked as repeated (while holding a key for a long
795 // time, if their handling is nonrepeatable.
796 if (nonrepeatable_actions_.find(action) != nonrepeatable_actions_.end() &&
797 accelerator.IsRepeat() && !gesture_event) {
800 // Type of the previous accelerator. Used by NEXT_IME and DISABLE_CAPS_LOCK.
801 const ui::EventType previous_event_type = previous_accelerator_.type();
802 const ui::KeyboardCode previous_key_code = previous_accelerator_.key_code();
804 // You *MUST* return true when some action is performed. Otherwise, this
805 // function might be called *twice*, via BrowserView::PreHandleKeyboardEvent
806 // and BrowserView::HandleKeyboardEvent, for a single accelerator press.
808 // If your accelerator invokes more than one line of code, please either
809 // implement it in your module's controller code (like TOGGLE_MIRROR_MODE
810 // below) or pull it into a HandleFoo() function above.
812 case ACCESSIBLE_FOCUS_NEXT:
813 return HandleAccessibleFocusCycle(false);
814 case ACCESSIBLE_FOCUS_PREVIOUS:
815 return HandleAccessibleFocusCycle(true);
816 case CYCLE_BACKWARD_MRU:
817 return HandleCycleBackwardMRU(accelerator);
818 case CYCLE_FORWARD_MRU:
819 return HandleCycleForwardMRU(accelerator);
820 case TOGGLE_OVERVIEW:
821 return ToggleOverview(accelerator);
822 #if defined(OS_CHROMEOS)
823 case TOGGLE_MIRROR_MODE:
824 return HandleToggleMirrorMode();
826 return HandleLock(key_code);
827 case OPEN_FILE_MANAGER:
828 return HandleFileManager();
830 return HandleCrosh();
831 case SILENCE_SPOKEN_FEEDBACK:
832 HandleSilenceSpokenFeedback();
834 case SWAP_PRIMARY_DISPLAY:
835 return HandleSwapPrimaryDisplay();
836 case SWITCH_TO_NEXT_USER:
837 return HandleCycleUser(SessionStateDelegate::CYCLE_TO_NEXT_USER);
838 case SWITCH_TO_PREVIOUS_USER:
839 return HandleCycleUser(SessionStateDelegate::CYCLE_TO_PREVIOUS_USER);
840 case TOGGLE_SPOKEN_FEEDBACK:
841 return HandleToggleSpokenFeedback();
842 case TOGGLE_TOUCH_VIEW_TESTING:
843 return HandleToggleTouchViewTesting();
845 Shell::GetInstance()->system_tray_notifier()->NotifyRequestToggleWifi();
847 case TOUCH_HUD_CLEAR:
848 return HandleTouchHudClear();
849 case TOUCH_HUD_MODE_CHANGE:
850 return HandleTouchHudModeChange();
851 case TOUCH_HUD_PROJECTION_TOGGLE:
852 accelerators::ToggleTouchHudProjection();
854 case DISABLE_GPU_WATCHDOG:
855 Shell::GetInstance()->gpu_support()->DisableGpuWatchdog();
857 case DISABLE_CAPS_LOCK:
858 return HandleDisableCapsLock(
859 key_code, previous_event_type, previous_key_code);
860 case TOGGLE_CAPS_LOCK:
861 return HandleToggleCapsLock(
862 key_code, previous_event_type, previous_key_code);
863 #endif // OS_CHROMEOS
864 case OPEN_FEEDBACK_PAGE:
865 return HandleOpenFeedbackPage();
867 // UMA metrics are recorded in the handler.
868 exit_warning_handler_.HandleAccelerator();
870 case NEW_INCOGNITO_WINDOW:
871 return HandleNewIncognitoWindow();
873 return HandleNewTab(key_code);
875 return HandleNewWindow();
877 return HandleRestoreTab();
878 case TAKE_SCREENSHOT:
879 return HandleTakeScreenshot(screenshot_delegate_.get());
880 case TAKE_PARTIAL_SCREENSHOT:
881 return HandleTakePartialScreenshot(screenshot_delegate_.get());
882 case TOGGLE_APP_LIST:
883 return HandleToggleAppList(
884 key_code, previous_event_type, previous_key_code, accelerator);
885 case BRIGHTNESS_DOWN:
886 if (brightness_control_delegate_)
887 return brightness_control_delegate_->HandleBrightnessDown(accelerator);
890 if (brightness_control_delegate_)
891 return brightness_control_delegate_->HandleBrightnessUp(accelerator);
893 case KEYBOARD_BRIGHTNESS_DOWN:
894 if (keyboard_brightness_control_delegate_)
895 return keyboard_brightness_control_delegate_->
896 HandleKeyboardBrightnessDown(accelerator);
898 case KEYBOARD_BRIGHTNESS_UP:
899 if (keyboard_brightness_control_delegate_)
900 return keyboard_brightness_control_delegate_->
901 HandleKeyboardBrightnessUp(accelerator);
904 ash::VolumeControlDelegate* volume_delegate =
905 shell->system_tray_delegate()->GetVolumeControlDelegate();
906 return volume_delegate && volume_delegate->HandleVolumeMute(accelerator);
909 ash::VolumeControlDelegate* volume_delegate =
910 shell->system_tray_delegate()->GetVolumeControlDelegate();
911 return volume_delegate && volume_delegate->HandleVolumeDown(accelerator);
914 ash::VolumeControlDelegate* volume_delegate =
915 shell->system_tray_delegate()->GetVolumeControlDelegate();
916 return volume_delegate && volume_delegate->HandleVolumeUp(accelerator);
919 return HandleFocusShelf();
920 case FOCUS_NEXT_PANE:
921 return HandleRotatePaneFocus(Shell::FORWARD);
922 case FOCUS_PREVIOUS_PANE:
923 return HandleRotatePaneFocus(Shell::BACKWARD);
924 case SHOW_KEYBOARD_OVERLAY:
925 return HandleShowKeyboardOverlay();
926 case SHOW_SYSTEM_TRAY_BUBBLE:
927 return HandleShowSystemTrayBubble();
928 case SHOW_MESSAGE_CENTER_BUBBLE:
929 return HandleShowMessageCenterBubble();
930 case SHOW_TASK_MANAGER:
931 return HandleShowTaskManager();
934 ime_control_delegate_.get(), previous_event_type, previous_key_code);
935 // NEXT_IME is bound to Alt-Shift key up event. To be consistent with
936 // Windows behavior, do not consume the key event here.
939 return HandlePreviousIme(ime_control_delegate_.get(), accelerator);
940 case PRINT_UI_HIERARCHIES:
941 debug::PrintUIHierarchies();
944 return HandleSwitchIme(ime_control_delegate_.get(), accelerator);
946 return HandleLaunchAppN(0);
948 return HandleLaunchAppN(1);
950 return HandleLaunchAppN(2);
952 return HandleLaunchAppN(3);
954 return HandleLaunchAppN(4);
956 return HandleLaunchAppN(5);
958 return HandleLaunchAppN(6);
960 return HandleLaunchAppN(7);
961 case LAUNCH_LAST_APP:
962 return HandleLaunchLastApp();
963 case WINDOW_CYCLE_SNAP_DOCK_LEFT:
964 case WINDOW_CYCLE_SNAP_DOCK_RIGHT:
965 return HandleWindowSnapOrDock(action);
966 case WINDOW_MINIMIZE:
967 return HandleWindowMinimize();
968 case TOGGLE_FULLSCREEN:
969 return HandleToggleFullscreen(key_code);
970 case TOGGLE_MAXIMIZED:
971 accelerators::ToggleMaximized();
973 case WINDOW_POSITION_CENTER:
974 return HandlePositionCenter();
976 return HandleScaleUI(true /* up */);
978 return HandleScaleUI(false /* down */);
980 return HandleScaleReset();
982 return HandleRotateActiveWindow();
984 return HandleRotateScreen();
985 case MAGNIFY_SCREEN_ZOOM_IN:
986 return HandleMagnifyScreen(1);
987 case MAGNIFY_SCREEN_ZOOM_OUT:
988 return HandleMagnifyScreen(-1);
989 case MEDIA_NEXT_TRACK:
990 return HandleMediaNextTrack();
991 case MEDIA_PLAY_PAUSE:
992 return HandleMediaPlayPause();
993 case MEDIA_PREV_TRACK:
994 return HandleMediaPrevTrack();
995 case POWER_PRESSED: // fallthrough
997 #if defined(OS_CHROMEOS)
998 if (!base::SysInfo::IsRunningOnChromeOS()) {
999 // There is no powerd in linux desktop, so call the
1000 // PowerButtonController here.
1001 Shell::GetInstance()->power_button_controller()->
1002 OnPowerButtonEvent(action == POWER_PRESSED, base::TimeTicks());
1005 // We don't do anything with these at present on the device,
1006 // (power button events are reported to us from powerm via
1007 // D-BUS), but we consume them to prevent them from getting
1008 // passed to apps -- see http://crbug.com/146609.
1012 Shell::GetInstance()->power_button_controller()->
1013 OnLockButtonEvent(action == LOCK_PRESSED, base::TimeTicks());
1016 DCHECK(debug::DebugAcceleratorsEnabled())
1017 << "Unhandled action " << action;
1020 // If |action| is a debug action, run it.
1021 return debug::PerformDebugAction(action);
1024 AcceleratorController::AcceleratorProcessingRestriction
1025 AcceleratorController::GetCurrentAcceleratorRestriction() {
1026 return GetAcceleratorProcessingRestriction(-1);
1029 AcceleratorController::AcceleratorProcessingRestriction
1030 AcceleratorController::GetAcceleratorProcessingRestriction(int action) {
1031 ash::Shell* shell = ash::Shell::GetInstance();
1032 if (!shell->session_state_delegate()->IsActiveUserSessionStarted() &&
1033 actions_allowed_at_login_screen_.find(action) ==
1034 actions_allowed_at_login_screen_.end()) {
1035 return RESTRICTION_PREVENT_PROCESSING;
1037 if (shell->session_state_delegate()->IsScreenLocked() &&
1038 actions_allowed_at_lock_screen_.find(action) ==
1039 actions_allowed_at_lock_screen_.end()) {
1040 return RESTRICTION_PREVENT_PROCESSING;
1042 if (shell->IsSystemModalWindowOpen() &&
1043 actions_allowed_at_modal_window_.find(action) ==
1044 actions_allowed_at_modal_window_.end()) {
1045 // Note we prevent the shortcut from propagating so it will not
1046 // be passed to the modal window. This is important for things like
1047 // Alt+Tab that would cause an undesired effect in the modal window by
1048 // cycling through its window elements.
1049 return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
1051 if (shell->delegate()->IsRunningInForcedAppMode() &&
1052 actions_allowed_in_app_mode_.find(action) ==
1053 actions_allowed_in_app_mode_.end()) {
1054 return RESTRICTION_PREVENT_PROCESSING;
1056 if (MruWindowTracker::BuildWindowList(false).empty() &&
1057 actions_needing_window_.find(action) != actions_needing_window_.end()) {
1058 Shell::GetInstance()->accessibility_delegate()->TriggerAccessibilityAlert(
1059 ui::A11Y_ALERT_WINDOW_NEEDED);
1060 return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION;
1062 return RESTRICTION_NONE;
1065 void AcceleratorController::SetBrightnessControlDelegate(
1066 scoped_ptr<BrightnessControlDelegate> brightness_control_delegate) {
1067 brightness_control_delegate_ = brightness_control_delegate.Pass();
1070 void AcceleratorController::SetImeControlDelegate(
1071 scoped_ptr<ImeControlDelegate> ime_control_delegate) {
1072 ime_control_delegate_ = ime_control_delegate.Pass();
1075 void AcceleratorController::SetScreenshotDelegate(
1076 scoped_ptr<ScreenshotDelegate> screenshot_delegate) {
1077 screenshot_delegate_ = screenshot_delegate.Pass();
1080 ////////////////////////////////////////////////////////////////////////////////
1081 // AcceleratorController, ui::AcceleratorTarget implementation:
1083 bool AcceleratorController::AcceleratorPressed(
1084 const ui::Accelerator& accelerator) {
1085 std::map<ui::Accelerator, int>::const_iterator it =
1086 accelerators_.find(accelerator);
1087 DCHECK(it != accelerators_.end());
1088 return PerformAction(static_cast<AcceleratorAction>(it->second), accelerator);
1091 void AcceleratorController::RegisterAccelerators(
1092 const AcceleratorData accelerators[],
1093 size_t accelerators_length) {
1094 for (size_t i = 0; i < accelerators_length; ++i) {
1095 ui::Accelerator accelerator(accelerators[i].keycode,
1096 accelerators[i].modifiers);
1097 accelerator.set_type(accelerators[i].trigger_on_press ?
1098 ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED);
1099 Register(accelerator, this);
1100 accelerators_.insert(
1101 std::make_pair(accelerator, accelerators[i].action));
1105 void AcceleratorController::SetKeyboardBrightnessControlDelegate(
1106 scoped_ptr<KeyboardBrightnessControlDelegate>
1107 keyboard_brightness_control_delegate) {
1108 keyboard_brightness_control_delegate_ =
1109 keyboard_brightness_control_delegate.Pass();
1112 bool AcceleratorController::CanHandleAccelerators() const {