Fix the backtick crash (a /FORCE-hidden linkage bug) + backtick = view toggle

The crash (any typed key in a glass session; found via the backtick report):
the merge-reconciliation stand-down declared extern BTRIODevicePresent at
BLOCK scope inside the extern-C BTInputSuppressKey -- the declaration
inherited C linkage, _BTRIODevicePresent went UNRESOLVED, and /FORCE bound
the call to garbage (cdb: wild call into Sensor::DefaultData from
LBE4ControlsManager::Execute's suppression check).  The tolerated-LNK2019
batch hid the new unresolved external -- the exact CLAUDE.md /FORCE trap.
Fix: the extern moved to file scope (C++ linkage); link verified clean of
_BTRIODevicePresent.

Backtick feature (per Cyd: backtick = 1st/3rd person): PadRIO edge-detects
VK_OEM_3 in its poll (focus-guarded, message-path-free) and the mech4 view
block consumes it beside the V action (which stands down with the binding
engine in glass mode).  Verified live: two real presses -> [view] COCKPIT
eyepoint -> [view] external chase, game alive.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-18 19:52:36 -05:00
co-authored by Claude Fable 5
parent 22d7a0e3b7
commit 122fb7bccb
3 changed files with 54 additions and 2 deletions
+35
View File
@@ -20,6 +20,23 @@
PadRIO *PadRIO::activeInstance = NULL;
//
// Pending backtick view-toggle edges (set in Poll, consumed by the game's
// view-toggle block through BTPadViewToggleEdge).
//
int gBTPadViewToggleEdges = 0;
int
BTPadViewToggleEdge(void)
{
if (gBTPadViewToggleEdges > 0)
{
--gBTPadViewToggleEdges;
return 1;
}
return 0;
}
//
// XInput normalization: thumbs to -1..1 past the stock deadzone, triggers
// to 0..1 past the stock threshold.
@@ -258,6 +275,24 @@ void
//-----------------------------------------------------------------
//
int focused = ProcessHasFocus();
//
// The backtick view toggle (per Cyd: ` = 1st/3rd person in the glass
// cockpit). Edge-detected here (async poll, message-path-free) and
// consumed by the game's view-toggle block via BTPadViewToggleEdge.
//
{
static int s_backtickWas = 0;
int backtick_held = focused &&
(GetAsyncKeyState(VK_OEM_3) & 0x8000) != 0;
if (backtick_held && !s_backtickWas)
{
extern int gBTPadViewToggleEdges;
++gBTPadViewToggleEdges;
}
s_backtickWas = backtick_held;
}
float slewDelta[PadBindingProfile::ChannelCount];
int deflectHeld[PadBindingProfile::ChannelCount];
memset(slewDelta, 0, sizeof(slewDelta));
+6 -2
View File
@@ -42,6 +42,12 @@ struct BTDriveInput { float throttle; float turn; int forced; int fire; int fire
int keyFwd; int keyBack; int keyLeft; int keyRight; int allStop; };
extern BTDriveInput gBTDrive;
// FILE scope (C++ linkage!): a block-scope extern inside the extern "C"
// BTInputSuppressKey inherited C linkage -> _BTRIODevicePresent went
// UNRESOLVED, /FORCE bound the call to garbage (Sensor::DefaultData), and
// ANY typed key crashed the glass build (found via the backtick report).
extern int BTRIODevicePresent(void);
//=============================================================================
// Binding model
//=============================================================================
@@ -742,7 +748,6 @@ void
// engine on for debugging, matching the bridges' force-on.
//
{
extern int BTRIODevicePresent(void);
static const char *s_kbEnv = getenv("BT_KEY_BRIDGE");
int engine_owns = s_kbEnv ? (*s_kbEnv == '0')
: BTRIODevicePresent();
@@ -1017,7 +1022,6 @@ extern "C" int
// otherwise go dead).
//
{
extern int BTRIODevicePresent(void);
static const char *s_kbEnv = getenv("BT_KEY_BRIDGE");
int engine_owns = s_kbEnv ? (*s_kbEnv == '0')
: BTRIODevicePresent();
+13
View File
@@ -2721,6 +2721,19 @@ void
BTSetViewInside(sViewInside);
}
sPrevV = vNow;
#ifdef BT_GLASS
// The glass backtick toggle (PadRIO edge; the V action
// stands down with the binding engine in glass mode).
{
extern int BTPadViewToggleEdge(void);
while (BTPadViewToggleEdge())
{
sViewInside = !sViewInside;
extern void BTSetViewInside(int inside);
BTSetViewInside(sViewInside);
}
}
#endif
// RETICLE = SCREEN CENTER (task #58 correction, supersedes the
// task #39 "body-mounted view" model): the CAMERA yaws with