#pragma once #include #include #include #include #include #include "alvin/error.hpp" #include "alvin/keys.hpp" #include "alvin/types.hpp" namespace alvin { enum class InputBackend { Auto, WlrVirtual, // Wayland zwlr_virtual_pointer_v1 + zwp_virtual_keyboard_v1 (Hyprland, sway, other wlroots) LibEi, // libei via xdg-desktop-portal RemoteDesktop (GNOME, KDE) UInput, // /dev/uinput kernel virtual devices (any Linux session; needs write access) SendInput, // Win32 }; std::string_view toString(InputBackend backend) noexcept; struct InputOptions { InputBackend backend = InputBackend::Auto; // LibEi only: token from a previous session (Input::restoreToken()) that // lets the portal skip its permission dialog. std::string restoreToken; // How long to wait for the user to answer a portal permission dialog. std::chrono::milliseconds permissionTimeout = std::chrono::minutes(2); }; // Synthesises mouse and keyboard events. // // Coordinates passed to moveTo() are global desktop coordinates in logical // pixels, matching Monitor::bounds and WindowInfo::bounds. class Input { public: // Picks a backend (or uses options.backend). With Auto, the environment // variable ALVIN_INPUT_BACKEND=wlr|libei|uinput|sendinput overrides the choice. static Result> create(const InputOptions& options = {}); virtual ~Input() = default; Input(const Input&) = delete; Input& operator=(const Input&) = delete; virtual InputBackend backend() const = 0; virtual Status moveTo(Point p) = 0; virtual Status moveBy(int dx, int dy) = 0; virtual Status buttonDown(MouseButton button) = 0; virtual Status buttonUp(MouseButton button) = 0; // Wheel notches; positive dy scrolls down, positive dx scrolls right. virtual Status scroll(int dx, int dy) = 0; virtual Status keyDown(Key key) = 0; virtual Status keyUp(Key key) = 0; // Types UTF-8 text using the active keyboard layout (or a synthesized one). virtual Status typeText(std::string_view utf8) = 0; // Portal-backed sessions can hand out a token to skip the dialog next time. virtual std::string restoreToken() const { return {}; } // ---- Convenience helpers built on the primitives above ---- Status click(MouseButton button = MouseButton::Left, int count = 1); Status clickAt(Point p, MouseButton button = MouseButton::Left, int count = 1); Status drag(Point from, Point to, MouseButton button = MouseButton::Left); Status keyPress(Key key); // Presses keys in order, releases in reverse: chord({Key::LeftCtrl, Key::C}). Status chord(std::initializer_list keys); // Same, from a string such as "ctrl+shift+esc". Status chord(std::string_view chord); // Delay inserted between the down/up halves of clicks and key presses. // Some applications drop events that arrive with zero spacing. void setEventDelay(std::chrono::milliseconds delay) { eventDelay_ = delay; } std::chrono::milliseconds eventDelay() const { return eventDelay_; } protected: Input() = default; void pause() const; private: std::chrono::milliseconds eventDelay_{8}; }; } // namespace alvin