Files
dusk/.claude/input.md
T
2026-06-16 10:15:59 -05:00

4.1 KiB

Input System

Source: src/dusk/input/, platform layers in src/dusk<platform>/input/

Architecture

The input system has two layers:

  1. Action layer (inputaction_t) -- named gameplay inputs, e.g. UP, DOWN, ACCEPT, CANCEL. This is what game code reads.
  2. 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 frame
  • inputButtonGetValuePlatform() -- 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 via inputGetDeadzoneSDL2)

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 -- --