Data produced by the game controller input module
One entity per connected, matching device, published every capture tick regardless of activity -
even a device nobody is touching still gets its EntityState in the frame. Whether that entity
also carries any events that tick depends on TrackEdgeDetection and SendAxisData below.
Entity
| Field | Value |
|---|---|
| Name | The DirectInput driver’s reported device name (for example "Logitech G29 Racing Wheel"), or a synthetic "XInput Gamepad (Player N)" / "XInput Controller (Player N)" for an XInput slot |
| Id | A hash of the device’s instance GUID (DirectInput) or of the synthetic per-slot GUID (XInput) |
Button events
Each button transition is one ButtonPressEvent, with
button_name and state mapped from this module’s own four internal states:
| Internal state | Meaning | Published state |
|---|---|---|
Down | First tick the button reads pressed | BUTTON_STATE_PRESSED |
Hold | Held from a previous tick | BUTTON_STATE_HOLD |
Released | First tick the button reads released | BUTTON_STATE_RELEASED |
Up | Not pressed | Not published at all |
A button held down publishes a fresh Hold event every tick for as long as it stays pressed, not
once. Filter to BUTTON_STATE_PRESSED if only the rising edge matters to your use case.
Button names: DirectInput resolves whatever name the driver reports ("Button 0", "Button 1",
… for an unbranded pad; a real name for some branded controllers). XInput uses a fixed table:
A, B, X, Y, LB, RB, Back, Start, LS, RS, DPad Up, DPad Down, DPad Left,
DPad Right.
Axis events
When SendAxisData is on (default), every active device also publishes one
JsonEventData named ControllerAxes every tick, unconditionally
- even a device nobody is touching still sends its (unchanging) axis values every tick. This is
flagged as an open question in the module’s own source rather than a settled design decision; if
the event volume from an idle controller is a problem for your use case, disabling
SendAxisDatais the only control available today. The JSON shape is not the same between the two device types:
DirectInput - one field per axis the device actually reports, all normalized to -1..1 except POV switches:
| Field | Meaning |
|---|---|
x, y, z | Primary axes |
rx, ry, rz | Rotational axes |
slider0, slider1, … | Slider controls, if the device has any |
pov0, pov1, … | Point-of-view (hat switch) controllers, in degrees / 100 as a fraction 0..1, or -1 when centered/not pressed |
XInput - always exactly these six fields, all normalized to -1..1 (triggers 0..1):
| Field | Meaning |
|---|---|
left_x, left_y | Left stick |
right_x, right_y | Right stick |
left_trigger, right_trigger | Analog triggers |
A consumer reading ControllerAxes must key its parsing off which entity (and therefore which
device type) the event belongs to; the two schemas share no field names.
Timing
Button edges and axis values are only computed and published when this module’s own capture
call runs, at the Interval setting’s cadence - see
Configure for why this, not PollIntervalMs, is what
actually bounds how quickly a button press is seen.