Files
BT411/game/reconstructed/btinput.hpp
T
arcattackandClaude Fable 5 980c9cd7e5 Input remap: CONTROLS.MAP binding engine + XInput gamepad support
The pod's controls reach the game through the RIO serial board; on a
desktop that hardware is a keyboard shim of hardcoded GetAsyncKeyState
reads.  New binding engine (game/reconstructed/btinput.cpp) maps PC keys
and an XInput pad onto the authentic channels through a user-editable
file (content/CONTROLS.MAP, community-suggested grammar, corrected):

  key/pad -> button <addr>   real buttonGroup emissions, mirroring the
                             RIO convention exactly (press a+1 w/ mode
                             mask saved, release -a-1 w/ saved mask;
                             L4CTRL.cpp:2470-2520) -- aux/preset banks,
                             hotbox, panic, reverse thrust all reachable
  key/pad -> axis            Throttle rate (lever), pedals/JoystickX
                             deflect (turn/twist) into the existing
                             virtual-controls integrators (feel, gait
                             detent, spring-centering all unchanged)
  keypad pilot|external <n>  keyboardGroup key values ('0'-'F')
  pckey <char>               any authentic 1995 typed hotkey
  action <name>              port dev controls (view, all-stop, ...)

Keys claimed by a binding are SUPPRESSED from the legacy WM_CHAR/KEYUP
feed -- ends the historic double-dispatch ('w' drove AND selected pilot
0; F5's key-up value 0x74 aliased to the 't' hotkey; letter key-ups fed
the developer fake-event dispatcher).  Unbound keys keep their authentic
meaning.  The dual-use 'V' is split: V = view toggle, B = look behind.

Default profile = WASD classic (compiled-in twin; delete the file to
restore).  CONTROLS_NUMPAD.MAP ships the corrected community layout
(keypads are NOT buttons 0x50-0x6F -- that space doesn't exist; no
clickable cockpit exists so everything needs a binding; keyboard fire
buttons added; 0x36/0x37 are hotbox not 'config'; missiles moved off
Ctrl).  XInput loads dynamically (1_4 -> 9_1_0), disconnected-pad
probing rate-limited; pad sticks write the axes as absolute positions
(the spring is physical), triggers/buttons per the file.

Verified live: bindings load (43), W and NumPad8 drive (speedDemand 0 ->
61.5), X all-stop (spd -> 0), aux-bank emission (D1 -> [input] 0x2f
PRESS/release under the numpad profile), suppression both directions
(posted 'r' reaches [keych], posted 'w' swallowed), full-keyspace
WM_CHAR+WM_KEYUP fuzz x3 survived with sim advancing, XInput graceful
with no pad, 2-node relay session un-regressed (full ladder + UDP).
Pad-in-hand testing still needs a physical controller.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:09:36 -05:00

69 lines
3.0 KiB
C++

//#############################################################################
// btinput.hpp -- the desktop input binding engine (CONTROLS.MAP + XInput).
//
// The pod's controls are a fixed physical device set (stick, throttle lever,
// pedals, ~44 lamp buttons, keypads) reaching the game through the
// LBE4ControlsManager push model. On a desktop there is no RIO, so this
// engine maps PC keys and an XInput gamepad onto the SAME channels:
//
// axes -> the virtual-controls integrators in mech4.cpp (lever / turn
// stick / torso twist), exactly where the BT_KEY_BRIDGE writes
// the analog values the RIO would have produced
// buttons -> real buttonGroup[addr] ForceUpdates (aux banks, hotbox,
// panic, throttle-head...) so the AUTHENTIC handlers fire;
// the four joystick fire buttons (0x40/45/46/47) drive the
// bring-up fire channels instead (see btinput.cpp note)
// keypads -> keyboardGroup[KeyboardPilot/KeyboardExternal] key values
// pckey -> keyboardGroup[KeyboardPC] (any authentic '+'-style hotkey)
// actions -> the port-side dev controls (view toggle, all-stop, ...)
//
// Bindings load from content/CONTROLS.MAP at first poll; if the file is
// absent the compiled-in WASD-classic profile (identical text) applies.
// Keys claimed by a binding are SUPPRESSED from the legacy WM_CHAR/-KEYUP
// keyboard feed (BTInputSuppressKey), ending the historic double-dispatch
// (W = drive AND pilot-select, F5 keyup aliasing to 't' = pilot 3, ...).
//#############################################################################
#ifndef BTINPUT_HPP
#define BTINPUT_HPP
struct BTInputState
{
// analog demands (consumed by the mech4 virtual-controls block)
float leverRate; // throttle lever sweep, per second (+fwd/-back)
float turnTarget; // turn-stick deflection target [-1,1]
int turnActive; // any turn input held (else spring-center)
float twistTarget; // torso-twist deflection target [-1,1]
int twistActive;
int turnAbsolute; // pad stick overrides the integrator outright
int twistAbsolute;
// the four pod joystick fire buttons (levels)
int fireTrigger; // 0x40 Main
int firePinky; // 0x45
int fireThumbLow; // 0x46 Middle
int fireThumbHigh; // 0x47 Upper
// port-side actions (levels; consumers keep their own edge detectors)
int viewToggle;
int lookBehind;
int allStop;
int modeCycle;
int valve;
int configHold;
int genSel; // 0 = none, 4..7 = Generator A..D, 8 = reconnect
};
extern BTInputState gBTInput;
// Poll everything (keys + pad), evaluate the binding table, fire button /
// keypad edges into the controls manager. Call ONCE per sim frame from the
// player drive block. Handles the foreground-focus guard (BT_KEY_NOFOCUS)
// internally.
void BTInputPoll(float dt);
// The legacy keyboard feed asks before dispatching a typed character /
// key-up value: nonzero = this key is claimed by a binding, swallow it.
extern "C" int BTInputSuppressKey(unsigned int key_value, int is_char);
#endif // BTINPUT_HPP