chromium/ui/events/ash/keyboard_modifier_event_rewriter.h

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef UI_EVENTS_ASH_KEYBOARD_MODIFIER_EVENT_REWRITER_H_
#define UI_EVENTS_ASH_KEYBOARD_MODIFIER_EVENT_REWRITER_H_

#include <map>
#include <memory>
#include <variant>

#include "base/memory/raw_ptr.h"
#include "ui/events/ash/event_rewriter_utils.h"
#include "ui/events/ash/mojom/modifier_key.mojom-shared.h"
#include "ui/events/ash/mojom/modifier_key.mojom.h"
#include "ui/events/event_rewriter.h"

namespace ash::input_method {
class ImeKeyboard;
}  // namespace ash::input_method

namespace ui {

class KeyboardCapability;
class KeyboardLayoutEngine;

// This rewriter remaps modifier key events based on settings/preferences.
// Also, updates modifier flags along with the remapping not only
// for KeyEvent instances but also motion Event instances, such as mouse
// events and touch events.
class KeyboardModifierEventRewriter : public EventRewriter {
 public:
  // UnmappedCode are keys which do not have a corresponding DomCode for their
  // meaning which are used for modifier remapping.
  enum class UnmappedCode {
    kRightAlt,
  };

  using PhysicalCode = std::variant<DomCode, UnmappedCode>;
  struct RemappedKey {
    PhysicalCode code;
    DomKey key;
    KeyboardCode key_code;
  };

  // Delegate interface to inject chrome dependencies.
  class Delegate {
   public:
    virtual ~Delegate() = default;

    // If per-device settings is disabled, returns the remapped modifier value
    // from prefs by looking up the given |pref_name|. If per-device settings is
    // enabled, returns the remapped modifier value for |device_id| and
    // |modifier_key|.
    // TODO(dpad): Remove |pref_name| once fully transitioned to per-device
    // settings.
    virtual std::optional<mojom::ModifierKey> GetKeyboardRemappedModifierValue(
        int device_id,
        mojom::ModifierKey modifier_key,
        const std::string& pref_name) const = 0;

    // Returns true only if the the key event was rewritten to ALTGR. For most
    // cases, it is expected that this function returns false as most key events
    // do not involve ALTGR. Returns false if SuppressModifierKeyRewrites was
    // called to suppress modifier rewrites.
    virtual bool RewriteModifierKeys() = 0;
  };

  KeyboardModifierEventRewriter(std::unique_ptr<Delegate> delegate,
                                KeyboardLayoutEngine* keyboard_layout_engine,
                                KeyboardCapability* keyboard_capability,
                                ash::input_method::ImeKeyboard* ime_keyboard);
  KeyboardModifierEventRewriter(const KeyboardModifierEventRewriter&) = delete;
  KeyboardModifierEventRewriter& operator=(
      const KeyboardModifierEventRewriter&) = delete;
  ~KeyboardModifierEventRewriter() override;

  // EventRewriter:
  EventDispatchDetails RewriteEvent(const Event& event,
                                    const Continuation continuation) override;

 private:
  std::unique_ptr<Event> RewritePressKeyEvent(const KeyEvent& event);
  std::optional<RemappedKey> RemapPressKey(const KeyEvent& event);
  std::unique_ptr<Event> RewriteReleaseKeyEvent(const KeyEvent& event);
  std::unique_ptr<KeyEvent> BuildRewrittenEvent(const KeyEvent& event,
                                                const RemappedKey& remapped);
  int RewriteModifierFlags(int flags) const;

  std::optional<PhysicalCode> GetRemappedPhysicalCode(DomCode code,
                                                      int device_id) const;

  std::unique_ptr<Delegate> delegate_;
  const raw_ptr<KeyboardLayoutEngine> keyboard_layout_engine_;
  const raw_ptr<KeyboardCapability> keyboard_capability_;
  const raw_ptr<ash::input_method::ImeKeyboard> ime_keyboard_;

  // Map from physical keys to the affected modifiers on press.
  std::map<internal::PhysicalKey, RemappedKey> remapped_keys_;
  std::map<internal::PhysicalKey, EventFlags> pressed_modifier_keys_;
  bool altgr_latch_ = false;
};

}  // namespace ui

#endif  // UI_EVENTS_ASH_KEYBOARD_MODIFIER_EVENT_REWRITER_H_