mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-01-22 11:04:35 +00:00
Fix/reimplement input flushing
This fixes: - menu toggle erratically not working on Android - stray input going to libretro core when resuming content - bound keys triggering as soon as they're bound on Android - menu key repeat also repeating keys which should not be repeated - issues caused by relying on timeouts for flushing Architectural changes: - menu_ctx_driver_t::input_postprocess now takes state and old_state (this allows getting rid of menu_handle_t::trigger_state) Related changes: - remove some no-op input_postprocess handlers (same effect as NULL) - menu_iterate now uses the parameters passed to it, instead of polling menu_input - menu_input is now merged into meta_input_keys_pressed
This commit is contained in:
parent
91557b34da
commit
d0e970f175
3
driver.h
3
driver.h
@ -481,10 +481,9 @@ typedef struct driver
|
||||
#endif
|
||||
bool stdin_claimed;
|
||||
bool block_hotkey;
|
||||
unsigned block_hotkey_until;
|
||||
bool block_input;
|
||||
bool block_libretro_input;
|
||||
unsigned block_libretro_input_until;
|
||||
bool flushing_input;
|
||||
bool nonblock_state;
|
||||
|
||||
/* Opaque handles to currently running window.
|
||||
|
@ -344,13 +344,6 @@ static void glui_free(void *data)
|
||||
g_extern.core_info = NULL;
|
||||
}
|
||||
|
||||
static int glui_input_postprocess(uint64_t old_state)
|
||||
{
|
||||
(void)old_state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static GLuint glui_png_texture_load(const char * file_name)
|
||||
{
|
||||
struct texture_image ti = {0};
|
||||
@ -404,7 +397,7 @@ menu_ctx_driver_t menu_ctx_glui = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
glui_input_postprocess,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -984,10 +984,10 @@ static void lakka_free(void *data)
|
||||
g_extern.core_info = NULL;
|
||||
}
|
||||
|
||||
static int lakka_input_postprocess(uint64_t old_state)
|
||||
static int lakka_input_postprocess(retro_input_t state, retro_input_t old_state)
|
||||
{
|
||||
if ((driver.menu && driver.menu->trigger_state
|
||||
& (1ULL << RARCH_MENU_TOGGLE)) &&
|
||||
retro_input_t trigger_state = state & ~old_state;
|
||||
if ((driver.menu && check_enter_menu_func(trigger_state)) &&
|
||||
g_extern.main_is_init &&
|
||||
!g_extern.libretro_dummy)
|
||||
global_alpha = 0;
|
||||
|
@ -18,7 +18,7 @@ typedef struct menu_ctx_driver
|
||||
void (*populate_entries)(void*, const char *, const char *,
|
||||
unsigned);
|
||||
void (*iterate)(void*, unsigned);
|
||||
int (*input_postprocess)(uint64_t);
|
||||
int (*input_postprocess)(uint64_t, uint64_t);
|
||||
void (*navigation_clear)(void *);
|
||||
void (*navigation_decrement)(void *);
|
||||
void (*navigation_increment)(void *);
|
||||
|
@ -447,11 +447,6 @@ static void rgui_free(void *data)
|
||||
free((uint8_t*)menu->font);
|
||||
}
|
||||
|
||||
static int rgui_input_postprocess(uint64_t old_state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rgui_set_texture(void *data)
|
||||
{
|
||||
menu_handle_t *menu = (menu_handle_t*)data;
|
||||
@ -473,7 +468,7 @@ menu_ctx_driver_t menu_ctx_rgui = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
rgui_input_postprocess,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
@ -103,8 +103,6 @@ bool load_menu_content(void)
|
||||
/* redraw menu frame */
|
||||
if (driver.menu)
|
||||
{
|
||||
driver.menu->old_input_state = driver.menu->trigger_state = 0;
|
||||
driver.menu->do_held = false;
|
||||
driver.menu->msg_force = true;
|
||||
}
|
||||
|
||||
@ -172,9 +170,6 @@ void *menu_init(const void *data)
|
||||
menu_entries_push_list(menu, menu->selection_buf,
|
||||
"", "mainmenu", 0);
|
||||
|
||||
menu->trigger_state = 0;
|
||||
menu->old_input_state = 0;
|
||||
menu->do_held = false;
|
||||
menu->current_pad = 0;
|
||||
|
||||
update_libretro_info(&g_extern.menu.info);
|
||||
@ -302,8 +297,14 @@ bool menu_iterate(retro_input_t input,
|
||||
unsigned action = MENU_ACTION_NOOP;
|
||||
static bool initial_held = true;
|
||||
static bool first_held = false;
|
||||
uint64_t input_state = 0;
|
||||
int32_t ret = 0;
|
||||
static const retro_input_t input_repeat =
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_UP)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_L)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_R);
|
||||
|
||||
if (!driver.menu)
|
||||
return false;
|
||||
@ -316,9 +317,7 @@ bool menu_iterate(retro_input_t input,
|
||||
|
||||
driver.retro_ctx.poll_cb();
|
||||
|
||||
input_state = menu_input();
|
||||
|
||||
if (driver.menu->do_held)
|
||||
if (input & input_repeat)
|
||||
{
|
||||
if (!first_held)
|
||||
{
|
||||
@ -330,7 +329,7 @@ bool menu_iterate(retro_input_t input,
|
||||
if (driver.menu->delay_count >= driver.menu->delay_timer)
|
||||
{
|
||||
first_held = false;
|
||||
driver.menu->trigger_state = input_state;
|
||||
trigger_input |= input & input_repeat;
|
||||
driver.menu->scroll_accel = min(driver.menu->scroll_accel + 1, 64);
|
||||
}
|
||||
|
||||
@ -344,15 +343,14 @@ bool menu_iterate(retro_input_t input,
|
||||
}
|
||||
|
||||
driver.menu->delay_count++;
|
||||
driver.menu->old_input_state = input_state;
|
||||
|
||||
if (driver.block_input)
|
||||
driver.menu->trigger_state = 0;
|
||||
trigger_input = 0;
|
||||
|
||||
/* don't run anything first frame, only capture held inputs
|
||||
* for old_input_state.
|
||||
*/
|
||||
action = input_frame(driver.menu->trigger_state);
|
||||
action = input_frame(trigger_input);
|
||||
|
||||
if (driver.menu_ctx && driver.menu_ctx->backend
|
||||
&& driver.menu_ctx->backend->iterate)
|
||||
@ -362,7 +360,7 @@ bool menu_iterate(retro_input_t input,
|
||||
draw_frame(false);
|
||||
|
||||
if (driver.menu_ctx && driver.menu_ctx->input_postprocess)
|
||||
driver.menu_ctx->input_postprocess(driver.menu->old_input_state);
|
||||
driver.menu_ctx->input_postprocess(input, old_input);
|
||||
|
||||
#if 0
|
||||
/* Go back to Main Menu when exiting */
|
||||
|
@ -67,18 +67,6 @@ struct menu_bind_state
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* Keys down last frame. Used for trigger_state */
|
||||
uint64_t old_input_state;
|
||||
|
||||
/* New keys pressed down this frame */
|
||||
uint64_t trigger_state;
|
||||
|
||||
/* Whether any repeating keys are being held down, */
|
||||
/* and key repeat should be handled */
|
||||
/* TODO: should be a mask of keys we are repeating, */
|
||||
/* instead of repeating all keys being held down. */
|
||||
bool do_held;
|
||||
|
||||
/* Used for key repeat */
|
||||
unsigned delay_timer;
|
||||
unsigned delay_count;
|
||||
|
@ -56,7 +56,7 @@ static void menu_key_end_line(void *data)
|
||||
menu->keyboard.label_setting = NULL;
|
||||
|
||||
/* Avoid triggering states on pressing return. */
|
||||
menu->old_input_state = -1ULL;
|
||||
driver.flushing_input = true;
|
||||
}
|
||||
|
||||
static void menu_search_callback(void *userdata, const char *str)
|
||||
@ -298,43 +298,6 @@ bool menu_custom_bind_keyboard_cb(void *data, unsigned code)
|
||||
return menu->binds.begin <= menu->binds.last;
|
||||
}
|
||||
|
||||
uint64_t menu_input(void)
|
||||
{
|
||||
unsigned i;
|
||||
retro_input_t input_state = 0;
|
||||
static const struct retro_keybind *binds[] = { g_settings.input.binds[0] };
|
||||
|
||||
if (!driver.menu)
|
||||
return 0;
|
||||
|
||||
input_push_analog_dpad((struct retro_keybind*)binds[0],
|
||||
(g_settings.input.analog_dpad_mode[0] == ANALOG_DPAD_NONE) ?
|
||||
ANALOG_DPAD_LSTICK : g_settings.input.analog_dpad_mode[0]);
|
||||
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
input_push_analog_dpad(g_settings.input.autoconf_binds[i],
|
||||
g_settings.input.analog_dpad_mode[i]);
|
||||
|
||||
input_state = input_keys_pressed(0, RARCH_FIRST_CUSTOM_BIND, binds);
|
||||
|
||||
input_pop_analog_dpad((struct retro_keybind*)binds[0]);
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
input_pop_analog_dpad(g_settings.input.autoconf_binds[i]);
|
||||
|
||||
driver.menu->trigger_state = input_state & ~driver.menu->old_input_state;
|
||||
|
||||
driver.menu->do_held = (input_state & (
|
||||
(1ULL << RETRO_DEVICE_ID_JOYPAD_UP)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_DOWN)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_LEFT)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_RIGHT)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_L)
|
||||
| (1ULL << RETRO_DEVICE_ID_JOYPAD_R)
|
||||
));
|
||||
|
||||
return input_state;
|
||||
}
|
||||
|
||||
int menu_input_bind_iterate(void *data)
|
||||
{
|
||||
char msg[PATH_MAX];
|
||||
@ -358,22 +321,22 @@ int menu_input_bind_iterate(void *data)
|
||||
&& driver.menu_ctx->render_messagebox)
|
||||
driver.menu_ctx->render_messagebox(msg);
|
||||
|
||||
driver.block_input = true;
|
||||
menu_poll_bind_state(&binds);
|
||||
|
||||
driver.block_hotkey_until = g_extern.frame_count + (15);
|
||||
|
||||
if ((binds.skip && !menu->binds.skip) ||
|
||||
menu_poll_find_trigger(&menu->binds, &binds))
|
||||
{
|
||||
driver.block_input = false;
|
||||
|
||||
/* Avoid new binds triggering things right away. */
|
||||
driver.flushing_input = true;
|
||||
|
||||
binds.begin++;
|
||||
if (binds.begin <= binds.last)
|
||||
binds.target++;
|
||||
else
|
||||
return 1;
|
||||
|
||||
/* Avoid new binds triggering things right away. */
|
||||
menu->trigger_state = 0;
|
||||
menu->old_input_state = -1ULL;
|
||||
}
|
||||
menu->binds = binds;
|
||||
|
||||
@ -416,14 +379,11 @@ int menu_input_bind_iterate_keyboard(void *data)
|
||||
timed_out = true;
|
||||
}
|
||||
|
||||
driver.block_hotkey_until = g_extern.frame_count + (15);
|
||||
|
||||
/* binds.begin is updated in keyboard_press callback. */
|
||||
if (menu->binds.begin > menu->binds.last)
|
||||
{
|
||||
/* Avoid new binds triggering things right away. */
|
||||
menu->trigger_state = 0;
|
||||
menu->old_input_state = -1ULL;
|
||||
driver.flushing_input = true;
|
||||
|
||||
/* We won't be getting any key events, so just cancel early. */
|
||||
if (timed_out)
|
||||
|
@ -42,6 +42,4 @@ int menu_input_bind_iterate(void *data);
|
||||
|
||||
int menu_input_bind_iterate_keyboard(void *data);
|
||||
|
||||
uint64_t menu_input(void);
|
||||
|
||||
#endif
|
||||
|
@ -503,9 +503,7 @@ static int android_input_get_id(android_input_t *android, AInputEvent *event)
|
||||
|
||||
static bool pause_key_pressed(void)
|
||||
{
|
||||
retro_input_t old_input = 0;
|
||||
retro_input_t input = meta_input_keys_pressed(RARCH_PAUSE_TOGGLE, RARCH_PAUSE_TOGGLE+1, &old_input);
|
||||
return BIND_PRESSED(input, RARCH_PAUSE_TOGGLE);
|
||||
return driver.input->key_pressed(driver.input_data, RARCH_PAUSE_TOGGLE);
|
||||
}
|
||||
|
||||
/* Handle all events. If our activity is in pause state,
|
||||
|
@ -1625,6 +1625,10 @@ retro_input_t input_keys_pressed(unsigned key,
|
||||
* from the specified key up until the last queryable key
|
||||
* (key_end).
|
||||
*
|
||||
* Because this function keeps a copy of the old input state,
|
||||
* it should only be called once per frame (currently in
|
||||
* rarch_main_iterate);
|
||||
*
|
||||
* TODO: In case RARCH_BIND_LIST_END starts exceeding 64,
|
||||
* and you need a bitmask of more than 64 entries, don't
|
||||
* use this function.
|
||||
@ -1634,20 +1638,29 @@ retro_input_t meta_input_keys_pressed(unsigned key,
|
||||
unsigned key_end, retro_input_t *old_state)
|
||||
{
|
||||
static retro_input_t old_ret = 0;
|
||||
static const struct retro_keybind *binds[] = { g_settings.input.binds[0] };
|
||||
retro_input_t ret = 0;
|
||||
*old_state = old_ret;
|
||||
int i;
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
rarch_check_block_hotkey(driver.input->key_pressed(driver.input_data,
|
||||
RARCH_ENABLE_HOTKEY));
|
||||
#endif
|
||||
|
||||
input_push_analog_dpad((struct retro_keybind*)binds[0],
|
||||
(g_settings.input.analog_dpad_mode[0] == ANALOG_DPAD_NONE) ?
|
||||
ANALOG_DPAD_LSTICK : g_settings.input.analog_dpad_mode[0]);
|
||||
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
input_push_analog_dpad(g_settings.input.autoconf_binds[i],
|
||||
g_settings.input.analog_dpad_mode[i]);
|
||||
|
||||
for (; key < key_end; key++)
|
||||
{
|
||||
bool state = false;
|
||||
|
||||
if (!driver.block_hotkey
|
||||
&& g_extern.frame_count > driver.block_hotkey_until)
|
||||
if (!driver.block_hotkey)
|
||||
state = driver.input->key_pressed(driver.input_data, key);
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
@ -1663,6 +1676,10 @@ retro_input_t meta_input_keys_pressed(unsigned key,
|
||||
ret |= (1ULL << key);
|
||||
}
|
||||
|
||||
input_pop_analog_dpad((struct retro_keybind*)binds[0]);
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
input_pop_analog_dpad(g_settings.input.autoconf_binds[i]);
|
||||
|
||||
old_ret = ret;
|
||||
|
||||
return ret;
|
||||
|
@ -183,8 +183,7 @@ static int16_t input_state(unsigned port, unsigned device,
|
||||
|
||||
if (!driver.block_libretro_input &&
|
||||
((id < RARCH_FIRST_META_KEY ||
|
||||
device == RETRO_DEVICE_KEYBOARD) &&
|
||||
(g_extern.frame_count > driver.block_libretro_input_until))
|
||||
device == RETRO_DEVICE_KEYBOARD))
|
||||
)
|
||||
res = driver.input->input_state(driver.input_data, binds, port,
|
||||
device, index, id);
|
||||
@ -203,6 +202,35 @@ static int16_t input_state(unsigned port, unsigned device,
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
/* Last frame input_state was called. */
|
||||
static unsigned flush_frame = 0;
|
||||
/* Last frame which had input. */
|
||||
static unsigned flush_frame_input = 0;
|
||||
|
||||
if (driver.flushing_input)
|
||||
{
|
||||
if (flush_frame != g_extern.frame_count &&
|
||||
flush_frame != flush_frame_input)
|
||||
{
|
||||
/* At least one entire frame has passed with no input. */
|
||||
driver.flushing_input = false;
|
||||
flush_frame = flush_frame_input = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
flush_frame = g_extern.frame_count;
|
||||
if (res)
|
||||
{
|
||||
flush_frame_input = g_extern.frame_count;
|
||||
res = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
flush_frame = flush_frame_input = 0;
|
||||
}
|
||||
|
||||
/* Don't allow turbo for D-pad. */
|
||||
if (device == RETRO_DEVICE_JOYPAD && (id < RETRO_DEVICE_ID_JOYPAD_UP ||
|
||||
id > RETRO_DEVICE_ID_JOYPAD_RIGHT))
|
||||
|
14
retroarch.c
14
retroarch.c
@ -2838,7 +2838,9 @@ void rarch_main_set_state(unsigned cmd)
|
||||
|
||||
rarch_main_command(RARCH_CMD_AUDIO_START);
|
||||
|
||||
driver.block_libretro_input_until = g_extern.frame_count + (5);
|
||||
/* Prevent stray input from going to libretro core */
|
||||
driver.flushing_input = true;
|
||||
|
||||
/* Restore libretro keyboard callback. */
|
||||
g_extern.system.key_event = g_extern.frontend_key_event;
|
||||
break;
|
||||
@ -3226,9 +3228,17 @@ bool rarch_main_iterate(void)
|
||||
{
|
||||
unsigned i;
|
||||
retro_input_t old_input, trigger_input;
|
||||
retro_input_t input = meta_input_keys_pressed(RARCH_FIRST_META_KEY,
|
||||
retro_input_t input = meta_input_keys_pressed(0,
|
||||
RARCH_BIND_LIST_END, &old_input);
|
||||
|
||||
if (driver.flushing_input)
|
||||
{
|
||||
if (input)
|
||||
input = 0;
|
||||
else
|
||||
driver.flushing_input = false;
|
||||
}
|
||||
|
||||
trigger_input = input & ~old_input;
|
||||
|
||||
/* Time to drop? */
|
||||
|
Loading…
x
Reference in New Issue
Block a user