4.1 KiB
Input System
Source: src/dusk/input/, platform layers in src/dusk<platform>/input/
Architecture
The input system has two layers:
- Action layer (
inputaction_t) -- named gameplay inputs, e.g. UP, DOWN, ACCEPT, CANCEL. This is what game code reads. - Button layer (
inputbutton_t) -- physical hardware inputs, e.g. keyboard key, gamepad button, analog axis, mouse axis. Multiple buttons can bind to the same action (the highest value wins).
The platform layer implements two hooks:
inputUpdatePlatform()-- read hardware state once per frameinputButtonGetValuePlatform()-- return the analog value [0.0, 1.0] for a given button
Global state
extern input_t INPUT;
// INPUT.actions[INPUT_ACTION_COUNT] -- all action states
// INPUT.platform -- platform-specific data
Reading actions (game code)
// Analog value this frame (0.0 - 1.0)
float_t inputGetCurrentValue(inputaction_t action);
// Analog value last frame
float_t inputGetLastValue(inputaction_t action);
// Boolean helpers (built on current/last values)
bool_t inputIsDown(inputaction_t action);
bool_t inputWasDown(inputaction_t action);
bool_t inputPressed(inputaction_t action); // was up, now down
bool_t inputReleased(inputaction_t action); // was down, now up
// 2D axis helpers
void inputAxis2D(
inputaction_t horiz,
inputaction_t vert,
vec2 out
);
float_t inputAngle2D(inputaction_t horiz, inputaction_t vert);
void inputAxis(inputaction_t action, float_t *out);
// Deadzone filter (applied to raw axis values)
float_t inputDeadzone(float_t value, float_t deadzone);
Binding buttons to actions
void inputBind(inputaction_t action, inputbutton_t button);
Each platform's init function calls inputBind to wire its hardware
buttons to the standard action IDs. Game code should never need to call
inputBind -- it is set up once during platform init.
Button types
INPUT_BUTTON_TYPE_KEYBOARD // SDL scancode (SDL2 targets only)
INPUT_BUTTON_TYPE_POINTER // Mouse axes: X, Y, Z, WHEEL_X, WHEEL_Y
INPUT_BUTTON_TYPE_TOUCH // Touch (defined, not fully implemented)
INPUT_BUTTON_TYPE_GAMEPAD // Digital gamepad buttons
INPUT_BUTTON_TYPE_GAMEPAD_AXIS // Analog axes (-1.0 to 1.0 internally)
Events
Each action has onPressed and onReleased event callbacks. Subscribe
via the event system (see .claude/events.md):
eventSubscribe(&INPUT.actions[ACTION_ACCEPT].onPressed, myCallback, NULL);
Platform implementations
SDL2 (src/dusksdl2/input/)
Handles Linux, Knulli, and PSP (PSP adds its own button mapping layer on top of SDL2).
- Keyboard: SDL scancode array from
SDL_GetKeyboardState() - Pointer: normalized mouse position (0.0-1.0), scroll axes
- Gamepad: first available
SDL_GameController; axis values normalized to [-1.0, 1.0] with deadzone (default 0.2f viainputGetDeadzoneSDL2)
Dolphin -- GameCube / Wii (src/duskdolphin/input/)
Uses libogc PAD API. No keyboard or pointer input -- trying to use
those button types is a compile-time #error.
- Gamepad:
PAD_ScanPads()+PAD_ButtonsHeld()for pad 0 - Axes: left stick X/Y, C-stick X/Y, L/R triggers (6 total)
- Deadzone: hardcoded 0.2f
- Default bindings set at init: D-pad/L-stick = directional actions, A = ACCEPT, B = CANCEL, X = CONSOLE, Start = RAGEQUIT
PSP (src/duskpsp/input/)
Layered on top of SDL2. inputInitPSP() remaps SDL2 controller button
constants to PSP button names, then calls inputBind to wire them:
| PSP button | SDL2 constant |
|---|---|
| Cross | SDL_CONTROLLER_BUTTON_A |
| Circle | SDL_CONTROLLER_BUTTON_B |
| Triangle | SDL_CONTROLLER_BUTTON_Y |
| Square | SDL_CONTROLLER_BUTTON_X |
| L / R | SDL_CONTROLLER_BUTTON_LEFTSHOULDER / RIGHTSHOULDER |
| L-Stick | SDL_CONTROLLER_AXIS_LEFTX/Y |
Platform capability notes
| Feature | Linux/Knulli | PSP | GameCube/Wii |
|---|---|---|---|
| Keyboard | Yes (SDL2) | No | No |
| Pointer/Mouse | Yes (SDL2) | No | No |
| Gamepad | Yes (SDL2) | Yes (SDL2) | Yes (PAD) |
| Analog axes | Yes | L-Stick only | L-Stick, C-Stick, Triggers |
| Touch | Defined, not implemented | -- | -- |