#118 crash fix: the eng-eject page gate moves into the game-thread RIO drain

The page-gated eject query ran in the window-click thread (PadRIO
EmitButton) and dereferenced the TU-local application global -- NULL there
under the /FORCE duplicate-symbol layout -> c0000005 at mode-manager +0x50
the moment the operator pressed the eng eject key (field crash,
live.log [crash] record). Moved into LBE4ControlsManager::ProcessRIOEvent's
ButtonPressedEvent branch, where mode_mask is already resolved on the game
thread; PadRIO now only queues events. Same gate semantics (armed + that
bank's ENG-page mode bits); verified no-crash + no-eject on the quad page.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-03 20:33:32 -05:00
co-authored by Claude Fable 5
parent bfc072b56f
commit fa3d634ed3
2 changed files with 31 additions and 24 deletions
+26
View File
@@ -2630,6 +2630,32 @@ void
// Save 'pressed' mode mask for 'release'
//----------------------------------------
buttonActivateModeMask[rio_event.Data.Unit] = mode_mask;
// THE ENG-PAGE EJECT KEY [T3 intent-completion, #118]: side keys
// 0x0B/0x23/0x03 are the eng-page EJECT position (engEject lamp 0x85
// = kBTEngBankTop-4; the streamed weapon pages route the same key to
// EjectAmmo). Eject was UNFINISHED in the 4.10 binary (the armed
// mode never rose), so the generator-page press has no authored
// route; complete the intent here IN THE DRAIN (game thread --
// mode_mask in hand; a first cut queried the mode manager from the
// window-click thread and crashed on the unbound TU global): while
// PANIC is armed AND that bank shows an ENG page, forward the press
// as a pilot-keypad key -- the binary's one armed eject binding.
{
const int a = rio_event.Data.Unit;
unsigned engBits =
(a == 0x0B) ? 0x001Eu : // bank 1: eng modes aux 1-4
(a == 0x23) ? 0x03C0u : // bank 2: eng modes aux 5-8
(a == 0x03) ? 0x7800u : 0u; // bank 3: eng modes aux 9-12
if (engBits != 0
&& ((unsigned)mode_mask & 0x200000u) != 0
&& ((unsigned)mode_mask & engBits) != 0)
{
ControlsKey eject_key = '0';
Check(&keyboardGroup[KeyboardPilot]);
keyboardGroup[KeyboardPilot].ForceUpdate(&eject_key, mode_mask);
}
}
break;
case RIO::ButtonReleasedEvent:
+5 -24
View File
@@ -475,30 +475,11 @@ void
if (address == 0x3D && pressed)
EmitKeypad(LBE4ControlsManager::KeyboardPilot, 0);
// THE ENG-PAGE EJECT KEY [T3 intent-completion, 2026-08-03]: physical
// side keys 0x0B / 0x23 / 0x03 are the eng-page EJECT function position
// (engEject lamp 0x85 = kBTEngBankTop - 4; the streamed weapon pages
// route the same key to EjectAmmo msg 0xB, and the lamp-name/function
// columns align key-for-key). On GENERATOR eng pages the shipped stream
// gives this key NO live route (msg 9 -- no handler in any class table):
// eject was UNFINISHED in the 4.10 binary (the permission evaluator was
// dead code, so panic mode never armed in the arcade at all). Complete
// the authored intent: while PANIC mode is armed AND that bank shows an
// ENGINEERING page (kBTEngModeMask bits -- the same per-page gating the
// alarm lamps use), the flashing EJECT key fires the pilot-keypad eject.
// On any other page (quad select, weapon pages) the key keeps its
// authored function -- the two field regressions came from skipping the
// page gate.
if (pressed && (address == 0x0B || address == 0x23 || address == 0x03))
{
ModeMask mask = application->GetModeManager()->GetModeMask();
unsigned engBits =
(address == 0x0B) ? 0x001Eu : // bank 1: eng modes aux 1-4
(address == 0x23) ? 0x03C0u : // bank 2: eng modes aux 5-8
0x7800u; // bank 3: eng modes aux 9-12
if ((mask & 0x200000u) != 0 && ((unsigned)mask & engBits) != 0)
EmitKeypad(LBE4ControlsManager::KeyboardPilot, address & 0xF);
}
// (The ENG-PAGE EJECT KEY intent-completion lives in the game-thread RIO
// drain -- LBE4ControlsManager::ProcessRIOEvent, ButtonPressedEvent --
// where mode_mask is safely in hand. A first cut queried the mode
// manager HERE, on the window-click thread, and crashed on the unbound
// TU global (field-caught 2026-08-03).)
RIOEvent event;
event.Type = pressed ? ButtonPressedEvent : ButtonReleasedEvent;