blob: c9a34946e831fc7b0fde84bb669c3d2f02593569 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_EVENTS_PERIPHERAL_CUSTOMIZATION_EVENT_REWRITER_H_
#define ASH_EVENTS_PERIPHERAL_CUSTOMIZATION_EVENT_REWRITER_H_
#include "ash/ash_export.h"
#include "ash/public/mojom/input_device_settings.mojom-forward.h"
#include "ash/public/mojom/input_device_settings.mojom.h"
#include "ash/system/input_device_settings/input_device_settings_metrics_manager.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "ui/events/event.h"
#include "ui/events/event_dispatcher.h"
#include "ui/events/event_rewriter.h"
namespace ash {
class InputDeviceSettingsController;
// PeripheralCustomizationEventRewriter recognizes and rewrites events from mice
// and graphics tablets to arbitrary `ui::KeyEvent`s configured by the user via
// the Settings SWA.
class ASH_EXPORT PeripheralCustomizationEventRewriter
: public ui::EventRewriter {
public:
using ButtonRemappingList =
std::vector<std::pair<mojom::ButtonPtr, mojom::RemappingActionPtr>>;
enum class DeviceType { kMouse, kGraphicsTablet };
enum class PeripheralCustomizationMetricsType {
kMouse,
kGraphicsTablet,
kGraphicsTabletPen
};
struct DeviceIdButton {
int device_id;
mojom::ButtonPtr button;
DeviceIdButton(int device_id, mojom::ButtonPtr button);
DeviceIdButton(DeviceIdButton&& device_id_button);
~DeviceIdButton();
DeviceIdButton& operator=(DeviceIdButton&& device_id_button);
friend bool operator<(const DeviceIdButton& left,
const DeviceIdButton& right);
};
struct RemappingActionResult {
raw_ref<mojom::RemappingAction> remapping_action;
PeripheralCustomizationMetricsType peripheral_kind;
RemappingActionResult(mojom::RemappingAction& remapping_action,
PeripheralCustomizationMetricsType peripheral_kind);
RemappingActionResult(RemappingActionResult&& result);
~RemappingActionResult();
};
explicit PeripheralCustomizationEventRewriter(
InputDeviceSettingsController* input_device_settings_controller);
PeripheralCustomizationEventRewriter(
const PeripheralCustomizationEventRewriter&) = delete;
PeripheralCustomizationEventRewriter& operator=(
const PeripheralCustomizationEventRewriter&) = delete;
~PeripheralCustomizationEventRewriter() override;
// Starts observing and blocking mouse events for `device_id`. Notifies
// observers via `OnMouseButtonPressed` whenever an event
void StartObservingMouse(
int device_id,
mojom::CustomizationRestriction customization_restriction);
// Starts observing and blocking graphics tablet events for `device_id`.
// Notifies observers via `OnGraphicsTabletButtonPressed` whenever an event is
// received.
void StartObservingGraphicsTablet(
int device_id,
mojom::CustomizationRestriction customization_restriction);
// Stops observing for all devices of every type.
void StopObserving();
// ui::EventRewriter:
ui::EventDispatchDetails RewriteEvent(
const ui::Event& event,
const Continuation continuation) override;
const base::flat_map<int, mojom::CustomizationRestriction>&
mice_to_observe() {
return mice_to_observe_;
}
const base::flat_map<int, mojom::CustomizationRestriction>&
graphics_tablets_to_observe() {
return graphics_tablets_to_observe_;
}
private:
// Notifies observers if the given `mouse_event` is a remappable button for
// the given `device_type`. Returns true if the event should be discarded.
bool NotifyMouseEventObserving(const ui::MouseEvent& mouse_event,
DeviceType device_type);
// Notifies observers if the given `mouse_wheel_event` is a remappable button
// for the given `device_type`. Returns true if the event should be discarded.
bool NotifyMouseWheelEventObserving(
const ui::MouseWheelEvent& mouse_wheel_event,
DeviceType device_type);
// Notifies observers if the given `key_event` is a remappable button for
// the given `device_type`. Returns true if the event should be discarded.
bool NotifyKeyEventObserving(const ui::KeyEvent& key_event,
DeviceType device_type);
// Returns if the button is customizable.
bool IsButtonCustomizable(const ui::KeyEvent& key_event);
// Rewrites the given event that came from `button` within the
// `rewritten_event` param. Returns true if the original event should be
// discarded.
bool RewriteEventFromButton(
const ui::Event& event,
const mojom::Button& button,
std::vector<std::unique_ptr<ui::Event>>& rewritten_event);
ui::EventDispatchDetails RewriteMouseEvent(const ui::MouseEvent& mouse_event,
const Continuation continuation);
ui::EventDispatchDetails RewriteMouseWheelEvent(
const ui::MouseWheelEvent& mouse_event,
const Continuation continuation);
ui::EventDispatchDetails RewriteKeyEvent(const ui::KeyEvent& key_event,
const Continuation continuation);
std::optional<DeviceType> GetDeviceTypeToObserve(int device_id);
std::optional<RemappingActionResult> GetRemappingAction(
int device_id,
const mojom::Button& button);
void UpdatePressedButtonMap(
mojom::ButtonPtr button,
const ui::Event& original_event,
const std::vector<std::unique_ptr<ui::Event>>& rewritten_event);
// Removes the set of remapped modifiers from the event that should be
// discarded.
void RemoveRemappedModifiers(ui::Event& event);
// Applies all remapped modifiers.
void ApplyRemappedModifiers(ui::Event& event);
std::unique_ptr<ui::Event> CloneEvent(const ui::Event& event);
base::flat_map<int, mojom::CustomizationRestriction> mice_to_observe_;
base::flat_map<int, mojom::CustomizationRestriction>
graphics_tablets_to_observe_;
// Maintains a list of currently pressed buttons and the flags that should
// be applied to other events processed.
base::flat_map<DeviceIdButton, int> device_button_to_flags_;
raw_ptr<InputDeviceSettingsController> input_device_settings_controller_;
// Emit all metrics.
std::unique_ptr<InputDeviceSettingsMetricsManager> metrics_manager_;
};
} // namespace ash
#endif // ASH_EVENTS_PERIPHERAL_CUSTOMIZATION_EVENT_REWRITER_H_