Summary
Implement a unified native input subsystem for MiniAV to capture real-time user/system input events: keyboard, mouse, gamepad, touch (multi-touch / gestures), and MIDI (note/control/system messages). Web is explicitly out-of-scope for this phase.
Goals
- Cross-platform (Windows, macOS, Linux) unified C API.
- Event callback model with low-latency, monotonic timestamps.
- Device enumeration + hotplug notifications.
- Normalized key / button / axis / touch / MIDI representations.
- Support both push (OS callbacks) and poll backends internally.
- Efficient lock-free ring buffer between backend threads and user callback.
- Touch abstraction (multi-touch points) where available.
- MIDI: raw message bytes + parsed helpers (status, channel, data bytes, SysEx support).
- Optional gamepad vibration (where supported).
Out of Scope (for now)
- Web, Android, iOS.
- Gesture recognition (pinch/rotate) beyond raw touch points.
- High-level MIDI routing/thru.
API Proposal (Draft)
#pragma once
#include "miniav_types.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum MiniAVInputDeviceType {
MINIAV_INPUT_DEVICE_KEYBOARD = 1,
MINIAV_INPUT_DEVICE_MOUSE = 2,
MINIAV_INPUT_DEVICE_GAMEPAD = 3,
MINIAV_INPUT_DEVICE_TOUCH = 4,
MINIAV_INPUT_DEVICE_MIDI = 5,
MINIAV_INPUT_DEVICE_UNKNOWN = 0xFF
} MiniAVInputDeviceType;
typedef enum MiniAVInputEventKind {
MINIAV_INPUT_EVENT_KEY_DOWN = 1,
MINIAV_INPUT_EVENT_KEY_UP,
MINIAV_INPUT_EVENT_MOUSE_MOVE,
MINIAV_INPUT_EVENT_MOUSE_BUTTON_DOWN,
MINIAV_INPUT_EVENT_MOUSE_BUTTON_UP,
MINIAV_INPUT_EVENT_MOUSE_WHEEL,
MINIAV_INPUT_EVENT_GAMEPAD_BUTTON_DOWN,
MINIAV_INPUT_EVENT_GAMEPAD_BUTTON_UP,
MINIAV_INPUT_EVENT_GAMEPAD_AXIS,
MINIAV_INPUT_EVENT_TOUCH_BEGIN,
MINIAV_INPUT_EVENT_TOUCH_MOVE,
MINIAV_INPUT_EVENT_TOUCH_END,
MINIAV_INPUT_EVENT_TOUCH_CANCEL,
MINIAV_INPUT_EVENT_TOUCH_FRAME, // frame delimiter batching points
MINIAV_INPUT_EVENT_MIDI_MESSAGE,
MINIAV_INPUT_EVENT_DEVICE_ADDED,
MINIAV_INPUT_EVENT_DEVICE_REMOVED
} MiniAVInputEventKind;
typedef struct MiniAVInputDeviceInfo {
const char* device_id;
const char* name;
MiniAVInputDeviceType type;
uint32_t vendor_id;
uint32_t product_id;
} MiniAVInputDeviceInfo;
typedef enum MiniAVTouchPhase {
MINIAV_TOUCH_PHASE_UNKNOWN = 0,
MINIAV_TOUCH_PHASE_BEGIN,
MINIAV_TOUCH_PHASE_MOVE,
MINIAV_TOUCH_PHASE_END,
MINIAV_TOUCH_PHASE_CANCEL
} MiniAVTouchPhase;
typedef struct MiniAVTouchPoint {
uint64_t touch_id; // stable per contact
float x; // normalized 0..1 or pixels (flagged)
float y;
float pressure; // 0..1 if available else -1
float major_radius; // -1 if unknown
float minor_radius; // -1 if unknown
MiniAVTouchPhase phase;
} MiniAVTouchPoint;
typedef struct MiniAVMidiMessage {
uint64_t timestamp_ns;
uint8_t status;
uint8_t data1;
uint8_t data2;
const uint8_t* sysex; // if SysEx, points to buffer (owned until event released)
uint32_t sysex_length;
uint8_t is_sysex;
uint8_t channel; // 0-15 if channel voice
} MiniAVMidiMessage;
typedef enum MiniAVKey {
MINIAV_KEY_UNKNOWN = 0,
// (expand as needed)
MINIAV_KEY_A, MINIAV_KEY_B, MINIAV_KEY_C, MINIAV_KEY_Z = MINIAV_KEY_A + 25,
MINIAV_KEY_0, MINIAV_KEY_1, MINIAV_KEY_9 = MINIAV_KEY_0 + 9,
MINIAV_KEY_ENTER,
MINIAV_KEY_ESCAPE,
MINIAV_KEY_SPACE,
MINIAV_KEY_LEFT, MINIAV_KEY_RIGHT, MINIAV_KEY_UP, MINIAV_KEY_DOWN,
MINIAV_KEY_SHIFT_LEFT, MINIAV_KEY_SHIFT_RIGHT,
MINIAV_KEY_CTRL_LEFT, MINIAV_KEY_CTRL_RIGHT,
MINIAV_KEY_ALT_LEFT, MINIAV_KEY_ALT_RIGHT,
MINIAV_KEY_SUPER_LEFT, MINIAV_KEY_SUPER_RIGHT,
MINIAV_KEY_F1, MINIAV_KEY_F12 = MINIAV_KEY_F1 + 11
} MiniAVKey;
typedef struct MiniAVInputEvent {
uint64_t timestamp_ns;
const char* device_id;
MiniAVInputDeviceType device_type;
MiniAVInputEventKind kind;
union {
struct { MiniAVKey key; } key;
struct { int32_t x; int32_t y; int32_t dx; int32_t dy; } mouse_move;
struct { int32_t x; int32_t y; int32_t dx; int32_t dy; uint8_t button; } mouse_button;
struct { float wheel_x; float wheel_y; int32_t pixel_delta_x; int32_t pixel_delta_y; } mouse_wheel;
struct { uint16_t button; uint8_t pressed; } gamepad_button;
struct { uint16_t axis; float value; } gamepad_axis;
struct { const MiniAVTouchPoint* points; uint32_t count; } touch; // for individual + frame events
struct { MiniAVMidiMessage msg; } midi;
struct { MiniAVInputDeviceInfo info; } device_change;
} data;
} MiniAVInputEvent;
typedef void (*MiniAVInputEventCallback)(const MiniAVInputEvent* event, void* user);
typedef struct MiniAVInputContext__* MiniAVInputContextHandle;
MiniAVResultCode MiniAV_Input_EnumerateDevices(MiniAVInputDeviceInfo** devices, uint32_t* count);
MiniAVResultCode MiniAV_Input_FreeDeviceList(MiniAVInputDeviceInfo* devices, uint32_t count);
MiniAVResultCode MiniAV_Input_CreateContext(MiniAVInputContextHandle* ctx);
MiniAVResultCode MiniAV_Input_DestroyContext(MiniAVInputContextHandle ctx);
MiniAVResultCode MiniAV_Input_Start(MiniAVInputContextHandle ctx, MiniAVInputEventCallback cb, void* user);
MiniAVResultCode MiniAV_Input_Stop(MiniAVInputContextHandle ctx);
MiniAVResultCode MiniAV_Input_GamepadSetVibration(MiniAVInputContextHandle ctx, const char* device_id, float low_freq, float high_freq, uint32_t duration_ms);
#ifdef __cplusplus
}
#endif
Backend Strategy
- Windows: Raw Input (keyboard/mouse), WM_POINTER / WM_TOUCH, XInput + GameInput (gamepad), WinRT MIDI (preferred) with fallback to WinMM.
- macOS: CGEventTap (KB/mouse), NSTouch (trackpad), GameController.framework (gamepad), CoreMIDI (MIDI).
- Linux: evdev + libudev (keyboard/mouse/gamepad/touch), multitouch via ABS_MT* events, ALSA sequencer (MIDI). Fallback X11 for basic KB/mouse if no /dev/input access.
- Touch: Only if device exposes MT events or platform API supports it.
- Ring buffer size configurable (e.g. env MINIAV_INPUT_RING=4096).
Threading Model
- Each backend has one dispatcher thread (message loop / epoll / run loop).
- Events written to lock-free SPSC ring; consumer thread optionally merges TOUCH_* into FRAME delimiting events before invoking user callback on calling thread or dedicated dispatch thread (configurable).
Device ID Format (Proposal)
- Windows: "win:<handle_hex>"
- macOS: "mac:" or GCController vendor/product
- Linux: "linux:evdev::"
- MIDI: Append ":midi:<endpoint_unique>"
Memory Rules
- Strings stable for context lifetime.
- Touch point arrays owned until callback returns (user must copy).
- SysEx data freed after callback returns.
Acceptance Criteria
- Enumerate returns devices with correct categorization.
- Receive key down/up, mouse move, button, wheel, gamepad button/axis, touch begin/move/end, MIDI note-on/off/control-change, device add/remove.
- Timestamps monotonic and strictly non-decreasing per device.
- Stress test (rapid input 5k events/sec) without drops (unless ring overflow -> documented error metric).
- Clean shutdown without leaks (validated by ASAN on Linux, Instruments on macOS, heap leak detector on Windows).
Risk / Notes
- Permissions: Linux access to /dev/input requires group (input) or elevated; document fallback.
- High DPI / coordinate normalization differences; decide pixel vs normalized (current: store raw pixels; normalization optional later).
- MIDI SysEx large messages may need pooled buffers (future optimization).
Initial Task Breakdown
- Define public header + enums (above).
- Implement core input context + ring buffer (platform-agnostic).
- Windows backend: Raw Input + XInput + minimal MIDI (WinMM).
- Linux backend: evdev + udev hotplug + ALSA MIDI.
- macOS backend: CGEventTap + GameController + CoreMIDI.
- Touch handling: implement per platform where available.
- Gamepad vibration API (Windows/XInput + macOS if supported).
- Add logging + error translation layer.
- Add basic tests (simulated injection where possible / mock).
- Documentation + examples (print events).
Future Enhancements
- Batch event callback variant.
- State snapshot API (poll last known state).
- Gesture synthesis (pinch/zoom).
- Mapping layer for customizable key/gamepad remapping.
Summary
Implement a unified native input subsystem for MiniAV to capture real-time user/system input events: keyboard, mouse, gamepad, touch (multi-touch / gestures), and MIDI (note/control/system messages). Web is explicitly out-of-scope for this phase.
Goals
Out of Scope (for now)
API Proposal (Draft)
Backend Strategy
Threading Model
Device ID Format (Proposal)
Memory Rules
Acceptance Criteria
Risk / Notes
Initial Task Breakdown
Future Enhancements