(menu_event) Fix D-pad repeat firing early after blocked input

Sixth instance of the class fixed by c09a057, 8ab71e9, 46288b2 and
9240338, but affecting a time delta rather than a button edge.

'last_time_us' drives the navigation auto-repeat clock:

   float delta_time = (float)(menu_st->current_time_us - last_time_us) / 1000;
   last_time_us     = menu_st->current_time_us;
   ...
   delay_count     += delta_time;
   if (delay_count >= delay_timer)
      /* fire repeat */

It is written at exactly one place, inside 'if (navigation_current)',
which sits after both the MENU_ST_FLAG_BLOCK_ALL_INPUT and screensaver
early returns. Taking either return leaves the clock frozen while
current_time_us keeps advancing on wall-clock.

'hold_reset' normally protects against an oversized delta: on the first
frame of a press it zeroes 'delay_count' and skips the accumulate, so
an idle menu followed by a press is harmless. The early returns bypass
that protection, because they leave 'hold_reset' and 'delay_count'
holding their mid-hold values. When input is unblocked, the next
'delta_time' spans the entire blocked interval and is added to a
'delay_count' that is already partway to 'delay_timer', overshooting it
in a single step.

The result is a repeat firing on the frame after the press rather than
after menu_scroll_delay, so one D-pad press moves the selection two or
more entries. The screensaver path is the easier of the two to hit,
since dismissing the screensaver with a direction press takes it.

Advance 'last_time_us' on both early returns, alongside the 'ok_old'
and 'switch_old' updates already there.
This commit is contained in:
libretroadmin committed 2026-07-20 20:21:55 +02:00
1 parent fc27e433a3
commit 656acd3a70
1 file changed
+8
+8
View File
@@ -5230,6 +5230,11 @@ unsigned menu_event(
ok_old = ok_current;
switch_old = BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_LEFT)
| BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_RIGHT);
/* The navigation auto-repeat clock must keep advancing too,
* otherwise the next 'delta_time' spans the whole blocked
* interval and overshoots 'delay_timer' in a single step,
* firing a repeat immediately after the next press */
last_time_us = menu_st->current_time_us;
return MENU_ACTION_NOOP;
}
@@ -5368,6 +5373,9 @@ unsigned menu_event(
menu_input->cancel_inhibit = true;
switch_old = BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_LEFT)
| BIT256_GET_PTR(p_input, RETRO_DEVICE_ID_JOYPAD_RIGHT);
/* Keep the navigation auto-repeat clock advancing, for the
* same reason as the BLOCK_ALL_INPUT path above */
last_time_us = menu_st->current_time_us;
return MENU_ACTION_NOOP;
}