From 2ef2ff1b365edd8f60e636426af6f14101d71f01 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Mon, 21 Feb 2022 14:13:02 +0100 Subject: [PATCH] Add a configurable workaround for Android reconnecting devices Closes https://github.com/libretro/RetroArch/issues/3414 I have investigated the issue. The crux of the problem is that on Android there is no way distinguishing 2 scenarios: 1) 2 identical bluetooth controllers A and B and first there are button presses only on controller A and then on controller B 2) the same controller disconnects and reconnects. Android doesn't give bluetooth mac address of where the touch came from, only opaque ID and this opaque ID changes after reconnect. Hence without changes to android this is infeasible without giving up the ability for 2 users to play on identical controllers. I guess that this sacrifice makes sense for affected users --- configuration.c | 4 ++++ configuration.h | 4 ++++ input/drivers/android_input.c | 24 ++++++++++++++++++++++-- intl/msg_hash_us.h | 9 +++++++++ menu/cbs/menu_cbs_sublabel.c | 1 + menu/menu_displaylist.c | 6 ++++++ menu/menu_setting.c | 18 ++++++++++++++++++ msg_hash.h | 2 ++ 8 files changed, 66 insertions(+), 2 deletions(-) diff --git a/configuration.c b/configuration.c index 8720d33ccb..9065cd1494 100644 --- a/configuration.c +++ b/configuration.c @@ -2023,6 +2023,10 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("wifi_enabled", &settings->bools.wifi_enabled, true, DEFAULT_WIFI_ENABLE, false); SETTING_BOOL("gamemode_enable", &settings->bools.gamemode_enable, true, DEFAULT_GAMEMODE_ENABLE, false); +#ifdef ANDROID + SETTING_BOOL("android_input_disconnect_workaround", &settings->bools.android_input_disconnect_workaround, true, false, false); +#endif + *size = count; return tmp; diff --git a/configuration.h b/configuration.h index f452a22bc7..4fc1d9b25a 100644 --- a/configuration.h +++ b/configuration.h @@ -940,6 +940,10 @@ typedef struct settings #ifdef _3DS bool new3ds_speedup_enable; #endif + +#ifdef ANDROID + bool android_input_disconnect_workaround; +#endif } bools; } settings_t; diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index 4f20b0dbcb..e071fc4c4a 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -838,7 +838,6 @@ static int android_input_get_id_port(android_input_t *android, int id, return ret; } -#ifdef HAVE_DYNAMIC /* Returns the index inside android->pad_state */ static int android_input_get_id_index_from_name(android_input_t *android, const char *name) @@ -852,7 +851,25 @@ static int android_input_get_id_index_from_name(android_input_t *android, return -1; } -#endif + +static int android_input_recover_port(android_input_t *android, int id) +{ + char device_name[256] = { 0 }; + int vendorId = 0; + int productId = 0; + settings_t *settings = config_get_ptr(); + + if (!settings->bools.android_input_disconnect_workaround) + return -1; + if (!engine_lookup_name(device_name, &vendorId, + &productId, sizeof(device_name), id)) + return -1; + int ret = android_input_get_id_index_from_name(android, device_name); + if (ret >= 0) + android->pad_states[ret].id = id; + return ret; +} + static void handle_hotplug(android_input_t *android, struct android_app *android_app, int *port, int id, @@ -1195,6 +1212,9 @@ static void android_input_poll_input(android_input_t *android, int id = android_input_get_id(event); int port = android_input_get_id_port(android, id, source); + if (port < 0 && !android_is_keyboard_id(id)) + port = android_input_recover_port(android, id); + if (port < 0 && !android_is_keyboard_id(id)) handle_hotplug(android, android_app, &port, id, source); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 5aa389f066..11f924ec7f 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2597,6 +2597,15 @@ MSG_HASH( "Allow any user to control the menu. If disabled, only User 1 can control the menu." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ANDROID_INPUT_DISCONNECT_WORKAROUND, + "Android disconnect workaround" + ) +MSG_HASH( + MENU_ENUM_LABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND, + "Workaround for controllers disconnecting and reconnecting. Impedes 2 players with the identical controllers." + ) + /* Settings > Input > Hotkeys */ MSG_HASH( diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 52ba84848b..810c605cb1 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -681,6 +681,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_nowinkey_enable, MENU_ #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_sensors_enable, MENU_ENUM_SUBLABEL_INPUT_SENSORS_ENABLE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_auto_mouse_grab, MENU_ENUM_SUBLABEL_INPUT_AUTO_MOUSE_GRAB) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_android_input_disconnect_workaround, MENU_ENUM_SUBLABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_auto_game_focus, MENU_ENUM_SUBLABEL_INPUT_AUTO_GAME_FOCUS) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_swap_ok_cancel, MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_pause_libretro, MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 1cd1db4c2f..65e0a6a552 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -6940,6 +6940,12 @@ unsigned menu_displaylist_build_list( MENU_ENUM_LABEL_INPUT_AUTO_MOUSE_GRAB, PARSE_ONLY_BOOL, false) == 0) count++; +#ifdef ANDROID + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, + MENU_ENUM_LABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND, + PARSE_ONLY_BOOL, false) == 0) + count++; +#endif if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_INPUT_AUTO_GAME_FOCUS, PARSE_ONLY_UINT, false) == 0) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 1f56f0783e..e7d639a79e 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -13618,6 +13618,24 @@ static bool setting_append_list( SD_FLAG_NONE ); +#ifdef ANDROID + CONFIG_BOOL( + list, list_info, + &settings->bools.android_input_disconnect_workaround, + MENU_ENUM_LABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND, + MENU_ENUM_LABEL_VALUE_ANDROID_INPUT_DISCONNECT_WORKAROUND, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE + ); +#endif + CONFIG_UINT( list, list_info, &settings->uints.input_auto_game_focus, diff --git a/msg_hash.h b/msg_hash.h index bd202f926a..3ae2798aa8 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1058,6 +1058,8 @@ enum msg_hash_enums MENU_LABEL(QUIT_PRESS_TWICE), MENU_LABEL(QUIT_ON_CLOSE_CONTENT), + MENU_LABEL(ANDROID_INPUT_DISCONNECT_WORKAROUND), + MENU_ENUM_LABEL_VALUE_QUIT_ON_CLOSE_CONTENT_DISABLED, MENU_ENUM_LABEL_VALUE_QUIT_ON_CLOSE_CONTENT_ENABLED, MENU_ENUM_LABEL_VALUE_QUIT_ON_CLOSE_CONTENT_CLI,