Input: bring-up gameplay keys stand down under PadRIO (BT_DEVKEYS)
The hardcoded GetAsyncKeyState gameplay keys in mech4.cpp (WASD drive, 1-4 weapon groups, G config, F5-F9 generators, C valve, M mode, Q/E torso, X all-stop/recenter) OVERLAP a RIO device's own controls -- with L4CONTROLS=PAD (or a serial RIO) engaged, every one of them double-fired against the same key going through the PadRIO bindings. Gate them behind BT_DEVKEYS: they now stand down whenever a RIO device owns input (application->GetControlsManager()->rioPointer != 0), so PadRIO's bindings.txt is the single source of truth. Env override: BT_DEVKEYS=1 forces them on (hybrid keyboard+pad testing), =0 forces off, unset = auto. Implemented as a `gfocus` gate (focused AND keys-enabled) replacing `focused` on those reads; the 'V' cockpit/chase view toggle and the '`' display toggle are desktop-only conveniences with no RIO equivalent and stay live. Backward compatible: with no device (keyboard dev mode) gfocus == focused, so keyboard-only play is unchanged. Boots clean (13 ticks, no faults). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2566,37 +2566,63 @@ void
|
||||
if (pAsync)
|
||||
{
|
||||
const int dn = 0x8000;
|
||||
gBTDrive.keyFwd = focused && ((pAsync('W') | pAsync(0x26 /*VK_UP*/)) & dn) ? 1 : 0;
|
||||
gBTDrive.keyBack = focused && ((pAsync('S') | pAsync(0x28 /*VK_DOWN*/)) & dn) ? 1 : 0;
|
||||
gBTDrive.keyLeft = focused && ((pAsync('A') | pAsync(0x25 /*VK_LEFT*/)) & dn) ? 1 : 0;
|
||||
gBTDrive.keyRight = focused && ((pAsync('D') | pAsync(0x27 /*VK_RIGHT*/)) & dn) ? 1 : 0;
|
||||
// BT_DEVKEYS gate: the bring-up GAMEPLAY keys below (drive,
|
||||
// weapons, mode, torso, config/gen/valve) OVERLAP a RIO
|
||||
// device's own controls, so with PadRIO (or serial RIO)
|
||||
// engaged they double-fire against the device's bindings.
|
||||
// They stand down whenever a RIO device owns input.
|
||||
// BT_DEVKEYS unset = AUTO (off under a device, on otherwise)
|
||||
// BT_DEVKEYS=1 = force ON (hybrid keyboard + pad)
|
||||
// BT_DEVKEYS=0 = force OFF (device only)
|
||||
// `gfocus` replaces `focused` for those keys; the 'V'
|
||||
// cockpit/chase view toggle (a desktop-only convenience with
|
||||
// no RIO equivalent) stays on `focused` and is always live,
|
||||
// as is the '`' display toggle (handled in the WndProc).
|
||||
static int s_devKeysMode = -1; // 0 auto, 1 on, 2 off
|
||||
if (s_devKeysMode < 0)
|
||||
{
|
||||
const char *dk = getenv("BT_DEVKEYS");
|
||||
s_devKeysMode = (dk == 0) ? 0 : (atoi(dk) != 0 ? 1 : 2);
|
||||
}
|
||||
LBE4ControlsManager *pollControls = (application != 0)
|
||||
? (LBE4ControlsManager *)application->GetControlsManager() : 0;
|
||||
const int deviceOwnsInput =
|
||||
(pollControls != 0 && pollControls->rioPointer != 0);
|
||||
const int gfocus = focused && (
|
||||
(s_devKeysMode == 1) ? 1 :
|
||||
(s_devKeysMode == 2) ? 0 :
|
||||
(deviceOwnsInput ? 0 : 1));
|
||||
gBTDrive.keyFwd = gfocus && ((pAsync('W') | pAsync(0x26 /*VK_UP*/)) & dn) ? 1 : 0;
|
||||
gBTDrive.keyBack = gfocus && ((pAsync('S') | pAsync(0x28 /*VK_DOWN*/)) & dn) ? 1 : 0;
|
||||
gBTDrive.keyLeft = gfocus && ((pAsync('A') | pAsync(0x25 /*VK_LEFT*/)) & dn) ? 1 : 0;
|
||||
gBTDrive.keyRight = gfocus && ((pAsync('D') | pAsync(0x27 /*VK_RIGHT*/)) & dn) ? 1 : 0;
|
||||
// WEAPON GROUPS (task #43, KEYBOARD only per user): three fire
|
||||
// channels like three pod buttons -- 1/SPACE = lasers, 2 = PPCs,
|
||||
// 3/CTRL = missiles. (Interim; the authentic system is the
|
||||
// ConfigureMappables/ChooseButton mapper channels.)
|
||||
gBTLaserKey = focused && ((pAsync('1') | pAsync(0x20 /*VK_SPACE*/)) & dn) ? 1 : 0;
|
||||
gBTPPCKey = focused && (pAsync('2') & dn) ? 1 : 0;
|
||||
gBTMissileKey = focused && ((pAsync('3') | pAsync(0x11 /*VK_CONTROL*/)) & dn) ? 1 : 0;
|
||||
gBTLaserKey = gfocus && ((pAsync('1') | pAsync(0x20 /*VK_SPACE*/)) & dn) ? 1 : 0;
|
||||
gBTPPCKey = gfocus && (pAsync('2') & dn) ? 1 : 0;
|
||||
gBTMissileKey = gfocus && ((pAsync('3') | pAsync(0x11 /*VK_CONTROL*/)) & dn) ? 1 : 0;
|
||||
// The pod's 4TH fire button (Pinky, 0x45) -- previously
|
||||
// unmapped on desktop, so any weapon the authored groups
|
||||
// put there (the Avatar's NARC etc.) was unreachable.
|
||||
gBTPinkyKey = focused && (pAsync('4') & dn) ? 1 : 0;
|
||||
gBTPinkyKey = gfocus && (pAsync('4') & dn) ? 1 : 0;
|
||||
// task #6: HOLD 'G' opens the config session on the selected
|
||||
// weapon (BT_CONFIG_SLOT, default: the first weapon); while
|
||||
// held, the fire keys TOGGLE its group membership.
|
||||
gBTConfigKey = focused && (pAsync('G') & dn) ? 1 : 0;
|
||||
gBTConfigKey = gfocus && (pAsync('G') & dn) ? 1 : 0;
|
||||
// task #12: F5..F8 assign the selected weapon to Generator
|
||||
// A..D; F9 toggles Manual/Auto reconnect.
|
||||
gBTGenSelKey =
|
||||
(focused && (pAsync(0x74 /*F5*/) & dn)) ? 4
|
||||
: (focused && (pAsync(0x75 /*F6*/) & dn)) ? 5
|
||||
: (focused && (pAsync(0x76 /*F7*/) & dn)) ? 6
|
||||
: (focused && (pAsync(0x77 /*F8*/) & dn)) ? 7
|
||||
: (focused && (pAsync(0x78 /*F9*/) & dn)) ? 8
|
||||
(gfocus && (pAsync(0x74 /*F5*/) & dn)) ? 4
|
||||
: (gfocus && (pAsync(0x75 /*F6*/) & dn)) ? 5
|
||||
: (gfocus && (pAsync(0x76 /*F7*/) & dn)) ? 6
|
||||
: (gfocus && (pAsync(0x77 /*F8*/) & dn)) ? 7
|
||||
: (gfocus && (pAsync(0x78 /*F9*/) & dn)) ? 8
|
||||
: 0;
|
||||
// task #13: 'C' cycles the coolant valve (BT_VALVE_SLOT
|
||||
// picks the condenser roster slot; default = Condenser1).
|
||||
gBTValveKey = focused && (pAsync('C') & dn) ? 1 : 0;
|
||||
gBTValveKey = gfocus && (pAsync('C') & dn) ? 1 : 0;
|
||||
// TORSO CONTROLS (2026-07-13): 'M' cycles the control mode
|
||||
// (Basic -> Standard -> Veteran -- the pod console button,
|
||||
// CycleControlModeMessageHandler); Q/E deflect the torso
|
||||
@@ -2604,15 +2630,15 @@ void
|
||||
// become the pedals). Ramped like the turn stick.
|
||||
{
|
||||
static int sPrevM = 0;
|
||||
const int mNow = focused && (pAsync('M') & dn) ? 1 : 0;
|
||||
const int mNow = gfocus && (pAsync('M') & dn) ? 1 : 0;
|
||||
if (mNow && !sPrevM) gBTModeCycle = 1; // edge -> one cycle
|
||||
sPrevM = mNow;
|
||||
// (task #68) 'V' HELD = look behind (the pod's rear-view
|
||||
// button; releases back to the forward view). Rear-mounted
|
||||
// weapons (blackhawk/owens back racks) fire only in it.
|
||||
gBTLookBehind = focused && (pAsync('V') & dn) ? 1 : 0;
|
||||
const int tw = (focused && (pAsync('E') & dn) ? 1 : 0)
|
||||
- (focused && (pAsync('Q') & dn) ? 1 : 0);
|
||||
gBTLookBehind = gfocus && (pAsync('V') & dn) ? 1 : 0;
|
||||
const int tw = (gfocus && (pAsync('E') & dn) ? 1 : 0)
|
||||
- (gfocus && (pAsync('Q') & dn) ? 1 : 0);
|
||||
static float sTwist = 0.0f;
|
||||
if (tw != 0)
|
||||
{
|
||||
@@ -2642,7 +2668,7 @@ void
|
||||
// edge detector from the drive all-stop below -- both
|
||||
// fire on the same press.
|
||||
static int sPrevXT = 0;
|
||||
const int xtNow = focused && (pAsync('X') & dn) ? 1 : 0;
|
||||
const int xtNow = gfocus && (pAsync('X') & dn) ? 1 : 0;
|
||||
if (xtNow && !sPrevXT)
|
||||
{
|
||||
sTwist = 0.0f;
|
||||
@@ -2655,7 +2681,7 @@ void
|
||||
// damage dispatcher + the beam-visual keepalive)
|
||||
gBTDrive.fire = (gBTLaserKey || gBTPPCKey || gBTMissileKey || gBTPinkyKey) ? 1 : 0;
|
||||
static int sPrevX = 0;
|
||||
const int xNow = focused && (pAsync('X') & dn) ? 1 : 0;
|
||||
const int xNow = gfocus && (pAsync('X') & dn) ? 1 : 0;
|
||||
if (xNow && !sPrevX) gBTDrive.allStop = 1; // edge -> one all-stop
|
||||
sPrevX = xNow;
|
||||
// V: toggle the view between the authentic COCKPIT eyepoint
|
||||
|
||||
Reference in New Issue
Block a user