Custom input device

micro::input_device is the abstract base class that keyboard and mouse are built on. Derive from it to add support for any custom hardware — joysticks, gamepads, touch surfaces, or completely synthetic input sources.

Interface

class input_device {
public:
    virtual ~input_device() = default;

    // Human-readable name, e.g. "gamepad_0":
    [[nodiscard]] virtual const char* name() const noexcept = 0;

    // Copy current state to previous state — called once per frame:
    virtual void save_state() = 0;

    // Process one SDL event — called for every event polled that frame:
    virtual void handle_event(const SDL_Event& event) = 0;
};

The window calls save_state() at the start of each frame before processing events, then handle_event() for every SDL event. This pattern lets you implement pressed/released detection by comparing current and previous state.

Attaching to a window

auto dev = std::make_shared<my_device>();
win.attach(dev);

The window stores a weak reference. The device is automatically unregistered when the last shared_ptr owner is destroyed (typically when dev goes out of scope), so no manual detach is needed.

Example — minimal gamepad stub

struct gamepad : micro::input_device {
    struct state { bool a{}; bool b{}; };

    const char* name() const noexcept override { return "gamepad"; }

    void save_state() override {
        prev_ = current_;
    }

    void handle_event(const SDL_Event& e) override {
        // examine e.type and update current_ ...
    }

    bool is_a_pressed() const { return current_.a && !prev_.a; }
    bool is_b_pressed() const { return current_.b && !prev_.b; }

private:
    state current_{};
    state prev_{};
};

auto pad = std::make_shared<gamepad>();
win.attach(pad);

win.run([&](float) {
    if (pad->is_a_pressed()) player.jump();
});

Access to SDL events

handle_event receives a const SDL_Event&. Include <SDL3/SDL_events.h> in your implementation file to inspect event types and fields.