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.