// 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. #ifndef ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_IMPL_H_ #define ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_IMPL_H_ #include #include #include #include #include #include "ash/accelerators/accelerator_history_impl.h" #include "ash/accelerators/accelerator_table.h" #include "ash/accelerators/exit_warning_handler.h" #include "ash/accessibility/ui/accessibility_confirmation_dialog.h" #include "ash/ash_export.h" #include "ash/public/cpp/accelerators.h" #include "base/gtest_prod_util.h" #include "ui/base/accelerators/accelerator.h" #include "ui/base/accelerators/accelerator_map.h" #include "ui/base/ime/ash/input_method_manager.h" namespace ui { class AcceleratorManager; } namespace ash { struct AcceleratorData; class ExitWarningHandler; // See TabletModeVolumeAdjustType at tools/metrics/histograms/enums.xml. enum class TabletModeVolumeAdjustType { kAccidentalAdjustWithSwapEnabled = 0, kNormalAdjustWithSwapEnabled = 1, kAccidentalAdjustWithSwapDisabled = 2, kNormalAdjustWithSwapDisabled = 3, kMaxValue = kNormalAdjustWithSwapDisabled, }; // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. // Captures usage of Alt+[ and Alt+]. enum class WindowSnapAcceleratorAction { kCycleLeftSnapInClamshellNoOverview = 0, kCycleLeftSnapInClamshellOverview = 1, kCycleLeftSnapInTablet = 2, kCycleRightSnapInClamshellNoOverview = 3, kCycleRightSnapInClamshellOverview = 4, kCycleRightSnapInTablet = 5, kMaxValue = kCycleRightSnapInTablet, }; // Histogram for volume adjustment in tablet mode. ASH_EXPORT extern const char kTabletCountOfVolumeAdjustType[]; // UMA accessibility histogram names. ASH_EXPORT extern const char kAccessibilityHighContrastShortcut[]; ASH_EXPORT extern const char kAccessibilitySpokenFeedbackShortcut[]; ASH_EXPORT extern const char kAccessibilityScreenMagnifierShortcut[]; ASH_EXPORT extern const char kAccessibilityDockedMagnifierShortcut[]; // Name of histogram corresponding to |WindowSnapAcceleratorAction|. ASH_EXPORT extern const char kAccelWindowSnap[]; // AcceleratorControllerImpl provides functions for registering or unregistering // global keyboard accelerators, which are handled earlier than any windows. It // also implements several handlers as an accelerator target. class ASH_EXPORT AcceleratorControllerImpl : public ui::AcceleratorTarget, public AcceleratorController, public input_method::InputMethodManager::Observer { public: // Some Chrome OS devices have volume up and volume down buttons on their // side. We want the button that's closer to the top/right to increase the // volume and the button that's closer to the bottom/left to decrease the // volume, so we use the buttons' location and the device orientation to // determine whether the buttons should be swapped. struct SideVolumeButtonLocation { // The button can be at the side of the keyboard or the display. Then value // of the region could be kVolumeButtonRegionKeyboard or // kVolumeButtonRegionScreen. std::string region; // Side info of region. The value could be kVolumeButtonSideLeft, // kVolumeButtonSideRight, kVolumeButtonSideTop or kVolumeButtonSideBottom. std::string side; }; // TestApi is used for tests to get internal implementation details. class TestApi { public: explicit TestApi(AcceleratorControllerImpl* controller); TestApi(const TestApi&) = delete; TestApi& operator=(const TestApi&) = delete; ~TestApi() = default; // If |controller_->tablet_mode_volume_adjust_timer_| is running, stops it, // runs its task, and returns true. Otherwise returns false. [[nodiscard]] bool TriggerTabletModeVolumeAdjustTimer(); // Registers the specified accelerators. void RegisterAccelerators(const AcceleratorData accelerators[], size_t accelerators_length); // Returns whether the action for this accelerator is enabled. bool IsActionForAcceleratorEnabled(const ui::Accelerator& accelerator); // Returns the corresponding accelerator data if |action| maps to a // deprecated accelerator, otherwise return nullptr. const DeprecatedAcceleratorData* GetDeprecatedAcceleratorData( AcceleratorAction action); // Accessor to accelerator confirmation dialog. AccessibilityConfirmationDialog* GetConfirmationDialog(); // Provides access to the ExitWarningHandler. ExitWarningHandler* GetExitWarningHandler(); AcceleratorControllerImpl::SideVolumeButtonLocation side_volume_button_location() { return controller_->side_volume_button_location_; } void SetSideVolumeButtonFilePath(base::FilePath path); void SetSideVolumeButtonLocation(const std::string& region, const std::string& side); private: AcceleratorControllerImpl* controller_; // Not owned. }; // Fields of the side volume button location info. static constexpr const char* kVolumeButtonRegion = "region"; static constexpr const char* kVolumeButtonSide = "side"; // Values of kVolumeButtonRegion. static constexpr const char* kVolumeButtonRegionKeyboard = "keyboard"; static constexpr const char* kVolumeButtonRegionScreen = "screen"; // Values of kVolumeButtonSide. static constexpr const char* kVolumeButtonSideLeft = "left"; static constexpr const char* kVolumeButtonSideRight = "right"; static constexpr const char* kVolumeButtonSideTop = "top"; static constexpr const char* kVolumeButtonSideBottom = "bottom"; AcceleratorControllerImpl(); AcceleratorControllerImpl(const AcceleratorControllerImpl&) = delete; AcceleratorControllerImpl& operator=(const AcceleratorControllerImpl&) = delete; ~AcceleratorControllerImpl() override; // A list of possible ways in which an accelerator should be restricted before // processing. Any target registered with this controller should respect // restrictions by calling GetAcceleratorProcessingRestriction() during // processing. enum AcceleratorProcessingRestriction { // Process the accelerator normally. RESTRICTION_NONE, // Don't process the accelerator. RESTRICTION_PREVENT_PROCESSING, // Don't process the accelerator and prevent propagation to other targets. RESTRICTION_PREVENT_PROCESSING_AND_PROPAGATION }; // input_method::InputMethodManager::Observer overrides: void InputMethodChanged(input_method::InputMethodManager* manager, Profile* profile, bool show_message) override; // Registers global keyboard accelerators for the specified target. If // multiple targets are registered for any given accelerator, a target // registered later has higher priority. void Register(const std::vector& accelerators, ui::AcceleratorTarget* target); // Unregisters the specified keyboard accelerator for the specified target. void Unregister(const ui::Accelerator& accelerator, ui::AcceleratorTarget* target); // Unregisters all keyboard accelerators for the specified target. void UnregisterAll(ui::AcceleratorTarget* target); // AcceleratorControllerImpl: bool Process(const ui::Accelerator& accelerator) override; bool IsDeprecated(const ui::Accelerator& accelerator) const override; bool PerformActionIfEnabled(AcceleratorAction action, const ui::Accelerator& accelerator) override; bool OnMenuAccelerator(const ui::Accelerator& accelerator) override; bool IsRegistered(const ui::Accelerator& accelerator) const override; AcceleratorHistoryImpl* GetAcceleratorHistory() override; bool DoesAcceleratorMatchAction(const ui::Accelerator& accelerator, AcceleratorAction action) override; // Returns true if the |accelerator| is preferred. A preferred accelerator // is handled before being passed to an window/web contents, unless // the window is in fullscreen state. bool IsPreferred(const ui::Accelerator& accelerator) const; // Returns true if the |accelerator| is reserved. A reserved accelerator // is always handled and will never be passed to an window/web contents. bool IsReserved(const ui::Accelerator& accelerator) const; // Provides access to the ExitWarningHandler for testing. ExitWarningHandler* GetExitWarningHandlerForTest() { return &exit_warning_handler_; } // Overridden from ui::AcceleratorTarget: bool AcceleratorPressed(const ui::Accelerator& accelerator) override; bool CanHandleAccelerators() const override; // A confirmation dialog will be shown the first time an accessibility feature // is enabled using the specified accelerator key sequence. Only one dialog // will be shown at a time, and will not be shown again if the user has // selected "accept" on a given dialog. The dialog was added to ensure that // users would be aware of the shortcut they have just enabled, and to prevent // users from accidentally triggering the feature. The dialog is currently // shown when enabling the following features: high contrast, full screen // magnifier, docked magnifier and screen rotation. The shown dialog is stored // as a weak pointer in the variable |confirmation_dialog_| below. void MaybeShowConfirmationDialog(int window_title_text_id, int dialog_text_id, base::OnceClosure on_accept_callback, base::OnceClosure on_cancel_callback); private: // A map for looking up actions from accelerators. using AcceleratorActionMap = ui::AcceleratorMap; // Initializes the accelerators this class handles as a target. void Init(); // Registers the specified accelerators. void RegisterAccelerators(const AcceleratorData accelerators[], size_t accelerators_length); // Registers the deprecated accelerators and their replacing new ones. void RegisterDeprecatedAccelerators(); // Returns true if there is an action for |accelerator| and it is enabled. bool IsActionForAcceleratorEnabled(const ui::Accelerator& accelerator) const; // Returns whether |action| can be performed. The |accelerator| may provide // additional data the action needs. bool CanPerformAction(AcceleratorAction action, const ui::Accelerator& accelerator) const; // Performs the specified action. The |accelerator| may provide additional // data the action needs. void PerformAction(AcceleratorAction action, const ui::Accelerator& accelerator); // Returns whether performing |action| should consume the key event. bool ShouldActionConsumeKeyEvent(AcceleratorAction action); // Get the accelerator restriction for the given action. Supply an |action| // of -1 to get restrictions that apply for the current context. AcceleratorProcessingRestriction GetAcceleratorProcessingRestriction( int action) const; // If |accelerator| is a deprecated accelerator, it performs the appropriate // deprecated accelerator pre-handling. // Returns PROCEED if the accelerator's action should be performed (i.e. if // |accelerator| is not a deprecated accelerator, or it's an enabled // deprecated accelerator), and STOP otherwise (if the accelerator is a // disabled deprecated accelerator). enum class AcceleratorProcessingStatus { PROCEED, STOP }; AcceleratorProcessingStatus MaybeDeprecatedAcceleratorPressed( AcceleratorAction action, const ui::Accelerator& accelerator) const; // Returns true if |source_device_id| corresponds to the internal keyboard or // an internal uncategorized input device. bool IsInternalKeyboardOrUncategorizedDevice(int source_device_id) const; // Returns true if |side_volume_button_location_| is in agreed format and // values. bool IsValidSideVolumeButtonLocation() const; // Returns true if the side volume buttons should be swapped. See // SideVolumeButonLocation for the details. bool ShouldSwapSideVolumeButtons(int source_device_id) const; // Read the side volume button location info from local file under // kSideVolumeButtonLocationFilePath, parse and write it into // |side_volume_button_location_|. void ParseSideVolumeButtonLocationInfo(); // The metrics recorded include accidental volume adjustments (defined as a // sequence of volume button events in close succession starting with a // volume-up event but ending with an overall-decreased volume, or vice versa) // or normal volume adjustments w/o SwapSideVolumeButtonsForOrientation // feature enabled. void UpdateTabletModeVolumeAdjustHistogram(); // Starts |tablet_mode_volume_adjust_timer_| while see VOLUME_UP or // VOLUME_DOWN acceleration action when in tablet mode. void StartTabletModeVolumeAdjustTimer(AcceleratorAction action); std::unique_ptr accelerator_manager_; // A tracker for the current and previous accelerators. std::unique_ptr accelerator_history_; // Handles the exit accelerator which requires a double press to exit and // shows a popup with an explanation. ExitWarningHandler exit_warning_handler_; // A map from accelerators to the AcceleratorAction values, which are used in // the implementation. AcceleratorActionMap accelerators_; std::map actions_with_deprecations_; std::set deprecated_accelerators_; // Actions allowed when the user is not signed in. std::set actions_allowed_at_login_screen_; // Actions allowed when the screen is locked. std::set actions_allowed_at_lock_screen_; // Actions allowed when the power menu is opened. std::set actions_allowed_at_power_menu_; // Actions allowed when a modal window is up. std::set actions_allowed_at_modal_window_; // Preferred actions. See accelerator_table.h for details. std::set preferred_actions_; // Reserved actions. See accelerator_table.h for details. std::set reserved_actions_; // Actions which will be repeated while holding the accelerator key. std::set repeatable_actions_; // Actions allowed in app mode. std::set actions_allowed_in_app_mode_; // Actions allowed in pinned mode. std::set actions_allowed_in_pinned_mode_; // Actions disallowed if there are no windows. std::set actions_needing_window_; // Actions that can be performed without closing the menu (if one is present). std::set actions_keeping_menu_open_; // Holds a weak pointer to the accessibility confirmation dialog. base::WeakPtr confirmation_dialog_; // Path of the file that contains the side volume button location info. It // should always be kSideVolumeButtonLocationFilePath. But it is allowed to be // set to different paths in test. base::FilePath side_volume_button_location_file_path_; // Stores the location info of side volume buttons. SideVolumeButtonLocation side_volume_button_location_; // Started when VOLUME_DOWN or VOLUME_UP accelerator action is seen while in // tablet mode. Runs UpdateTabletModeVolumeAdjustHistogram() to record // metrics. base::OneShotTimer tablet_mode_volume_adjust_timer_; // True if volume adjust starts with VOLUME_UP action. bool volume_adjust_starts_with_up_ = false; // The initial volume percentage when volume adjust starts. int initial_volume_percent_ = 0; }; } // namespace ash #endif // ASH_ACCELERATORS_ACCELERATOR_CONTROLLER_IMPL_H_