docs: input integration guide (cockpit -> RIOJoy -> game)

Companion to OUTPUT-INTEGRATION.md: the three input surfaces (ViGEm x360
pad, SendInput scancode keyboard/mouse, RioGamepad HID), per-button routing
kinds incl. the fixed 11-button pad order, axis calibration + routing with
the triggers-are-buttons trap and the shipped Descent pattern, per-game
strategy, profile building/triggers workflow, benchless testing, checklist.
Cross-linked from README and the output guide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-31 20:49:23 -05:00
co-authored by Claude Fable 5
parent 44b636ddd3
commit 80222c5ea7
3 changed files with 165 additions and 2 deletions
+2 -1
View File
@@ -23,7 +23,8 @@ Red Planet — talk to the RIO directly and do not use this app.)
| [`docs/PLAN.md`](docs/PLAN.md) | Full modernization plan | | [`docs/PLAN.md`](docs/PLAN.md) | Full modernization plan |
| [`docs/PROTOCOL.md`](docs/PROTOCOL.md) | RIO wire format + `iRIO` input-map reference | | [`docs/PROTOCOL.md`](docs/PROTOCOL.md) | RIO wire format + `iRIO` input-map reference |
| [`docs/FEEDBACK.md`](docs/FEEDBACK.md) | Game→cockpit feedback endpoint (lamps + plasma over pipe/UDP, rumble) | | [`docs/FEEDBACK.md`](docs/FEEDBACK.md) | Game→cockpit feedback endpoint (lamps + plasma over pipe/UDP, rumble) |
| [`docs/OUTPUT-INTEGRATION.md`](docs/OUTPUT-INTEGRATION.md) | Integrator's guide: lamp address map, plasma display model, per-game recipes | | [`docs/INPUT-INTEGRATION.md`](docs/INPUT-INTEGRATION.md) | Integrator's guide: cockpit→game — routing kinds, pad/axis mapping, profile building |
| [`docs/OUTPUT-INTEGRATION.md`](docs/OUTPUT-INTEGRATION.md) | Integrator's guide: game→cockpit — lamp address map, plasma display model, recipes |
| _RIO board hardware & firmware_ | Moved to the [TeslaRel410 `restoration/`](https://gitea.mysticmachines.com/VWE/TeslaRel410/src/branch/main/restoration) archive — board photos, schematics, GAL decode (`restoration/rio-hardware`) and the RIO 4.3 board firmware (`restoration/rio-firmware`) | | _RIO board hardware & firmware_ | Moved to the [TeslaRel410 `restoration/`](https://gitea.mysticmachines.com/VWE/TeslaRel410/src/branch/main/restoration) archive — board photos, schematics, GAL decode (`restoration/rio-hardware`) and the RIO 4.3 board firmware (`restoration/rio-firmware`) |
| [`docs/reference/`](docs/reference/) | Cockpit overlay art & the legacy labeling pipeline | | [`docs/reference/`](docs/reference/) | Cockpit overlay art & the legacy labeling pipeline |
| [`legacy/`](legacy/) | Original C++/vJoy implementation, kept as reference | | [`legacy/`](legacy/) | Original C++/vJoy implementation, kept as reference |
+161
View File
@@ -0,0 +1,161 @@
# Input integration guide (cockpit → RIOJoy → game)
How a game receives the cockpit's **inputs** — the 72 lighted buttons, two
16-key keypads, and 5 analog axes — and how to build the profile that maps
them. This is the mirror of [OUTPUT-INTEGRATION.md](OUTPUT-INTEGRATION.md)
(game → cockpit); the wire protocol lives in [PROTOCOL.md](PROTOCOL.md), the
profile/auto-switch model in [PLAN.md](PLAN.md).
## What a game sees
RIOJoy translates cockpit events into ordinary Windows input, per profile,
through three surfaces (all can be active at once — each button picks its
route):
| Surface | What the game sees | When |
|---|---|---|
| **Virtual Xbox 360 pad** (ViGEm) | a normal XInput controller: 11 buttons, D-pad, 2 sticks, 2 triggers | default on Windows 10/11 when ViGEmBus is installed |
| **Keyboard / mouse** (`SendInput`) | scancode keystrokes with modifiers; relative mouse moves + clicks | any button routed to a key/mouse action |
| **RioGamepad HID** | a native 6-axis, 96-button, 1-hat joystick | fallback when ViGEm is absent; the XP flavor |
The sink is chosen at activation: ViGEm → RioGamepad feeder → none (keyboard
and mouse always work). Most games — XInput and DirectInput alike — see the
Xbox 360 pad as a standard controller; the practical limit is its **11
mappable buttons**, so keyboard routing carries everything beyond that.
## The input inventory
- **72 lighted buttons**, RIO addresses `0x000x47`, grouped into five MFD
clusters and four columns — the physical map is in
[OUTPUT-INTEGRATION.md](OUTPUT-INTEGRATION.md#address-map-functional-groups).
- **Two 4×4 keypads**: internal `0x500x5F`, external `0x600x6F` (key label →
address = base + hex digit; no lamps).
- **5 analog inputs** — joystick X/Y, throttle, left pedal, right pedal —
calibrated into **6 virtual axes** (X, Y, Z, Rx, Ry, Rz), each `0..32766`
with center `16383`.
## Per-button routing
Every mapped address carries one action (the `iRIO` word, PROTOCOL.md §5).
The editor exposes these as the **Action** kinds:
| Kind | What happens on press/release |
|---|---|
| **Keyboard** | key down/up by **scancode** (so DOS-era and raw-input games see it), with optional Shift/Ctrl/Alt held around it and the extended-key flag for nav keys |
| **Joystick** | virtual pad button 111 (or 196 on the RioGamepad HID) |
| **Hat** | the POV hat / D-pad direction (up/right/down/left; release = centered) |
| **Mouse** | relative move in clean 50-px steps (up/right/down/left) or left/right click — the legacy build's mixed-up move deltas are fixed in the port |
| **RIO command** | internal: axis recalibrations/resets, version/check request, diagnostic toggles — useful on a spare cockpit button so recalibration never needs the desktop |
| **Lit** flag | lamp follows the button (dim idle, bright pressed). Also marks the lamp as *profile-owned*, which shields it from the feedback endpoint (see OUTPUT-INTEGRATION.md) |
### The Xbox 360 button map
RIO joystick buttons are assigned in this fixed order — pick low numbers for
the game's most important actions:
| RIO joy button | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Pad button | A | B | X | Y | LB | RB | Back | Start | L3 | R3 | Guide |
The hat maps to the D-pad. Buttons past 11 are dropped by the pad — route
those to the keyboard instead. (On the RioGamepad HID all 96 buttons exist
natively and no mapping table applies.)
## Axes
### Calibration (per profile)
`Calibration` holds per-axis invert flags and `EnableZR`:
- **Joystick X/Y** auto-range from observed travel with a small deadzone.
- **Throttle (Z)** is the ratcheted lever; calibrated so the detent rest
position reads **0**, full forward `32766` — i.e. it is naturally
**unipolar**.
- **Pedals** feed Rx/Ry directly, or — with `EnableZR` — mix into a single
rudder axis: `Rz = 16383 left/2 + right/2` (Rx/Ry then idle).
### Routing onto the pad (`AxisRouting`, JSON-only)
Each of the six axes picks a `Target` and `Mode`
(`src/RioJoy.Core/Output/AxisRoutingConfig.cs`; null section = the legacy
default routing):
| Axis | Default target | Conversion |
|---|---|---|
| X | LeftThumbX | Centered |
| Y | LeftThumbY | Centered |
| Z | LeftTrigger | trigger byte `value×255/32766` |
| Rx | RightThumbX | Centered |
| Ry | RightThumbY | Centered |
| Rz | RightTrigger | trigger byte |
Modes for thumb targets: **`Centered`** (`(value16383)×2` → stick range) for
axes that rest mid-travel, **`UnipolarPositive`** (rest 0 = stick center,
32766 = stick max — only the upper half is used) for the ratcheted throttle.
`Target: "None"` suppresses an axis entirely.
**The triggers-are-buttons trap:** many games hard-bind the pad triggers to
fire/actions. If the throttle rides `LeftTrigger` (the default), advancing the
throttle *fires*. The shipped Descent profile
([`profiles/descent-d1x.json`](../profiles/descent-d1x.json)) is the worked
example: throttle → `RightThumbY` `UnipolarPositive`, rudder mix →
`RightThumbX`, pedals `None`, keeping both triggers free for the game.
## Choosing a strategy per game
- **Modern XInput game** — pad buttons + axes for the flight controls, keyboard
routing for the long tail (MFD pages, systems). Check the game's own binding
UI to see the pad.
- **DOS / emulated game (DOSBox, source ports)** — mostly keyboard routing (it
arrives as scancodes, which DOSBox maps cleanly); axes via the pad if the
emulator supports a controller, else map coarse throttle steps to keys.
- **Legacy DirectInput sim** — the x360 pad appears as a DirectInput device
too; if the game needs more than 11 buttons on the *stick itself*, prefer
keyboard routing or run the RioGamepad HID (96 native buttons).
- **Anything with a clickable cockpit** — mouse routing gives you cursor
nudges and clicks from cockpit buttons.
## Building the profile
1. **Create/edit** from the tray: *Edit profile*. The editor shows the cockpit
panel in its functional groups; click a button, set its label, action,
modifiers, and **Lit**, then Apply. Save writes the config.
2. **Live check**: with the RIO (or vRIO) connected, physical presses light the
panel and the axis gauges move — before any game is involved. The "Send
button output to the PC" toggle turns real keystroke injection on when you
want to test into an editor/notepad.
3. **Triggers**: comma-separated executable names that auto-activate the
profile when their window is foreground (`d1x-rebirth, descent`). Matching
is basename, case-insensitive, `.exe` optional. First matching profile
wins; DOSBox-hosted games all share the DOSBox exe name (rename per game or
switch manually); native games (Firestorm, Red Planet) go in
`NativeGameExecutables` instead — RIOJoy releases the ports for them.
4. **RIO port**: leave `(app default)`, or a COM name, or `pipe:vrio` for the
emulator.
5. **JSON-only settings** (edit `%APPDATA%\RIOJoy\config.json`): `AxisRouting`,
`Calibration` fine points, `PlasmaComPort`/`PlasmaGreeting`, and the
`Feedback` section (see FEEDBACK.md).
6. **Legacy import**: `RioJoy.Tray.exe --import-profile <file>` merges a
single-profile JSON document; the `Import .ini` menu converts an original
`RIO.ini` (buttons, inverts, greeting).
## Testing without hardware or game
- **vRIO** (`pipe:vrio`): click buttons on the emulator's panel and watch them
arrive — the editor lights up, the pad reacts.
- **joy.cpl** (Game Controllers): shows the virtual pad's axes/buttons moving.
- Keyboard routes: open Notepad, enable the editor's output toggle, press
cockpit buttons.
## Checklist for a new game
1. Find the game's real executable name (foreground window process) → Triggers.
2. Decide the axis story first: does the game hard-use triggers? If yes, route
the throttle to a thumb axis `UnipolarPositive` (copy the Descent pattern).
3. Map the few primary actions to pad buttons 111, everything else to
keyboard; mark cockpit-lit buttons **Lit**.
4. Set `EnableZR` if the game wants one rudder axis rather than two pedals.
5. Live-check in the editor, then in-game; bind a spare cockpit button to
*RIO command → recalibrate* for the cabinet.
6. Add the `Feedback` section if the game will drive lamps/plasma back
(OUTPUT-INTEGRATION.md).
+2 -1
View File
@@ -5,7 +5,8 @@ through RIOJoy: the lighted buttons (lamps) and the plasma/VFD text display.
This is the integrator's view — what the hardware can show, which addresses This is the integrator's view — what the hardware can show, which addresses
mean what, and how to feed them. The exact wire grammar lives in mean what, and how to feed them. The exact wire grammar lives in
[FEEDBACK.md](FEEDBACK.md); the RIO serial protocol in [FEEDBACK.md](FEEDBACK.md); the RIO serial protocol in
[PROTOCOL.md](PROTOCOL.md). [PROTOCOL.md](PROTOCOL.md); the mirror direction (cockpit inputs → game) in
[INPUT-INTEGRATION.md](INPUT-INTEGRATION.md).
## The four output channels ## The four output channels