Issue #24: release held pad buttons on controller disconnect (look latch)
XInput button emission is edge-based against previousPadButtons; the
disconnect path zeroed that memory WITHOUT emitting release edges, so
any button held when a controller (wrapper) died stayed pressed
game-side forever -- and the zeroing also erased what a reconnect would
have released. Field signature (playtest night): a PS3-pad-in-xbox-
mode wrapper died mid-hat-hold -> the look-view machine (hold-based,
mppr) latched a side view with the authored look pitch ("stuck side
view + pitch at ground, no recovery"); the keyboard-only run was clean.
On the connected->disconnected transition PadRIO now emits
EmitButton(address, 0) for every binding whose mask was held, then
forgets. Not reproducible headless (needs a real hardware unplug
mid-hold) -- awaiting the reporter's controller for live verification.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5f115eca19
commit
44f7c39ee1
@@ -78,6 +78,16 @@ BEFORE Present. D3DPOOL_DEFAULT: released at every device-Reset site. One-shot
|
||||
`[waitscreen] paint path:` says which path is live. Verified: 14 rapid PrintWindow frames
|
||||
all carry the text (was alternating black).
|
||||
|
||||
## PadRIO gotcha: release-on-disconnect (issue #24, 2026-07-23) [T3 -- awaiting live verify]
|
||||
XInput button emission is EDGE-based (`held != was_held` vs `previousPadButtons`). The
|
||||
disconnect path zeroed `previousPadButtons` WITHOUT emitting release edges -- any button held
|
||||
at the moment a controller (wrapper) died stayed pressed game-side FOREVER, and the zeroing
|
||||
also erased the memory a reconnect would have released from. Field signature: PS3-pad-in-
|
||||
xbox-mode wrapper died mid-hold -> look-view latched (stuck side view + pitch-down, no
|
||||
recovery; keyboard-only run clean). Fix: on the connected->disconnected transition, emit
|
||||
`EmitButton(address, 0)` for every binding whose mask was held, THEN forget. Not reproducible
|
||||
headless (needs real hardware unplug) -- logic fix, awaiting the reporter's controller.
|
||||
|
||||
## Plan of record (2026-07-17)
|
||||
|
||||
Working branch `glass-cockpit` (from master `e2c21c4`). Steps: (1) gates+scaffolding [THIS],
|
||||
|
||||
@@ -416,6 +416,25 @@ void
|
||||
DEBUG_STREAM << "[padrio] XInput pad " << padIndex
|
||||
<< " disconnected\n" << std::flush;
|
||||
padIndex = -1;
|
||||
// issue #24 (stuck look-view): RELEASE everything the pad was
|
||||
// holding BEFORE forgetting it -- zeroing previousPadButtons
|
||||
// without emitting the release edges left the game-side buttons
|
||||
// pressed FOREVER (a hat held at the moment a flaky controller
|
||||
// wrapper died latched the look view with no recovery; field
|
||||
// report: PS3-pad-in-xbox-mode, stuck side view + pitch-down).
|
||||
if (previousPadButtons != 0)
|
||||
{
|
||||
for (int b = 0; b < bindings.padButtonBindingCount; ++b)
|
||||
{
|
||||
const PadBindingProfile::PadButtonBinding &binding =
|
||||
bindings.padButtonBindings[b];
|
||||
if ((previousPadButtons & binding.buttonMask) != 0
|
||||
&& binding.action.kind == PadBindingProfile::ActionButton)
|
||||
{
|
||||
EmitButton(binding.action.address, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
previousPadButtons = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user