Generic joystick / HOTAS / pedals support: DirectInput 8 layer + capture wizard

Tester ask: configure non-Xbox controllers.  New L4JOY layer (DI8):
enumerates every non-XInput game device (up to 4), DIJOYSTATE2 polling
with range normalization, reacquire-on-loss, 3s hot-plug re-enum.
XInput devices are excluded via the documented RawInput IG_ VID/PID
check (live-verified skipping a real XBOX360 pad -- no double-feed).

bindings.txt grows joydev/joyaxis/joybutton/joyhat rows (device slots
by name substring or ordinal; axes X..RZ/SL0/SL1 with invert/slew/
deadzone; hats as 4-direction buttons with diagonal chords).  PadRIO
runs them through the existing channel/event machinery -- per-binding
edge arrays release automatically on detach (the #24 rule), and a
direct throttle axis maps full lever travel onto the 0..1 channel
while the gait detent still snaps a lever parked in the walk/run dead
band.

BT_JOYCONFIG=1 (joyconfig.bat) runs a console capture wizard: move
each control when prompted (stick/twist/throttle/fire), invert derived
from the move direction, hat look cluster auto-added, output written
between markers in bindings.txt with the rest of the file preserved.

Legacy L4DINPUT DIJoystick (L4CONTROLS=DIJOYSTICK) untouched.
Verified: grammar accept/reject per line, XInput-exclusion live,
30s in-mission no-device polling clean.  Awaiting a tester with real
stick hardware for axis verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-23 16:36:32 -05:00
co-authored by Claude Opus 4.8
parent 86e387b6c7
commit c2ee7299b2
12 changed files with 1531 additions and 6 deletions
+11
View File
@@ -197,6 +197,17 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
? (std::ios::out | std::ios::app) : std::ios::out);
std::cout.rdbuf(logfile.rdbuf());
// BT_JOYCONFIG=1: the generic-joystick capture wizard (flight sticks /
// HOTAS / pedals -- L4JOY.h). Console prompts detect which device/axis
// the player moves for each pod control and write the joystick section
// of content\bindings.txt, then the boot continues into the game with
// the new bindings live (PadRIO loads the file after this point).
if (getenv("BT_JOYCONFIG") != NULL && *getenv("BT_JOYCONFIG") != '0')
{
extern int BTJoyConfigWizard(void);
BTJoyConfigWizard();
}
// MP wire-format probe (env BT_NET_PROBE=1): print the exact packet constants
// the console emulator (tools/btconsole.py) must speak, computed from OUR build
// (message IDs chain across class enums at compile time -- never hand-compute).