Files
BT411/engine/MUNGA_L4/L4JOY.h
T
arcattackandClaude Opus 4.8 c2ee7299b2 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>
2026-07-23 16:36:32 -05:00

70 lines
2.6 KiB
C

#pragma once
//###########################################################################
//
// L4JOY -- generic-joystick reader (DirectInput 8) for the glass cockpit.
//
// PadRIO reads XInput; this layer adds every OTHER game device Windows
// knows -- flight sticks, HOTAS throttles, twist-sticks, rudder pedals --
// through DirectInput 8 (the standard generic-HID game API). It exposes
// up to BTJoyMaxDevices attached devices as normalized state blocks; the
// PadRIO poll maps them onto the pod's control channels through the
// joydev/joyaxis/joybutton/joyhat rows of bindings.txt (L4PADBINDINGS.h)
// -- the same binding machinery the XInput pad uses.
//
// XInput-class devices are EXCLUDED (they'd double-feed through both
// APIs): a DirectInput device whose VID/PID appears in a RawInput device
// path containing the "IG_" marker is an XInput device (the documented
// wbem-free detection).
//
// This is DISTINCT from the legacy L4DINPUT.cpp DIJoystick (the 1995-era
// single-device `Joystick` engine interface, reachable only through the
// old L4CONTROLS=DIJOYSTICK profile) -- that path is left untouched.
//
// BT_JOYCONFIG=1 runs the interactive capture wizard at boot (console
// prompts; writes the joystick section of bindings.txt). BT_JOY_LOG=1
// logs device attach/detach and the resolved bindings.
//
//###########################################################################
enum
{
BTJoyMaxDevices = 4,
BTJoyAxisCount = 8, // X Y Z RX RY RZ SL0 SL1 (DIJOYSTATE2 order)
BTJoyButtonCount = 32, // buttons exposed to bindings (DI carries 128)
BTJoyHatCount = 4,
};
struct BTJoyDeviceState
{
int attached;
float axis[BTJoyAxisCount]; // normalized -1..1 (raw; deadzones
// are the binding layer's business)
unsigned buttons; // bit n = button n held
int hat[BTJoyHatCount]; // POV in centidegrees; -1 = centered
char name[64]; // product name ("T.16000M", ...)
};
//
// Lifecycle. Init is lazy-safe (Poll calls it); returns the attached
// non-XInput device count. Re-enumeration (hot-plug) happens inside Poll
// on a ~3 s cadence whenever nothing is attached or a device was lost.
//
int BTJoyInit(void);
void BTJoyShutdown(void);
void BTJoyPoll(void);
int BTJoyDeviceCount(void);
const BTJoyDeviceState *BTJoyDevice(int index); // NULL out of range/detached
//
// Case-insensitive product-name substring match -> device index, -1 none.
//
int BTJoyFindDevice(const char *name_substring);
//
// The BT_JOYCONFIG capture wizard (console UI; called from btl4main before
// the frontend). Returns 0 if it wrote a config, nonzero on abort/no-device.
//
int BTJoyConfigWizard(void);