From 80222c5ea741052a2709e101bfb2dca42a3578fd Mon Sep 17 00:00:00 2001 From: Cyd Date: Fri, 31 Jul 2026 20:49:23 -0500 Subject: [PATCH] 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 --- README.md | 3 +- docs/INPUT-INTEGRATION.md | 161 +++++++++++++++++++++++++++++++++++++ docs/OUTPUT-INTEGRATION.md | 3 +- 3 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 docs/INPUT-INTEGRATION.md diff --git a/README.md b/README.md index cb34e19..702b350 100644 --- a/README.md +++ b/README.md @@ -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/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/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`) | | [`docs/reference/`](docs/reference/) | Cockpit overlay art & the legacy labeling pipeline | | [`legacy/`](legacy/) | Original C++/vJoy implementation, kept as reference | diff --git a/docs/INPUT-INTEGRATION.md b/docs/INPUT-INTEGRATION.md new file mode 100644 index 0000000..0766ddf --- /dev/null +++ b/docs/INPUT-INTEGRATION.md @@ -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 `0x00–0x47`, 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 `0x50–0x5F`, external `0x60–0x6F` (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 1–11 (or 1–96 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`** (`(value−16383)×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 ` 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 1–11, 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). diff --git a/docs/OUTPUT-INTEGRATION.md b/docs/OUTPUT-INTEGRATION.md index 59a799c..9b7f657 100644 --- a/docs/OUTPUT-INTEGRATION.md +++ b/docs/OUTPUT-INTEGRATION.md @@ -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 mean what, and how to feed them. The exact wire grammar lives 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