mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-08 08:10:30 -10:00
(dinput) Clear stale pad state when acquisition fails
dinput_joypad_poll() skips a pad for the current frame when both
Poll() and the subsequent re-Acquire() fail:
if (FAILED(IDirectInputDevice8_Poll(pad->joypad)))
if ( FAILED(IDirectInputDevice8_Acquire(pad->joypad))
|| FAILED(IDirectInputDevice8_Poll(pad->joypad)))
continue;
but leaves 'pad->joy_state' holding the last successfully read state.
The comment below claims no pre-zeroing is needed because a failed read
is handled by dinput_joypad_cleanup_pad(), however that only covers the
GetDeviceState() failure path; the 'continue' above bypasses it.
DirectInput devices lose acquisition whenever the application loses
foreground focus - alt-tab, UAC prompts, the screen saver, or an
overlay window taking focus. Acquire() then keeps failing for as long
as the window is unfocused, so the pad is skipped every frame with its
state frozen at the instant focus was lost.
joy_state.rgdwPOV[] is the D-pad. A direction held at that moment is
therefore reported as still held for the entire unfocused period, and
continues to be reported until the first successful poll after focus
returns. This is read directly by dinput_joypad_button_state() with no
staleness check.
Zero the cached state before skipping the pad. Note that rgdwPOV[] must
be explicitly set to DINPUT_POV_CENTERED rather than left at zero,
since zero is a valid POV value meaning north - a plain memset would
report 'up' as held instead.
dinput_joypad_cleanup_pad() has the same rgdwPOV[] property via its
ZeroMemory(), but is safe because it also clears pad->joypad, and
dinput_joypad_button() rejects any port whose joypad pointer is NULL.
This commit is contained in:
1 parent
65f8fec25e
commit
fda77fa344
1 file changed
+15
-1
@@ -462,17 +462,31 @@ static void dinput_joypad_poll(void)
|
||||
for (i = 0; i < g_joypad_cnt; i++)
|
||||
{
|
||||
HRESULT ret;
|
||||
unsigned h;
|
||||
struct dinput_joypad_data *pad = &g_pads[i];
|
||||
|
||||
if (!pad->joypad)
|
||||
continue;
|
||||
|
||||
/* If Poll() fails, attempt to re-acquire and poll again.
|
||||
* If that also fails, skip this pad for this frame. */
|
||||
* If that also fails, skip this pad for this frame.
|
||||
* Zero the cached state first: DirectInput devices lose
|
||||
* acquisition on focus loss (alt-tab, UAC prompt, screen
|
||||
* saver), and 'joy_state' would otherwise keep reporting
|
||||
* whatever was held at that moment - including rgdwPOV[],
|
||||
* so a D-pad direction held when focus was lost is seen as
|
||||
* still held for the whole unfocused period and beyond. */
|
||||
if (FAILED(IDirectInputDevice8_Poll(pad->joypad)))
|
||||
if ( FAILED(IDirectInputDevice8_Acquire(pad->joypad))
|
||||
|| FAILED(IDirectInputDevice8_Poll(pad->joypad)))
|
||||
{
|
||||
memset(&pad->joy_state, 0, sizeof(pad->joy_state));
|
||||
/* Centre all hats - zero is a valid POV direction
|
||||
* (north), so memset alone would report 'up' held */
|
||||
for (h = 0; h < ARRAY_SIZE(pad->joy_state.rgdwPOV); h++)
|
||||
pad->joy_state.rgdwPOV[h] = DINPUT_POV_CENTERED;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = IDirectInputDevice8_GetDeviceState(pad->joypad,
|
||||
sizeof(DIJOYSTATE2), &pad->joy_state);
|
||||
|
||||
Reference in new issue
Block a user