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/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"
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)
84 using base::UserMetricsAction
;
86 bool DebugShortcutsEnabled() {
88 return CommandLine::ForCurrentProcess()->HasSwitch(
89 switches::kAshDebugShortcuts
);
95 bool HandleAccessibleFocusCycle(bool reverse
) {
97 base::RecordAction(UserMetricsAction("Accel_Accessible_Focus_Previous"));
99 base::RecordAction(UserMetricsAction("Accel_Accessible_Focus_Next"));
102 if (!Shell::GetInstance()->accessibility_delegate()->
103 IsSpokenFeedbackEnabled()) {
106 aura::Window
* active_window
= ash::wm::GetActiveWindow();
109 views::Widget
* widget
=
110 views::Widget::GetWidgetForNativeWindow(active_window
);
113 views::FocusManager
* focus_manager
= widget
->GetFocusManager();
116 views::View
* view
= focus_manager
->GetFocusedView();
119 if (!strcmp(view
->GetClassName(), views::WebView::kViewClassName
))
122 focus_manager
->AdvanceFocus(reverse
);
126 bool HandleCycleBackwardMRU(const ui::Accelerator
& accelerator
) {
127 if (accelerator
.key_code() == ui::VKEY_TAB
)
128 base::RecordAction(base::UserMetricsAction("Accel_PrevWindow_Tab"));
130 Shell::GetInstance()->window_cycle_controller()->HandleCycleWindow(
131 WindowCycleController::BACKWARD
);
135 bool HandleCycleForwardMRU(const ui::Accelerator
& accelerator
) {
136 if (accelerator
.key_code() == ui::VKEY_TAB
)
137 base::RecordAction(base::UserMetricsAction("Accel_NextWindow_Tab"));
139 Shell::GetInstance()->window_cycle_controller()->HandleCycleWindow(
140 WindowCycleController::FORWARD
);
144 bool ToggleOverview(const ui::Accelerator
& accelerator
) {
145 base::RecordAction(base::UserMetricsAction("Accel_Overview_F5"));
146 Shell::GetInstance()->window_selector_controller()->ToggleOverview();
150 bool 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());
157 bool HandleLaunchAppN(int n
) {
158 base::RecordAction(UserMetricsAction("Accel_Launch_App"));
159 Shelf::ForPrimaryDisplay()->LaunchAppIndexAt(n
);
163 bool HandleLaunchLastApp() {
164 base::RecordAction(UserMetricsAction("Accel_Launch_Last_App"));
165 Shelf::ForPrimaryDisplay()->LaunchAppIndexAt(-1);
169 // Magnify the screen
170 bool HandleMagnifyScreen(int delta_index
) {
171 if (ash::Shell::GetInstance()->magnification_controller()->IsEnabled()) {
172 // TODO(yoshiki): Move the following logic to MagnificationController.
174 ash::Shell::GetInstance()->magnification_controller()->GetScale();
175 // Calculate rounded logarithm (base kMagnificationScaleFactor) of scale.
177 std::floor(std::log(scale
) / std::log(kMagnificationScaleFactor
) + 0.5);
179 int new_scale_index
= std::max(0, std::min(8, scale_index
+ delta_index
));
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()->
193 bool HandleMediaNextTrack() {
194 Shell::GetInstance()->media_delegate()->HandleMediaNextTrack();
198 bool HandleMediaPlayPause() {
199 Shell::GetInstance()->media_delegate()->HandleMediaPlayPause();
203 bool HandleMediaPrevTrack() {
204 Shell::GetInstance()->media_delegate()->HandleMediaPrevTrack();
208 bool 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
;
218 bool 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();
225 bool HandleNewWindow() {
226 base::RecordAction(base::UserMetricsAction("Accel_New_Window"));
227 Shell::GetInstance()->new_window_delegate()->NewWindow(
228 false /* is_incognito */);
232 void 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
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
252 base::RecordAction(UserMetricsAction("Accel_Next_Ime"));
253 if (ime_control_delegate
)
254 ime_control_delegate
->HandleNextIme();
257 bool HandleOpenFeedbackPage() {
258 base::RecordAction(UserMetricsAction("Accel_Open_Feedback_Page"));
259 ash::Shell::GetInstance()->new_window_delegate()->OpenFeedbackPage();
263 bool HandlePositionCenter() {
264 base::RecordAction(UserMetricsAction("Accel_Window_Position_Center"));
265 aura::Window
* window
= wm::GetActiveWindow();
266 // Docked windows do not support centering and ignore accelerator.
267 if (window
&& !wm::GetWindowState(window
)->IsDocked()) {
268 wm::CenterWindow(window
);
274 bool HandlePreviousIme(ImeControlDelegate
* ime_control_delegate
,
275 const ui::Accelerator
& accelerator
) {
276 base::RecordAction(UserMetricsAction("Accel_Previous_Ime"));
277 if (ime_control_delegate
)
278 return ime_control_delegate
->HandlePreviousIme(accelerator
);
282 bool HandleRestoreTab() {
283 base::RecordAction(base::UserMetricsAction("Accel_Restore_Tab"));
284 Shell::GetInstance()->new_window_delegate()->RestoreTab();
288 bool HandleRotatePaneFocus(Shell::Direction direction
) {
289 Shell
* shell
= Shell::GetInstance();
291 // TODO(stevet): Not sure if this is the same as IDC_FOCUS_NEXT_PANE.
292 case Shell::FORWARD
: {
293 base::RecordAction(UserMetricsAction("Accel_Focus_Next_Pane"));
294 shell
->focus_cycler()->RotateFocus(FocusCycler::FORWARD
);
297 case Shell::BACKWARD
: {
298 base::RecordAction(UserMetricsAction("Accel_Focus_Previous_Pane"));
299 shell
->focus_cycler()->RotateFocus(FocusCycler::BACKWARD
);
306 // Rotate the active window.
307 bool HandleRotateActiveWindow() {
308 base::RecordAction(UserMetricsAction("Accel_Rotate_Window"));
309 aura::Window
* active_window
= wm::GetActiveWindow();
311 // The rotation animation bases its target transform on the current
312 // rotation and position. Since there could be an animation in progress
313 // right now, queue this animation so when it starts it picks up a neutral
314 // rotation and position. Use replace so we only enqueue one at a time.
315 active_window
->layer()->GetAnimator()->
316 set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS
);
317 active_window
->layer()->GetAnimator()->StartAnimation(
318 new ui::LayerAnimationSequence(
319 new ash::ScreenRotation(360, active_window
->layer())));
324 gfx::Display::Rotation
GetNextRotation(gfx::Display::Rotation current
) {
326 case gfx::Display::ROTATE_0
:
327 return gfx::Display::ROTATE_90
;
328 case gfx::Display::ROTATE_90
:
329 return gfx::Display::ROTATE_180
;
330 case gfx::Display::ROTATE_180
:
331 return gfx::Display::ROTATE_270
;
332 case gfx::Display::ROTATE_270
:
333 return gfx::Display::ROTATE_0
;
335 NOTREACHED() << "Unknown rotation:" << current
;
336 return gfx::Display::ROTATE_0
;
339 // Rotates the screen.
340 bool HandleRotateScreen() {
341 base::RecordAction(UserMetricsAction("Accel_Rotate_Window"));
342 gfx::Point point
= Shell::GetScreen()->GetCursorScreenPoint();
343 gfx::Display display
= Shell::GetScreen()->GetDisplayNearestPoint(point
);
344 const DisplayInfo
& display_info
=
345 Shell::GetInstance()->display_manager()->GetDisplayInfo(display
.id());
346 Shell::GetInstance()->display_manager()->SetDisplayRotation(
347 display
.id(), GetNextRotation(display_info
.rotation()));
351 bool HandleScaleReset() {
352 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
353 int64 display_id
= display_manager
->GetDisplayIdForUIScaling();
354 if (display_id
== gfx::Display::kInvalidDisplayID
)
357 base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Reset"));
359 display_manager
->SetDisplayUIScale(display_id
, 1.0f
);
363 bool HandleScaleUI(bool up
) {
364 DisplayManager
* display_manager
= Shell::GetInstance()->display_manager();
365 int64 display_id
= display_manager
->GetDisplayIdForUIScaling();
366 if (display_id
== gfx::Display::kInvalidDisplayID
)
370 base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Up"));
372 base::RecordAction(UserMetricsAction("Accel_Scale_Ui_Down"));
375 const DisplayInfo
& display_info
= display_manager
->GetDisplayInfo(display_id
);
376 float next_scale
= DisplayManager::GetNextUIScale(display_info
, up
);
377 display_manager
->SetDisplayUIScale(display_id
, next_scale
);
381 #if defined(OS_CHROMEOS)
382 bool HandleSwapPrimaryDisplay() {
383 base::RecordAction(UserMetricsAction("Accel_Swap_Primary_Display"));
384 Shell::GetInstance()->display_controller()->SwapPrimaryDisplay();
389 bool HandleShowKeyboardOverlay() {
390 base::RecordAction(UserMetricsAction("Accel_Show_Keyboard_Overlay"));
391 ash::Shell::GetInstance()->new_window_delegate()->ShowKeyboardOverlay();
396 void HandleShowMessageCenterBubble() {
397 base::RecordAction(UserMetricsAction("Accel_Show_Message_Center_Bubble"));
398 RootWindowController
* controller
=
399 RootWindowController::ForTargetRootWindow();
400 StatusAreaWidget
* status_area_widget
=
401 controller
->shelf()->status_area_widget();
402 if (status_area_widget
) {
403 WebNotificationTray
* notification_tray
=
404 status_area_widget
->web_notification_tray();
405 if (notification_tray
->visible())
406 notification_tray
->ShowMessageCenterBubble();
410 bool HandleShowSystemTrayBubble() {
411 base::RecordAction(UserMetricsAction("Accel_Show_System_Tray_Bubble"));
412 RootWindowController
* controller
=
413 RootWindowController::ForTargetRootWindow();
414 if (!controller
->GetSystemTray()->HasSystemBubble()) {
415 controller
->GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW
);
421 bool HandleShowTaskManager() {
422 base::RecordAction(UserMetricsAction("Accel_Show_Task_Manager"));
423 Shell::GetInstance()->new_window_delegate()->ShowTaskManager();
427 #if defined(OS_CHROMEOS)
428 void HandleSilenceSpokenFeedback() {
429 base::RecordAction(UserMetricsAction("Accel_Silence_Spoken_Feedback"));
431 AccessibilityDelegate
* delegate
=
432 Shell::GetInstance()->accessibility_delegate();
433 if (!delegate
->IsSpokenFeedbackEnabled())
435 delegate
->SilenceSpokenFeedback();
439 bool HandleSwitchIme(ImeControlDelegate
* ime_control_delegate
,
440 const ui::Accelerator
& accelerator
) {
441 base::RecordAction(UserMetricsAction("Accel_Switch_Ime"));
442 if (ime_control_delegate
)
443 return ime_control_delegate
->HandleSwitchIme(accelerator
);
447 bool HandleTakePartialScreenshot(ScreenshotDelegate
* screenshot_delegate
) {
448 base::RecordAction(UserMetricsAction("Accel_Take_Partial_Screenshot"));
449 if (screenshot_delegate
) {
450 ash::PartialScreenshotView::StartPartialScreenshot(
451 screenshot_delegate
);
453 // Return true to prevent propagation of the key event because
454 // this key combination is reserved for partial screenshot.
458 bool HandleTakeScreenshot(ScreenshotDelegate
* screenshot_delegate
) {
459 base::RecordAction(UserMetricsAction("Accel_Take_Screenshot"));
460 if (screenshot_delegate
&&
461 screenshot_delegate
->CanTakeScreenshot()) {
462 screenshot_delegate
->HandleTakeScreenshotForAllRootWindows();
464 // Return true to prevent propagation of the key event.
468 bool HandleToggleAppList(ui::KeyboardCode key_code
,
469 ui::EventType previous_event_type
,
470 ui::KeyboardCode previous_key_code
,
471 const ui::Accelerator
& accelerator
) {
472 // If something else was pressed between the Search key (LWIN)
473 // being pressed and released, then ignore the release of the
475 if (key_code
== ui::VKEY_LWIN
&&
476 (previous_event_type
== ui::ET_KEY_RELEASED
||
477 previous_key_code
!= ui::VKEY_LWIN
))
479 if (key_code
== ui::VKEY_LWIN
)
480 base::RecordAction(base::UserMetricsAction("Accel_Search_LWin"));
481 // When spoken feedback is enabled, we should neither toggle the list nor
482 // consume the key since Search+Shift is one of the shortcuts the a11y
483 // feature uses. crbug.com/132296
484 DCHECK_EQ(ui::VKEY_LWIN
, accelerator
.key_code());
485 if (Shell::GetInstance()->accessibility_delegate()->
486 IsSpokenFeedbackEnabled())
488 ash::Shell::GetInstance()->ToggleAppList(NULL
);
492 bool HandleToggleFullscreen(ui::KeyboardCode key_code
) {
493 if (key_code
== ui::VKEY_MEDIA_LAUNCH_APP2
) {
494 base::RecordAction(UserMetricsAction("Accel_Fullscreen_F4"));
496 accelerators::ToggleFullscreen();
500 bool HandleToggleRootWindowFullScreen() {
501 Shell::GetPrimaryRootWindowController()->ash_host()->ToggleFullScreen();
505 bool HandleWindowSnap(int action
) {
506 wm::WindowState
* window_state
= wm::GetActiveWindowState();
507 // Disable window snapping shortcut key for full screen window due to
508 // http://crbug.com/135487.
510 window_state
->window()->type() != ui::wm::WINDOW_TYPE_NORMAL
||
511 window_state
->IsFullscreen() ||
512 !window_state
->CanSnap()) {
516 if (action
== WINDOW_SNAP_LEFT
) {
517 base::RecordAction(UserMetricsAction("Accel_Window_Snap_Left"));
519 base::RecordAction(UserMetricsAction("Accel_Window_Snap_Right"));
521 const wm::WMEvent
event(action
== WINDOW_SNAP_LEFT
?
522 wm::WM_EVENT_SNAP_LEFT
: wm::WM_EVENT_SNAP_RIGHT
);
523 window_state
->OnWMEvent(&event
);
527 bool HandleWindowMinimize() {
529 base::UserMetricsAction("Accel_Toggle_Minimized_Minus"));
530 return accelerators::ToggleMinimized();
533 #if defined(OS_CHROMEOS)
534 bool HandleAddRemoveDisplay() {
535 base::RecordAction(UserMetricsAction("Accel_Add_Remove_Display"));
536 Shell::GetInstance()->display_manager()->AddRemoveDisplay();
541 base::RecordAction(UserMetricsAction("Accel_Open_Crosh"));
543 Shell::GetInstance()->new_window_delegate()->OpenCrosh();
547 bool HandleFileManager() {
548 base::RecordAction(UserMetricsAction("Accel_Open_File_Manager"));
550 Shell::GetInstance()->new_window_delegate()->OpenFileManager();
554 bool HandleLock(ui::KeyboardCode key_code
) {
555 base::RecordAction(UserMetricsAction("Accel_LockScreen_L"));
556 Shell::GetInstance()->session_state_delegate()->LockScreen();
560 bool HandleCycleUser(SessionStateDelegate::CycleUser cycle_user
) {
561 if (!Shell::GetInstance()->delegate()->IsMultiProfilesEnabled())
563 ash::SessionStateDelegate
* delegate
=
564 ash::Shell::GetInstance()->session_state_delegate();
565 if (delegate
->NumberOfLoggedInUsers() <= 1)
567 MultiProfileUMA::RecordSwitchActiveUser(
568 MultiProfileUMA::SWITCH_ACTIVE_USER_BY_ACCELERATOR
);
569 switch (cycle_user
) {
570 case SessionStateDelegate::CYCLE_TO_NEXT_USER
:
571 base::RecordAction(UserMetricsAction("Accel_Switch_To_Next_User"));
573 case SessionStateDelegate::CYCLE_TO_PREVIOUS_USER
:
574 base::RecordAction(UserMetricsAction("Accel_Switch_To_Previous_User"));
577 delegate
->CycleActiveUser(cycle_user
);
581 bool HandleToggleMirrorMode() {
582 base::RecordAction(UserMetricsAction("Accel_Toggle_Mirror_Mode"));
583 Shell::GetInstance()->display_controller()->ToggleMirrorMode();
587 bool HandleToggleSpokenFeedback() {
588 base::RecordAction(UserMetricsAction("Accel_Toggle_Spoken_Feedback"));
590 Shell::GetInstance()->accessibility_delegate()->
591 ToggleSpokenFeedback(A11Y_NOTIFICATION_SHOW
);
595 bool HandleToggleTouchViewTesting() {
596 // TODO(skuhne): This is only temporary! Remove this!
597 if (CommandLine::ForCurrentProcess()->HasSwitch(
598 switches::kAshEnableTouchViewTesting
)) {
599 MaximizeModeController
* controller
= Shell::GetInstance()->
600 maximize_mode_controller();
601 controller
->EnableMaximizeModeWindowManager(
602 !controller
->IsMaximizeModeWindowManagerEnabled());
608 bool HandleTouchHudClear() {
609 RootWindowController
* controller
=
610 RootWindowController::ForTargetRootWindow();
611 if (controller
->touch_hud_debug()) {
612 controller
->touch_hud_debug()->Clear();
618 bool HandleTouchHudModeChange() {
619 RootWindowController
* controller
=
620 RootWindowController::ForTargetRootWindow();
621 if (controller
->touch_hud_debug()) {
622 controller
->touch_hud_debug()->ChangeToNextMode();
628 bool HandleTouchHudProjectToggle() {
629 base::RecordAction(UserMetricsAction("Accel_Touch_Hud_Clear"));
630 bool enabled
= Shell::GetInstance()->is_touch_hud_projection_enabled();
631 Shell::GetInstance()->SetTouchHudProjectionEnabled(!enabled
);
635 bool HandleDisableCapsLock(ui::KeyboardCode key_code
,
636 ui::EventType previous_event_type
,
637 ui::KeyboardCode previous_key_code
) {
638 if (previous_event_type
== ui::ET_KEY_RELEASED
||
639 (previous_key_code
!= ui::VKEY_LSHIFT
&&
640 previous_key_code
!= ui::VKEY_SHIFT
&&
641 previous_key_code
!= ui::VKEY_RSHIFT
)) {
642 // If something else was pressed between the Shift key being pressed
643 // and released, then ignore the release of the Shift key.
646 base::RecordAction(UserMetricsAction("Accel_Disable_Caps_Lock"));
647 chromeos::input_method::InputMethodManager
* ime
=
648 chromeos::input_method::InputMethodManager::Get();
649 chromeos::input_method::ImeKeyboard
* keyboard
=
650 ime
? ime
->GetImeKeyboard() : NULL
;
651 if (keyboard
&& keyboard
->CapsLockIsEnabled()) {
652 keyboard
->SetCapsLockEnabled(false);
658 bool HandleToggleCapsLock(ui::KeyboardCode key_code
,
659 ui::EventType previous_event_type
,
660 ui::KeyboardCode previous_key_code
) {
661 if (key_code
== ui::VKEY_LWIN
) {
662 // If something else was pressed between the Search key (LWIN)
663 // being pressed and released, then ignore the release of the
665 // TODO(danakj): Releasing Alt first breaks this: crbug.com/166495
666 if (previous_event_type
== ui::ET_KEY_RELEASED
||
667 previous_key_code
!= ui::VKEY_LWIN
)
670 base::RecordAction(UserMetricsAction("Accel_Toggle_Caps_Lock"));
671 chromeos::input_method::InputMethodManager
* ime
=
672 chromeos::input_method::InputMethodManager::Get();
673 chromeos::input_method::ImeKeyboard
* keyboard
=
674 ime
? ime
->GetImeKeyboard() : NULL
;
676 keyboard
->SetCapsLockEnabled(!keyboard
->CapsLockIsEnabled());
680 #endif // defined(OS_CHROMEOS)
682 // Debug print methods.
684 bool HandlePrintLayerHierarchy() {
685 aura::Window::Windows root_windows
= Shell::GetAllRootWindows();
686 for (size_t i
= 0; i
< root_windows
.size(); ++i
) {
687 ui::PrintLayerHierarchy(
688 root_windows
[i
]->layer(),
689 root_windows
[i
]->GetHost()->dispatcher()->GetLastMouseLocationInRoot());
694 bool HandlePrintViewHierarchy() {
695 aura::Window
* active_window
= ash::wm::GetActiveWindow();
698 views::Widget
* browser_widget
=
699 views::Widget::GetWidgetForNativeWindow(active_window
);
702 views::PrintViewHierarchy(browser_widget
->GetRootView());
706 void PrintWindowHierarchy(aura::Window
* window
,
708 std::ostringstream
* out
) {
709 std::string
indent_str(indent
, ' ');
710 std::string
name(window
->name());
713 *out
<< indent_str
<< name
<< " (" << window
<< ")"
714 << " type=" << window
->type()
715 << (wm::IsActiveWindow(window
) ? " [active] " : " ")
716 << (window
->IsVisible() ? " visible " : " ")
717 << window
->bounds().ToString()
720 for (size_t i
= 0; i
< window
->children().size(); ++i
)
721 PrintWindowHierarchy(window
->children()[i
], indent
+ 3, out
);
724 bool HandlePrintWindowHierarchy() {
725 Shell::RootWindowControllerList controllers
=
726 Shell::GetAllRootWindowControllers();
727 for (size_t i
= 0; i
< controllers
.size(); ++i
) {
728 std::ostringstream out
;
729 out
<< "RootWindow " << i
<< ":\n";
730 PrintWindowHierarchy(controllers
[i
]->GetRootWindow(), 0, &out
);
731 // Error so logs can be collected from end-users.
732 LOG(ERROR
) << out
.str();
737 bool HandlePrintUIHierarchies() {
738 // This is a separate command so the user only has to hit one key to generate
739 // all the logs. Developers use the individual dumps repeatedly, so keep
740 // those as separate commands to avoid spamming their logs.
741 HandlePrintLayerHierarchy();
742 HandlePrintWindowHierarchy();
743 HandlePrintViewHierarchy();
749 AutoSet(ui::Accelerator
* scoped
, ui::Accelerator new_value
)
750 : scoped_(scoped
), new_value_(new_value
) {}
751 ~AutoSet() { *scoped_
= new_value_
; }
754 ui::Accelerator
* scoped_
;
755 const ui::Accelerator new_value_
;
757 DISALLOW_COPY_AND_ASSIGN(AutoSet
);
762 ////////////////////////////////////////////////////////////////////////////////
763 // AcceleratorController, public:
765 AcceleratorController::AcceleratorController()
766 : accelerator_manager_(new ui::AcceleratorManager
) {
770 AcceleratorController::~AcceleratorController() {
773 void AcceleratorController::Init() {
774 previous_accelerator_
.set_type(ui::ET_UNKNOWN
);
775 for (size_t i
= 0; i
< kActionsAllowedAtLoginOrLockScreenLength
; ++i
) {
776 actions_allowed_at_login_screen_
.insert(
777 kActionsAllowedAtLoginOrLockScreen
[i
]);
778 actions_allowed_at_lock_screen_
.insert(
779 kActionsAllowedAtLoginOrLockScreen
[i
]);
781 for (size_t i
= 0; i
< kActionsAllowedAtLockScreenLength
; ++i
)
782 actions_allowed_at_lock_screen_
.insert(kActionsAllowedAtLockScreen
[i
]);
783 for (size_t i
= 0; i
< kActionsAllowedAtModalWindowLength
; ++i
)
784 actions_allowed_at_modal_window_
.insert(kActionsAllowedAtModalWindow
[i
]);
785 for (size_t i
= 0; i
< kReservedActionsLength
; ++i
)
786 reserved_actions_
.insert(kReservedActions
[i
]);
787 for (size_t i
= 0; i
< kNonrepeatableActionsLength
; ++i
)
788 nonrepeatable_actions_
.insert(kNonrepeatableActions
[i
]);
789 for (size_t i
= 0; i
< kActionsAllowedInAppModeLength
; ++i
)
790 actions_allowed_in_app_mode_
.insert(kActionsAllowedInAppMode
[i
]);
791 for (size_t i
= 0; i
< kActionsNeedingWindowLength
; ++i
)
792 actions_needing_window_
.insert(kActionsNeedingWindow
[i
]);
794 RegisterAccelerators(kAcceleratorData
, kAcceleratorDataLength
);
797 RegisterAccelerators(kDesktopAcceleratorData
, kDesktopAcceleratorDataLength
);
800 if (DebugShortcutsEnabled()) {
801 RegisterAccelerators(kDebugAcceleratorData
, kDebugAcceleratorDataLength
);
802 for (size_t i
= 0; i
< kReservedDebugActionsLength
; ++i
)
803 reserved_actions_
.insert(kReservedDebugActions
[i
]);
806 #if defined(OS_CHROMEOS)
807 keyboard_brightness_control_delegate_
.reset(
808 new KeyboardBrightnessController());
812 void AcceleratorController::Register(const ui::Accelerator
& accelerator
,
813 ui::AcceleratorTarget
* target
) {
814 accelerator_manager_
->Register(accelerator
,
815 ui::AcceleratorManager::kNormalPriority
,
819 void AcceleratorController::Unregister(const ui::Accelerator
& accelerator
,
820 ui::AcceleratorTarget
* target
) {
821 accelerator_manager_
->Unregister(accelerator
, target
);
824 void AcceleratorController::UnregisterAll(ui::AcceleratorTarget
* target
) {
825 accelerator_manager_
->UnregisterAll(target
);
828 bool AcceleratorController::Process(const ui::Accelerator
& accelerator
) {
829 AutoSet
auto_set(&previous_accelerator_
, accelerator
);
831 if (ime_control_delegate_
) {
832 return accelerator_manager_
->Process(
833 ime_control_delegate_
->RemapAccelerator(accelerator
));
835 return accelerator_manager_
->Process(accelerator
);
838 bool AcceleratorController::IsRegistered(
839 const ui::Accelerator
& accelerator
) const {
840 return accelerator_manager_
->GetCurrentTarget(accelerator
) != NULL
;
843 bool AcceleratorController::IsReservedAccelerator(
844 const ui::Accelerator
& accelerator
) const {
845 const ui::Accelerator remapped_accelerator
= ime_control_delegate_
.get() ?
846 ime_control_delegate_
->RemapAccelerator(accelerator
) : accelerator
;
848 std::map
<ui::Accelerator
, int>::const_iterator iter
=
849 accelerators_
.find(remapped_accelerator
);
850 if (iter
== accelerators_
.end())
851 return false; // not an accelerator.
853 return reserved_actions_
.find(iter
->second
) != reserved_actions_
.end();
856 bool AcceleratorController::PerformAction(int action
,
857 const ui::Accelerator
& accelerator
) {
858 ash::Shell
* shell
= ash::Shell::GetInstance();
859 AcceleratorProcessingRestriction restriction
=
860 GetAcceleratorProcessingRestriction(action
);
861 if (restriction
!= RESTRICTION_NONE
)
862 return restriction
== RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION
;
864 const ui::KeyboardCode key_code
= accelerator
.key_code();
865 // PerformAction() is performed from gesture controllers and passes
866 // empty Accelerator() instance as the second argument. Such events
867 // should never be suspended.
868 const bool gesture_event
= key_code
== ui::VKEY_UNKNOWN
;
869 // Ignore accelerators invoked as repeated (while holding a key for a long
870 // time, if their handling is nonrepeatable.
871 if (nonrepeatable_actions_
.find(action
) != nonrepeatable_actions_
.end() &&
872 accelerator
.IsRepeat() && !gesture_event
) {
875 // Type of the previous accelerator. Used by NEXT_IME and DISABLE_CAPS_LOCK.
876 const ui::EventType previous_event_type
= previous_accelerator_
.type();
877 const ui::KeyboardCode previous_key_code
= previous_accelerator_
.key_code();
879 // You *MUST* return true when some action is performed. Otherwise, this
880 // function might be called *twice*, via BrowserView::PreHandleKeyboardEvent
881 // and BrowserView::HandleKeyboardEvent, for a single accelerator press.
883 // If your accelerator invokes more than one line of code, please either
884 // implement it in your module's controller code (like TOGGLE_MIRROR_MODE
885 // below) or pull it into a HandleFoo() function above.
887 case ACCESSIBLE_FOCUS_NEXT
:
888 return HandleAccessibleFocusCycle(false);
889 case ACCESSIBLE_FOCUS_PREVIOUS
:
890 return HandleAccessibleFocusCycle(true);
891 case CYCLE_BACKWARD_MRU
:
892 return HandleCycleBackwardMRU(accelerator
);
893 case CYCLE_FORWARD_MRU
:
894 return HandleCycleForwardMRU(accelerator
);
895 case TOGGLE_OVERVIEW
:
896 return ToggleOverview(accelerator
);
897 #if defined(OS_CHROMEOS)
898 case ADD_REMOVE_DISPLAY
:
899 return HandleAddRemoveDisplay();
900 case TOGGLE_MIRROR_MODE
:
901 return HandleToggleMirrorMode();
903 return HandleLock(key_code
);
904 case OPEN_FILE_MANAGER
:
905 return HandleFileManager();
907 return HandleCrosh();
908 case SILENCE_SPOKEN_FEEDBACK
:
909 HandleSilenceSpokenFeedback();
911 case SWAP_PRIMARY_DISPLAY
:
912 return HandleSwapPrimaryDisplay();
913 case SWITCH_TO_NEXT_USER
:
914 return HandleCycleUser(SessionStateDelegate::CYCLE_TO_NEXT_USER
);
915 case SWITCH_TO_PREVIOUS_USER
:
916 return HandleCycleUser(SessionStateDelegate::CYCLE_TO_PREVIOUS_USER
);
917 case TOGGLE_SPOKEN_FEEDBACK
:
918 return HandleToggleSpokenFeedback();
919 case TOGGLE_TOUCH_VIEW_TESTING
:
920 return HandleToggleTouchViewTesting();
922 Shell::GetInstance()->system_tray_notifier()->NotifyRequestToggleWifi();
924 case TOUCH_HUD_CLEAR
:
925 return HandleTouchHudClear();
926 case TOUCH_HUD_MODE_CHANGE
:
927 return HandleTouchHudModeChange();
928 case TOUCH_HUD_PROJECTION_TOGGLE
:
929 return HandleTouchHudProjectToggle();
930 case DISABLE_GPU_WATCHDOG
:
931 Shell::GetInstance()->gpu_support()->DisableGpuWatchdog();
933 case DISABLE_CAPS_LOCK
:
934 return HandleDisableCapsLock(
935 key_code
, previous_event_type
, previous_key_code
);
936 case TOGGLE_CAPS_LOCK
:
937 return HandleToggleCapsLock(
938 key_code
, previous_event_type
, previous_key_code
);
939 #endif // OS_CHROMEOS
940 case OPEN_FEEDBACK_PAGE
:
941 return HandleOpenFeedbackPage();
943 // UMA metrics are recorded in the handler.
944 exit_warning_handler_
.HandleAccelerator();
946 case NEW_INCOGNITO_WINDOW
:
947 return HandleNewIncognitoWindow();
949 return HandleNewTab(key_code
);
951 return HandleNewWindow();
953 return HandleRestoreTab();
954 case TAKE_SCREENSHOT
:
955 return HandleTakeScreenshot(screenshot_delegate_
.get());
956 case TAKE_PARTIAL_SCREENSHOT
:
957 return HandleTakePartialScreenshot(screenshot_delegate_
.get());
958 case TOGGLE_APP_LIST
:
959 return HandleToggleAppList(
960 key_code
, previous_event_type
, previous_key_code
, accelerator
);
961 case BRIGHTNESS_DOWN
:
962 if (brightness_control_delegate_
)
963 return brightness_control_delegate_
->HandleBrightnessDown(accelerator
);
966 if (brightness_control_delegate_
)
967 return brightness_control_delegate_
->HandleBrightnessUp(accelerator
);
969 case KEYBOARD_BRIGHTNESS_DOWN
:
970 if (keyboard_brightness_control_delegate_
)
971 return keyboard_brightness_control_delegate_
->
972 HandleKeyboardBrightnessDown(accelerator
);
974 case KEYBOARD_BRIGHTNESS_UP
:
975 if (keyboard_brightness_control_delegate_
)
976 return keyboard_brightness_control_delegate_
->
977 HandleKeyboardBrightnessUp(accelerator
);
980 ash::VolumeControlDelegate
* volume_delegate
=
981 shell
->system_tray_delegate()->GetVolumeControlDelegate();
982 return volume_delegate
&& volume_delegate
->HandleVolumeMute(accelerator
);
985 ash::VolumeControlDelegate
* volume_delegate
=
986 shell
->system_tray_delegate()->GetVolumeControlDelegate();
987 return volume_delegate
&& volume_delegate
->HandleVolumeDown(accelerator
);
990 ash::VolumeControlDelegate
* volume_delegate
=
991 shell
->system_tray_delegate()->GetVolumeControlDelegate();
992 return volume_delegate
&& volume_delegate
->HandleVolumeUp(accelerator
);
995 return HandleFocusLauncher();
996 case FOCUS_NEXT_PANE
:
997 return HandleRotatePaneFocus(Shell::FORWARD
);
998 case FOCUS_PREVIOUS_PANE
:
999 return HandleRotatePaneFocus(Shell::BACKWARD
);
1000 case SHOW_KEYBOARD_OVERLAY
:
1001 return HandleShowKeyboardOverlay();
1002 case SHOW_SYSTEM_TRAY_BUBBLE
:
1003 return HandleShowSystemTrayBubble();
1004 case SHOW_MESSAGE_CENTER_BUBBLE
:
1005 HandleShowMessageCenterBubble();
1007 case SHOW_TASK_MANAGER
:
1008 return HandleShowTaskManager();
1011 ime_control_delegate_
.get(), previous_event_type
, previous_key_code
);
1012 // NEXT_IME is bound to Alt-Shift key up event. To be consistent with
1013 // Windows behavior, do not consume the key event here.
1016 return HandlePreviousIme(ime_control_delegate_
.get(), accelerator
);
1017 case PRINT_UI_HIERARCHIES
:
1018 return HandlePrintUIHierarchies();
1020 return HandleSwitchIme(ime_control_delegate_
.get(), accelerator
);
1022 return HandleLaunchAppN(0);
1024 return HandleLaunchAppN(1);
1026 return HandleLaunchAppN(2);
1028 return HandleLaunchAppN(3);
1030 return HandleLaunchAppN(4);
1032 return HandleLaunchAppN(5);
1034 return HandleLaunchAppN(6);
1036 return HandleLaunchAppN(7);
1037 case LAUNCH_LAST_APP
:
1038 return HandleLaunchLastApp();
1039 case WINDOW_SNAP_LEFT
:
1040 case WINDOW_SNAP_RIGHT
:
1041 return HandleWindowSnap(action
);
1042 case WINDOW_MINIMIZE
:
1043 return HandleWindowMinimize();
1044 case TOGGLE_FULLSCREEN
:
1045 return HandleToggleFullscreen(key_code
);
1046 case TOGGLE_MAXIMIZED
:
1047 accelerators::ToggleMaximized();
1049 case WINDOW_POSITION_CENTER
:
1050 return HandlePositionCenter();
1052 return HandleScaleUI(true /* up */);
1054 return HandleScaleUI(false /* down */);
1055 case SCALE_UI_RESET
:
1056 return HandleScaleReset();
1058 return HandleRotateActiveWindow();
1060 return HandleRotateScreen();
1061 case TOGGLE_DESKTOP_BACKGROUND_MODE
:
1062 return debug::CycleDesktopBackgroundMode();
1063 case TOGGLE_ROOT_WINDOW_FULL_SCREEN
:
1064 return HandleToggleRootWindowFullScreen();
1065 case DEBUG_TOGGLE_DEVICE_SCALE_FACTOR
:
1066 Shell::GetInstance()->display_manager()->ToggleDisplayScaleFactor();
1068 case DEBUG_TOGGLE_SHOW_DEBUG_BORDERS
:
1069 ash::debug::ToggleShowDebugBorders();
1071 case DEBUG_TOGGLE_SHOW_FPS_COUNTER
:
1072 ash::debug::ToggleShowFpsCounter();
1074 case DEBUG_TOGGLE_SHOW_PAINT_RECTS
:
1075 ash::debug::ToggleShowPaintRects();
1077 case MAGNIFY_SCREEN_ZOOM_IN
:
1078 return HandleMagnifyScreen(1);
1079 case MAGNIFY_SCREEN_ZOOM_OUT
:
1080 return HandleMagnifyScreen(-1);
1081 case MEDIA_NEXT_TRACK
:
1082 return HandleMediaNextTrack();
1083 case MEDIA_PLAY_PAUSE
:
1084 return HandleMediaPlayPause();
1085 case MEDIA_PREV_TRACK
:
1086 return HandleMediaPrevTrack();
1087 case POWER_PRESSED
: // fallthrough
1088 case POWER_RELEASED
:
1089 #if defined(OS_CHROMEOS)
1090 if (!base::SysInfo::IsRunningOnChromeOS()) {
1091 // There is no powerd in linux desktop, so call the
1092 // PowerButtonController here.
1093 Shell::GetInstance()->power_button_controller()->
1094 OnPowerButtonEvent(action
== POWER_PRESSED
, base::TimeTicks());
1097 // We don't do anything with these at present on the device,
1098 // (power button events are reported to us from powerm via
1099 // D-BUS), but we consume them to prevent them from getting
1100 // passed to apps -- see http://crbug.com/146609.
1104 Shell::GetInstance()->power_button_controller()->
1105 OnLockButtonEvent(action
== LOCK_PRESSED
, base::TimeTicks());
1107 case PRINT_LAYER_HIERARCHY
:
1108 return HandlePrintLayerHierarchy();
1109 case PRINT_VIEW_HIERARCHY
:
1110 return HandlePrintViewHierarchy();
1111 case PRINT_WINDOW_HIERARCHY
:
1112 return HandlePrintWindowHierarchy();
1114 NOTREACHED() << "Unhandled action " << action
;
1119 AcceleratorController::AcceleratorProcessingRestriction
1120 AcceleratorController::GetCurrentAcceleratorRestriction() {
1121 return GetAcceleratorProcessingRestriction(-1);
1124 AcceleratorController::AcceleratorProcessingRestriction
1125 AcceleratorController::GetAcceleratorProcessingRestriction(int action
) {
1126 ash::Shell
* shell
= ash::Shell::GetInstance();
1127 if (!shell
->session_state_delegate()->IsActiveUserSessionStarted() &&
1128 actions_allowed_at_login_screen_
.find(action
) ==
1129 actions_allowed_at_login_screen_
.end()) {
1130 return RESTRICTION_PREVENT_PROCESSING
;
1132 if (shell
->session_state_delegate()->IsScreenLocked() &&
1133 actions_allowed_at_lock_screen_
.find(action
) ==
1134 actions_allowed_at_lock_screen_
.end()) {
1135 return RESTRICTION_PREVENT_PROCESSING
;
1137 if (shell
->IsSystemModalWindowOpen() &&
1138 actions_allowed_at_modal_window_
.find(action
) ==
1139 actions_allowed_at_modal_window_
.end()) {
1140 // Note we prevent the shortcut from propagating so it will not
1141 // be passed to the modal window. This is important for things like
1142 // Alt+Tab that would cause an undesired effect in the modal window by
1143 // cycling through its window elements.
1144 return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION
;
1146 if (shell
->delegate()->IsRunningInForcedAppMode() &&
1147 actions_allowed_in_app_mode_
.find(action
) ==
1148 actions_allowed_in_app_mode_
.end()) {
1149 return RESTRICTION_PREVENT_PROCESSING
;
1151 if (MruWindowTracker::BuildWindowList(false).empty() &&
1152 actions_needing_window_
.find(action
) != actions_needing_window_
.end()) {
1153 Shell::GetInstance()->accessibility_delegate()->TriggerAccessibilityAlert(
1154 A11Y_ALERT_WINDOW_NEEDED
);
1155 return RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION
;
1157 return RESTRICTION_NONE
;
1160 void AcceleratorController::SetBrightnessControlDelegate(
1161 scoped_ptr
<BrightnessControlDelegate
> brightness_control_delegate
) {
1162 brightness_control_delegate_
= brightness_control_delegate
.Pass();
1165 void AcceleratorController::SetImeControlDelegate(
1166 scoped_ptr
<ImeControlDelegate
> ime_control_delegate
) {
1167 ime_control_delegate_
= ime_control_delegate
.Pass();
1170 void AcceleratorController::SetScreenshotDelegate(
1171 scoped_ptr
<ScreenshotDelegate
> screenshot_delegate
) {
1172 screenshot_delegate_
= screenshot_delegate
.Pass();
1175 ////////////////////////////////////////////////////////////////////////////////
1176 // AcceleratorController, ui::AcceleratorTarget implementation:
1178 bool AcceleratorController::AcceleratorPressed(
1179 const ui::Accelerator
& accelerator
) {
1180 std::map
<ui::Accelerator
, int>::const_iterator it
=
1181 accelerators_
.find(accelerator
);
1182 DCHECK(it
!= accelerators_
.end());
1183 return PerformAction(static_cast<AcceleratorAction
>(it
->second
), accelerator
);
1186 void AcceleratorController::RegisterAccelerators(
1187 const AcceleratorData accelerators
[],
1188 size_t accelerators_length
) {
1189 for (size_t i
= 0; i
< accelerators_length
; ++i
) {
1190 ui::Accelerator
accelerator(accelerators
[i
].keycode
,
1191 accelerators
[i
].modifiers
);
1192 accelerator
.set_type(accelerators
[i
].trigger_on_press
?
1193 ui::ET_KEY_PRESSED
: ui::ET_KEY_RELEASED
);
1194 Register(accelerator
, this);
1195 accelerators_
.insert(
1196 std::make_pair(accelerator
, accelerators
[i
].action
));
1200 void AcceleratorController::SetKeyboardBrightnessControlDelegate(
1201 scoped_ptr
<KeyboardBrightnessControlDelegate
>
1202 keyboard_brightness_control_delegate
) {
1203 keyboard_brightness_control_delegate_
=
1204 keyboard_brightness_control_delegate
.Pass();
1207 bool AcceleratorController::CanHandleAccelerators() const {