table re-decoded to the ModeMFD bits + desktop J/K/L page cycle
The preset system was unwired by ONE defect in the message layer: the
SetPresetMode @004d1b24 table @0051dbf0 had been transcribed from the
section dump as BIG-endian dwords ({0x1e,0x01000000} instead of
{0x1e,0x01}), so a preset press set a garbage high bit -- and for group 1
items 3-4 / group 2 items 0-2 stomped the LIVE NonMapping / Intercom /
ModeSecondary* bits -- while the real page bits never moved. Ground
truth (section_dump.txt:72901-72908, little-endian + BTL4MODE.HPP [T0]):
set = ModeMFD{1,2,3}{Quad,Eng1-4} = 1<<(group*5+item), bits 0-14, fully
disjoint from the #6 secondary trio (bits 18-20); group 2 is MFD3, NOT a
duplicate of the secondary views.
What the 15 presets show (l4gauge.cfg): group = the MFD (Mfd1 lower left
/ Mfd2 upper center / Mfd3 lower right), item 0 = the btquad.pcx Quad
overview (up to 4 vehicleSubSystems cluster panels), items 1-4 = the
full-screen engineering-detail pages (bteng.pcx + prepEngr screens
group*4+1..4 + the cluster eng children: GENERATOR SELECT A-D, POWER
graph, COOLING loop, DAMAGE, ammo). Empty screens are authored per mech
(Blackhawk: 3/11/12 empty).
Authentic dispatch (streamed "L4" .CTL EventMappings, BT_CTRLMAP_LOG
dump): each MFD owns the 8-button RIO bank around it, MODE-MASK-gated --
Mfd1 = 0x08-0x0F, Mfd2 = 0x20-0x27, Mfd3 = 0x00-0x07. Quad page ->
direct-select buttons for the POPULATED eng pages (mapper msgs
Aux1Eng1-4 0x4-0x7 / Aux2* 0x9-0xC / Aux3* 0xE-0x11); eng page -> one
back-to-Quad button (0x3/0x8/0xD) + per-subsystem controls. These
records already install and fire on desktop (btinput passes the live
manager mask), so the NUMPAD profile's 0x20-0x27 keys page MFD2
authentically.
Port wiring (the #6 pattern): keys J/K/L -> actions Mfd1/2/3Cycle ->
gBTPresetCycle -> L4MechControlsMapper::CyclePresetModeNow(group) -- a
documented desktop shim (24 mode-dependent pod buttons don't fit a
keyboard) that cycles Quad -> populated Eng pages -> Quad, visiting
exactly the pod-reachable set; the body is the authentic SetPresetMode.
Dev-composite: BTDrawGaugeSurfaces now draws the Eng1-3 planes at their
sibling cells and skips any mono plane whose channel is BlankColor,
honoring the mode-driven reconfigure (RemapGraphicsPort) -- each dev
cell shows the ACTIVE page like the pod monitor. This supersedes and
removes the 2026-07-12 GAUGREND "frozen-dial" scaffold (forced all 15
page bits active under BT_DEV_GAUGES; it pinned the shared Eng plane on
the highest screen and ate the page flips).
Pixel-verified (BT_PRESET_TEST + BT_DEV_GAUGES_DOCK + BT_SHOT,
Blackhawk): all three MFDs page Quad -> SYSTEM NN eng details -> back to
Quad in lockstep with the [mode] preset mask log; group 0 skips the
authored-empty screen 3, group 2 skips 11/12. Un-regressed: N display
cycle (0x450421->0x490421->0x510421, page bits intact), M control mode,
CONTROLS.MAP 52 bindings parse clean.
Diags: BT_MODE_LOG ([mode] preset), BT_PRESET_TEST=<frame>.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
77 lines
3.4 KiB
C++
77 lines
3.4 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;
|
|
float elevTarget; // torso-elevation (pitch) target [-1,1]
|
|
int elevActive;
|
|
int turnAbsolute; // pad stick overrides the integrator outright
|
|
int twistAbsolute;
|
|
int elevAbsolute;
|
|
|
|
// 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 displayCycle; // Gitea #6: secondary schematic cycle (Damage/Critical/Heat)
|
|
int valve;
|
|
int flush; // Gitea #7: coolant flush HELD (InjectCoolant)
|
|
int configHold;
|
|
int genSel; // 0 = none, 4..7 = Generator A..D, 8 = reconnect
|
|
// Gitea #9: per-MFD preset-page cycle (desktop senders for SetPresetMode;
|
|
// index 0/1/2 = Mfd1 lower-left / Mfd2 upper-center / Mfd3 lower-right)
|
|
int mfdCycle[3];
|
|
};
|
|
|
|
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
|