// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ash/accelerators/accelerator_controller.h" #include #include #include #include "ash/accelerators/accelerator_table.h" #include "ash/ash_switches.h" #include "ash/caps_lock_delegate.h" #include "ash/desktop_background/desktop_background_controller.h" #include "ash/display/display_controller.h" #include "ash/display/multi_display_manager.h" #include "ash/focus_cycler.h" #include "ash/ime_control_delegate.h" #include "ash/launcher/launcher.h" #include "ash/launcher/launcher_delegate.h" #include "ash/launcher/launcher_model.h" #include "ash/magnifier/magnification_controller.h" #include "ash/root_window_controller.h" #include "ash/rotator/screen_rotation.h" #include "ash/screen_ash.h" #include "ash/screenshot_delegate.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/system/brightness/brightness_control_delegate.h" #include "ash/system/keyboard_brightness/keyboard_brightness_control_delegate.h" #include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray.h" #include "ash/system/tray/system_tray_delegate.h" #include "ash/volume_control_delegate.h" #include "ash/wm/partial_screenshot_view.h" #include "ash/wm/power_button_controller.h" #include "ash/wm/property_util.h" #include "ash/wm/window_cycle_controller.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/snap_sizer.h" #include "base/bind.h" #include "base/command_line.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator_manager.h" #include "ui/base/events/event.h" #include "ui/base/keycodes/keyboard_codes.h" #include "ui/compositor/debug_utils.h" #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/layer_animator.h" #include "ui/gfx/screen.h" #include "ui/oak/oak.h" #include "ui/views/debug_utils.h" #include "ui/views/widget/widget.h" #if defined(OS_CHROMEOS) #include "ash/display/output_configurator_animation.h" #include "ash/system/chromeos/keyboard_brightness_controller.h" #include "base/chromeos/chromeos_version.h" #include "base/time.h" #include "chromeos/display/output_configurator.h" #endif // defined(OS_CHROMEOS) namespace ash { namespace { // Factor of magnification scale. For example, when this value is 1.189, scale // value will be changed x1.000, x1.189, x1.414, x1.681, x2.000, ... // Note: this value is 2.0 ^ (1 / 4). const float kMagnificationFactor = 1.18920712f; bool DebugShortcutsEnabled() { #if defined(NDEBUG) return CommandLine::ForCurrentProcess()->HasSwitch( switches::kAshDebugShortcuts); #else return true; #endif } bool HandleCycleWindowMRU(WindowCycleController::Direction direction, bool is_alt_down) { Shell::GetInstance()-> window_cycle_controller()->HandleCycleWindow(direction, is_alt_down); // Always report we handled the key, even if the window didn't change. return true; } void HandleCycleWindowLinear(CycleDirection direction) { Launcher::ForPrimaryDisplay()->CycleWindowLinear(direction); } #if defined(OS_CHROMEOS) bool HandleLock() { Shell::GetInstance()->delegate()->LockScreen(); return true; } bool HandleFileManager(bool as_dialog) { Shell::GetInstance()->delegate()->OpenFileManager(as_dialog); return true; } bool HandleCrosh() { Shell::GetInstance()->delegate()->OpenCrosh(); return true; } bool HandleToggleSpokenFeedback() { Shell::GetInstance()->delegate()->ToggleSpokenFeedback(); return true; } void HandleCycleDisplayMode() { Shell* shell = Shell::GetInstance(); if (!base::chromeos::IsRunningOnChromeOS()) { internal::MultiDisplayManager::CycleDisplay(); } else if (shell->output_configurator()->connected_output_count() > 1) { internal::OutputConfiguratorAnimation* animation = shell->output_configurator_animation(); animation->StartFadeOutAnimation(base::Bind( base::IgnoreResult(&chromeos::OutputConfigurator::CycleDisplayMode), base::Unretained(shell->output_configurator()))); } } void HandleSwapPrimaryDisplay() { if (Shell::GetScreen()->GetNumDisplays() > 1) { Shell::GetInstance()->display_controller()->SetPrimaryDisplay( ScreenAsh::GetSecondaryDisplay()); } } #endif // defined(OS_CHROMEOS) bool HandleExit() { ShellDelegate* delegate = Shell::GetInstance()->delegate(); if (!delegate) return false; delegate->Exit(); return true; } bool HandleNewTab() { Shell::GetInstance()->delegate()->NewTab(); return true; } bool HandleNewWindow(bool is_incognito) { ShellDelegate* delegate = Shell::GetInstance()->delegate(); if (!delegate) return false; delegate->NewWindow(is_incognito); return true; } bool HandleRestoreTab() { Shell::GetInstance()->delegate()->RestoreTab(); return true; } bool HandleShowTaskManager() { Shell::GetInstance()->delegate()->ShowTaskManager(); return true; } bool HandleRotatePaneFocus(Shell::Direction direction) { if (!Shell::GetInstance()->delegate()->RotatePaneFocus(direction)) { // No browser window is available. Focus the launcher. Shell* shell = Shell::GetInstance(); switch (direction) { case Shell::FORWARD: shell->focus_cycler()->RotateFocus(internal::FocusCycler::FORWARD); break; case Shell::BACKWARD: shell->focus_cycler()->RotateFocus(internal::FocusCycler::BACKWARD); break; } } return true; } // Rotates the default window container. bool HandleRotateWindows() { Shell::RootWindowControllerList controllers = Shell::GetAllRootWindowControllers(); for (size_t i = 0; i < controllers.size(); ++i) { aura::Window* target = controllers[i]->GetContainer( internal::kShellWindowId_DefaultContainer); // The rotation animation bases its target transform on the current // rotation and position. Since there could be an animation in progress // right now, queue this animation so when it starts it picks up a neutral // rotation and position. Use replace so we only enqueue one at a time. target->layer()->GetAnimator()-> set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); scoped_ptr screen_rotation( new ui::LayerAnimationSequence(new ash::ScreenRotation(360))); target->layer()->GetAnimator()->StartAnimation( screen_rotation.release()); } return true; } // Rotates the screen. bool HandleRotateScreen() { static int i = 0; int delta = 0; switch (i) { case 0: delta = 90; break; case 1: delta = 90; break; case 2: delta = 90; break; case 3: delta = 90; break; case 4: delta = -90; break; case 5: delta = -90; break; case 6: delta = -90; break; case 7: delta = -90; break; case 8: delta = -90; break; case 9: delta = 180; break; case 10: delta = 180; break; case 11: delta = 90; break; case 12: delta = 180; break; case 13: delta = 180; break; } i = (i + 1) % 14; Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); for (size_t i = 0; i < root_windows.size(); ++i) { aura::RootWindow* root_window = root_windows[i]; root_window->layer()->GetAnimator()-> set_preemption_strategy(ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); scoped_ptr screen_rotation( new ui::LayerAnimationSequence(new ash::ScreenRotation(delta))); screen_rotation->AddObserver(root_window); root_window->layer()->GetAnimator()-> StartAnimation(screen_rotation.release()); } return true; } bool HandleToggleDesktopBackgroundMode() { DesktopBackgroundController* desktop_background_controller = Shell::GetInstance()->desktop_background_controller(); if (desktop_background_controller->desktop_background_mode() == DesktopBackgroundController::BACKGROUND_IMAGE) { desktop_background_controller->SetDesktopBackgroundSolidColorMode( SK_ColorBLACK); } else { ash::Shell::GetInstance()->user_wallpaper_delegate()-> InitializeWallpaper(); } return true; } bool HandleToggleRootWindowFullScreen() { Shell::GetPrimaryRootWindow()->ToggleFullScreen(); return true; } // Magnify the screen bool HandleMagnifyScreen(int delta_index) { // TODO(yoshiki): Create the class like MagnifierStepScaleController, and // move the following scale control to it. float scale = ash::Shell::GetInstance()->magnification_controller()->GetScale(); // Calculate rounded logarithm (base kMagnificationFactor) of scale. int scale_index = std::floor(std::log(scale) / std::log(kMagnificationFactor) + 0.5); int new_scale_index = std::max(0, std::min(8, scale_index + delta_index)); ash::Shell::GetInstance()->magnification_controller()-> SetScale(std::pow(kMagnificationFactor, new_scale_index), true); return true; } bool HandleMediaNextTrack() { Shell::GetInstance()->delegate()->HandleMediaNextTrack(); return true; } bool HandleMediaPlayPause() { Shell::GetInstance()->delegate()->HandleMediaPlayPause(); return true; } bool HandleMediaPrevTrack() { Shell::GetInstance()->delegate()->HandleMediaPrevTrack(); return true; } #if !defined(NDEBUG) bool HandlePrintLayerHierarchy() { Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); for (size_t i = 0; i < root_windows.size(); ++i) { ui::PrintLayerHierarchy(root_windows[i]->layer(), root_windows[i]->GetLastMouseLocationInRoot()); } return true; } bool HandlePrintViewHierarchy() { aura::Window* default_container = Shell::GetPrimaryRootWindowController()->GetContainer( internal::kShellWindowId_DefaultContainer); if (default_container->children().empty()) return true; aura::Window* browser_frame = default_container->children()[0]; views::Widget* browser_widget = views::Widget::GetWidgetForNativeWindow(browser_frame); views::PrintViewHierarchy(browser_widget->GetRootView()); return true; } void PrintWindowHierarchy(aura::Window* window, int indent) { std::string indent_str(indent, ' '); DLOG(INFO) << indent_str << window->name() << " type " << window->type() << (wm::IsActiveWindow(window) ? "active" : ""); for (size_t i = 0; i < window->children().size(); ++i) PrintWindowHierarchy(window->children()[i], indent + 3); } bool HandlePrintWindowHierarchy() { DLOG(INFO) << "Window hierarchy:"; Shell::RootWindowControllerList controllers = Shell::GetAllRootWindowControllers(); for (size_t i = 0; i < controllers.size(); ++i) { DLOG(INFO) << "RootWindow " << i << ":"; aura::Window* container = controllers[i]->GetContainer( internal::kShellWindowId_DefaultContainer); PrintWindowHierarchy(container, 0); } return true; } #endif // !defined(NDEBUG) } // namespace //////////////////////////////////////////////////////////////////////////////// // AcceleratorControllerContext, public: AcceleratorControllerContext::AcceleratorControllerContext() : repeated_(false), previous_event_type_(ui::ET_UNKNOWN) { } void AcceleratorControllerContext::UpdateContext( const ui::Accelerator& accelerator) { const ui::Accelerator previous_accelerator = current_accelerator_; current_accelerator_ = accelerator; // Compute contextual information. repeated_ = previous_accelerator == current_accelerator_; previous_event_type_ = previous_accelerator.type(); } //////////////////////////////////////////////////////////////////////////////// // AcceleratorController, public: AcceleratorController::AcceleratorController() : accelerator_manager_(new ui::AcceleratorManager) { Init(); } AcceleratorController::~AcceleratorController() { } void AcceleratorController::Init() { for (size_t i = 0; i < kActionsAllowedAtLoginOrLockScreenLength; ++i) { actions_allowed_at_login_screen_.insert( kActionsAllowedAtLoginOrLockScreen[i]); actions_allowed_at_lock_screen_.insert( kActionsAllowedAtLoginOrLockScreen[i]); } for (size_t i = 0; i < kActionsAllowedAtLockScreenLength; ++i) actions_allowed_at_lock_screen_.insert(kActionsAllowedAtLockScreen[i]); for (size_t i = 0; i < kActionsAllowedAtModalWindowLength; ++i) actions_allowed_at_modal_window_.insert(kActionsAllowedAtModalWindow[i]); for (size_t i = 0; i < kReservedActionsLength; ++i) reserved_actions_.insert(kReservedActions[i]); for (size_t i = 0; i < kNonrepeatableActionsLength; ++i) nonrepeatable_actions_.insert(kNonrepeatableActions[i]); RegisterAccelerators(kAcceleratorData, kAcceleratorDataLength); if (DebugShortcutsEnabled()) RegisterAccelerators(kDebugAcceleratorData, kDebugAcceleratorDataLength); #if defined(OS_CHROMEOS) keyboard_brightness_control_delegate_.reset( new KeyboardBrightnessController()); #endif } void AcceleratorController::Register(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) { accelerator_manager_->Register(accelerator, ui::AcceleratorManager::kNormalPriority, target); } void AcceleratorController::Unregister(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target) { accelerator_manager_->Unregister(accelerator, target); } void AcceleratorController::UnregisterAll(ui::AcceleratorTarget* target) { accelerator_manager_->UnregisterAll(target); } bool AcceleratorController::Process(const ui::Accelerator& accelerator) { if (ime_control_delegate_.get()) { return accelerator_manager_->Process( ime_control_delegate_->RemapAccelerator(accelerator)); } return accelerator_manager_->Process(accelerator); } bool AcceleratorController::IsRegistered( const ui::Accelerator& accelerator) const { return accelerator_manager_->GetCurrentTarget(accelerator) != NULL; } bool AcceleratorController::IsReservedAccelerator( const ui::Accelerator& accelerator) const { const ui::Accelerator remapped_accelerator = ime_control_delegate_.get() ? ime_control_delegate_->RemapAccelerator(accelerator) : accelerator; std::map::const_iterator iter = accelerators_.find(remapped_accelerator); if (iter == accelerators_.end()) return false; // not an accelerator. return reserved_actions_.find(iter->second) != reserved_actions_.end(); } bool AcceleratorController::PerformAction(int action, const ui::Accelerator& accelerator) { ash::Shell* shell = ash::Shell::GetInstance(); bool at_login_screen = false; #if defined(OS_CHROMEOS) at_login_screen = shell->delegate() && !shell->delegate()->IsSessionStarted(); #endif if (at_login_screen && actions_allowed_at_login_screen_.find(action) == actions_allowed_at_login_screen_.end()) { return false; } if (shell->IsScreenLocked() && actions_allowed_at_lock_screen_.find(action) == actions_allowed_at_lock_screen_.end()) { return false; } if (shell->IsModalWindowOpen() && actions_allowed_at_modal_window_.find(action) == actions_allowed_at_modal_window_.end()) { // Note: we return true. This indicates the shortcut is handled // and will not be passed to the modal window. This is important // for things like Alt+Tab that would cause an undesired effect // in the modal window by cycling through its window elements. return true; } const ui::KeyboardCode key_code = accelerator.key_code(); // PerformAction() is performed from gesture controllers and passes // empty Accelerator() instance as the second argument. Such events // should never be suspended. const bool gesture_event = key_code == ui::VKEY_UNKNOWN; // Ignore accelerators invoked as repeated (while holding a key for a long // time, if their handling is nonrepeatable. if (nonrepeatable_actions_.find(action) != nonrepeatable_actions_.end() && context_.repeated() && !gesture_event) { return true; } // Type of the previous accelerator. Used by NEXT_IME and DISABLE_CAPS_LOCK. const ui::EventType previous_event_type = context_.previous_event_type(); // You *MUST* return true when some action is performed. Otherwise, this // function might be called *twice*, via BrowserView::PreHandleKeyboardEvent // and BrowserView::HandleKeyboardEvent, for a single accelerator press. switch (action) { case CYCLE_BACKWARD_MRU: if (key_code == ui::VKEY_TAB && shell->delegate()) shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_PREVWINDOW_TAB); return HandleCycleWindowMRU(WindowCycleController::BACKWARD, accelerator.IsAltDown()); case CYCLE_FORWARD_MRU: if (key_code == ui::VKEY_TAB && shell->delegate()) shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEXTWINDOW_TAB); return HandleCycleWindowMRU(WindowCycleController::FORWARD, accelerator.IsAltDown()); case CYCLE_BACKWARD_LINEAR: if (key_code == ui::VKEY_F5 && shell->delegate()) shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_PREVWINDOW_F5); HandleCycleWindowLinear(CYCLE_BACKWARD); return true; case CYCLE_FORWARD_LINEAR: if (key_code == ui::VKEY_F5 && shell->delegate()) shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEXTWINDOW_F5); HandleCycleWindowLinear(CYCLE_FORWARD); return true; #if defined(OS_CHROMEOS) case CYCLE_DISPLAY_MODE: HandleCycleDisplayMode(); return true; case LOCK_SCREEN: return HandleLock(); case OPEN_FILE_MANAGER_DIALOG: return HandleFileManager(true /* as_dialog */); case OPEN_FILE_MANAGER_TAB: return HandleFileManager(false /* as_dialog */); case OPEN_CROSH: return HandleCrosh(); case SWAP_PRIMARY_DISPLAY: HandleSwapPrimaryDisplay(); return true; case TOGGLE_SPOKEN_FEEDBACK: return HandleToggleSpokenFeedback(); case TOGGLE_WIFI: if (Shell::GetInstance()->tray_delegate()) Shell::GetInstance()->tray_delegate()->ToggleWifi(); return true; #endif case OPEN_FEEDBACK_PAGE: ash::Shell::GetInstance()->delegate()->OpenFeedbackPage(); return true; case EXIT: return HandleExit(); case NEW_INCOGNITO_WINDOW: return HandleNewWindow(true /* is_incognito */); case NEW_TAB: if (key_code == ui::VKEY_T && shell->delegate()) shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_NEWTAB_T); return HandleNewTab(); case NEW_WINDOW: return HandleNewWindow(false /* is_incognito */); case RESTORE_TAB: return HandleRestoreTab(); case TAKE_SCREENSHOT: if (screenshot_delegate_.get() && screenshot_delegate_->CanTakeScreenshot()) { screenshot_delegate_->HandleTakeScreenshotForAllRootWindows(); } // Return true to prevent propagation of the key event. return true; case TAKE_PARTIAL_SCREENSHOT: if (screenshot_delegate_.get()) { ash::PartialScreenshotView::StartPartialScreenshot( screenshot_delegate_.get()); } // Return true to prevent propagation of the key event because // this key combination is reserved for partial screenshot. return true; case TOGGLE_APP_LIST: if (key_code == ui::VKEY_LWIN && shell->delegate()) shell->delegate()->RecordUserMetricsAction(UMA_ACCEL_SEARCH_LWIN); // When spoken feedback is enabled, we should neither toggle the list nor // consume the key since Search+Shift is one of the shortcuts the a11y // feature uses. crbug.com/132296 DCHECK_EQ(ui::VKEY_LWIN, accelerator.key_code()); if (Shell::GetInstance()->delegate()->IsSpokenFeedbackEnabled()) return false; ash::Shell::GetInstance()->ToggleAppList(); return true; case DISABLE_CAPS_LOCK: // See: case NEXT_IME. if (previous_event_type == ui::ET_KEY_RELEASED) { // We totally ignore this accelerator. return false; } if (shell->caps_lock_delegate()->IsCapsLockEnabled()) { shell->caps_lock_delegate()->SetCapsLockEnabled(false); return true; } return false; case TOGGLE_CAPS_LOCK: shell->caps_lock_delegate()->ToggleCapsLock(); return true; case BRIGHTNESS_DOWN: if (brightness_control_delegate_.get()) return brightness_control_delegate_->HandleBrightnessDown(accelerator); break; case BRIGHTNESS_UP: if (brightness_control_delegate_.get()) return brightness_control_delegate_->HandleBrightnessUp(accelerator); break; case KEYBOARD_BRIGHTNESS_DOWN: if (keyboard_brightness_control_delegate_.get()) return keyboard_brightness_control_delegate_-> HandleKeyboardBrightnessDown(accelerator); break; case KEYBOARD_BRIGHTNESS_UP: if (keyboard_brightness_control_delegate_.get()) return keyboard_brightness_control_delegate_-> HandleKeyboardBrightnessUp(accelerator); break; case VOLUME_MUTE: return shell->tray_delegate()->GetVolumeControlDelegate()-> HandleVolumeMute(accelerator); break; case VOLUME_DOWN: return shell->tray_delegate()->GetVolumeControlDelegate()-> HandleVolumeDown(accelerator); break; case VOLUME_UP: return shell->tray_delegate()->GetVolumeControlDelegate()-> HandleVolumeUp(accelerator); break; case FOCUS_LAUNCHER: return shell->focus_cycler()->FocusWidget( Launcher::ForPrimaryDisplay()->widget()); break; case FOCUS_NEXT_PANE: return HandleRotatePaneFocus(Shell::FORWARD); case FOCUS_PREVIOUS_PANE: return HandleRotatePaneFocus(Shell::BACKWARD); case FOCUS_SYSTEM_TRAY: { internal::StatusAreaWidget* status_area = ash::Shell::GetInstance()->status_area_widget(); if (status_area) { return shell->focus_cycler()->FocusWidget( status_area->system_tray()->GetWidget()); } break; } case SHOW_KEYBOARD_OVERLAY: ash::Shell::GetInstance()->delegate()->ShowKeyboardOverlay(); return true; case SHOW_OAK: if (CommandLine::ForCurrentProcess()->HasSwitch( switches::kAshEnableOak)) { oak::ShowOakWindow(); return true; } break; case SHOW_TASK_MANAGER: return HandleShowTaskManager(); case NEXT_IME: // This check is necessary e.g. not to process the Shift+Alt+ // ET_KEY_RELEASED accelerator for Chrome OS (see ash/accelerators/ // accelerator_controller.cc) when Shift+Alt+Tab is pressed and then Tab // is released. if (previous_event_type == ui::ET_KEY_RELEASED) { // We totally ignore this accelerator. // TODO(mazda): Fix crbug.com/158217 return false; } if (ime_control_delegate_.get()) return ime_control_delegate_->HandleNextIme(); break; case PREVIOUS_IME: if (ime_control_delegate_.get()) return ime_control_delegate_->HandlePreviousIme(); break; case SWITCH_IME: if (ime_control_delegate_.get()) return ime_control_delegate_->HandleSwitchIme(accelerator); break; case SELECT_WIN_0: SwitchToWindow(0); return true; case SELECT_WIN_1: SwitchToWindow(1); return true; case SELECT_WIN_2: SwitchToWindow(2); return true; case SELECT_WIN_3: SwitchToWindow(3); return true; case SELECT_WIN_4: SwitchToWindow(4); return true; case SELECT_WIN_5: SwitchToWindow(5); return true; case SELECT_WIN_6: SwitchToWindow(6); return true; case SELECT_WIN_7: SwitchToWindow(7); return true; case SELECT_LAST_WIN: SwitchToWindow(-1); return true; case WINDOW_SNAP_LEFT: case WINDOW_SNAP_RIGHT: { aura::Window* window = wm::GetActiveWindow(); // Disable window docking shortcut key for full screen window due to // http://crbug.com/135487. if (!window || window->type() != aura::client::WINDOW_TYPE_NORMAL || wm::IsWindowFullscreen(window)) { break; } internal::SnapSizer sizer(window, gfx::Point(), action == WINDOW_SNAP_LEFT ? internal::SnapSizer::LEFT_EDGE : internal::SnapSizer::RIGHT_EDGE, internal::SnapSizer::OTHER_INPUT); if (wm::IsWindowFullscreen(window) || wm::IsWindowMaximized(window)) { // Before we can set the bounds we need to restore the window. // Restoring the window will set the window to its restored bounds. // To avoid an unnecessary bounds changes (which may have side effects) // we set the restore bounds to the bounds we want, restore the window, // then reset the restore bounds. This way no unnecessary bounds // changes occurs and the original restore bounds is remembered. gfx::Rect restore = *GetRestoreBoundsInScreen(window); SetRestoreBoundsInParent(window, sizer.GetSnapBounds(window->bounds())); wm::RestoreWindow(window); SetRestoreBoundsInScreen(window, restore); } else { window->SetBounds(sizer.GetSnapBounds(window->bounds())); } return true; } case WINDOW_MINIMIZE: { aura::Window* window = wm::GetActiveWindow(); // Attempt to restore the window that would be cycled through next from // the launcher when there is no active window. if (!window) return HandleCycleWindowMRU(WindowCycleController::FORWARD, false); // Disable the shortcut for minimizing full screen window due to // crbug.com/131709, which is a crashing issue related to minimizing // full screen pepper window. if (!wm::IsWindowFullscreen(window)) { wm::MinimizeWindow(window); return true; } break; } case TOGGLE_MAXIMIZED: { if (key_code == ui::VKEY_F4 && shell->delegate()) { shell->delegate()->RecordUserMetricsAction( UMA_ACCEL_MAXIMIZE_RESTORE_F4); } shell->delegate()->ToggleMaximized(); return true; } case WINDOW_POSITION_CENTER: { aura::Window* window = wm::GetActiveWindow(); if (window) { wm::CenterWindow(window); return true; } break; } case ROTATE_WINDOWS: return HandleRotateWindows(); case ROTATE_SCREEN: return HandleRotateScreen(); case TOGGLE_DESKTOP_BACKGROUND_MODE: return HandleToggleDesktopBackgroundMode(); case TOGGLE_ROOT_WINDOW_FULL_SCREEN: return HandleToggleRootWindowFullScreen(); case DISPLAY_TOGGLE_SCALE: internal::MultiDisplayManager::ToggleDisplayScale(); return true; case MAGNIFY_SCREEN_ZOOM_IN: return HandleMagnifyScreen(1); case MAGNIFY_SCREEN_ZOOM_OUT: return HandleMagnifyScreen(-1); case MEDIA_NEXT_TRACK: return HandleMediaNextTrack(); case MEDIA_PLAY_PAUSE: return HandleMediaPlayPause(); case MEDIA_PREV_TRACK: return HandleMediaPrevTrack(); case POWER_PRESSED: // fallthrough case POWER_RELEASED: #if defined(OS_CHROMEOS) if (!base::chromeos::IsRunningOnChromeOS()) { // There is no powerd in linux desktop, so call the // PowerButtonController here. Shell::GetInstance()->power_button_controller()-> OnPowerButtonEvent(action == POWER_PRESSED, base::TimeTicks()); } #endif // We don't do anything with these at present on the device, // (power button evets are reported to us from powerm via // D-BUS), but we consume them to prevent them from getting // passed to apps -- see http://crbug.com/146609. return true; case LOCK_PRESSED: case LOCK_RELEASED: #if defined(OS_CHROMEOS) if (!base::chromeos::IsRunningOnChromeOS()) { // There is no powerd in linux desktop, so call the // PowerButtonController here. Shell::GetInstance()->power_button_controller()-> OnLockButtonEvent(action == LOCK_PRESSED, base::TimeTicks()); return true; } #endif // LOCK_PRESSED/RELEASED in debug only action that is meant for // testing lock behavior on linux desktop. If we ever reached // here (when you run a debug build on the device), pass it onto // apps. return false; #if !defined(NDEBUG) case PRINT_LAYER_HIERARCHY: return HandlePrintLayerHierarchy(); case PRINT_VIEW_HIERARCHY: return HandlePrintViewHierarchy(); case PRINT_WINDOW_HIERARCHY: return HandlePrintWindowHierarchy(); #endif default: NOTREACHED() << "Unhandled action " << action; } return false; } void AcceleratorController::SetBrightnessControlDelegate( scoped_ptr brightness_control_delegate) { internal::MultiDisplayManager* display_manager = static_cast( aura::Env::GetInstance()->display_manager()); // Install brightness control delegate only when internal // display exists. if (display_manager->HasInternalDisplay()) brightness_control_delegate_.swap(brightness_control_delegate); } void AcceleratorController::SetImeControlDelegate( scoped_ptr ime_control_delegate) { ime_control_delegate_.swap(ime_control_delegate); } void AcceleratorController::SetScreenshotDelegate( scoped_ptr screenshot_delegate) { screenshot_delegate_.swap(screenshot_delegate); } //////////////////////////////////////////////////////////////////////////////// // AcceleratorController, ui::AcceleratorTarget implementation: bool AcceleratorController::AcceleratorPressed( const ui::Accelerator& accelerator) { std::map::const_iterator it = accelerators_.find(accelerator); DCHECK(it != accelerators_.end()); return PerformAction(static_cast(it->second), accelerator); } void AcceleratorController::SwitchToWindow(int window) { Launcher* launcher = Launcher::ForPrimaryDisplay(); const LauncherItems& items = launcher->model()->items(); int item_count = launcher->model()->item_count(); int indexes_left = window >= 0 ? window : item_count; int found_index = -1; // Iterating until we have hit the index we are interested in which // is true once indexes_left becomes negative. for (int i = 0; i < item_count && indexes_left >= 0; i++) { if (items[i].type != TYPE_APP_LIST && items[i].type != TYPE_BROWSER_SHORTCUT) { found_index = i; indexes_left--; } } // There are two ways how found_index can be valid: a.) the nth item was // found (which is true when indexes_left is -1) or b.) the last item was // requested (which is true when index was passed in as a negative number). if (found_index >= 0 && (indexes_left == -1 || window < 0) && (items[found_index].status == ash::STATUS_RUNNING || items[found_index].status == ash::STATUS_CLOSED)) { // Then set this one as active. launcher->ActivateLauncherItem(found_index); } } void AcceleratorController::RegisterAccelerators( const AcceleratorData accelerators[], size_t accelerators_length) { for (size_t i = 0; i < accelerators_length; ++i) { ui::Accelerator accelerator(accelerators[i].keycode, accelerators[i].modifiers); accelerator.set_type(accelerators[i].trigger_on_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED); Register(accelerator, this); accelerators_.insert( std::make_pair(accelerator, accelerators[i].action)); } } void AcceleratorController::SetKeyboardBrightnessControlDelegate( scoped_ptr keyboard_brightness_control_delegate) { keyboard_brightness_control_delegate_ = keyboard_brightness_control_delegate.Pass(); } bool AcceleratorController::CanHandleAccelerators() const { return true; } } // namespace ash