131 lines
4.1 KiB
Markdown
131 lines
4.1 KiB
Markdown
# 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
|
|
|
|
```c
|
|
extern input_t INPUT;
|
|
// INPUT.actions[INPUT_ACTION_COUNT] -- all action states
|
|
// INPUT.platform -- platform-specific data
|
|
```
|
|
|
|
## Reading actions (game code)
|
|
|
|
```c
|
|
// 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
|
|
|
|
```c
|
|
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
|
|
|
|
```c
|
|
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`):
|
|
|
|
```c
|
|
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 | -- | -- |
|