From 538f0c534f654f5cfa0f5ae127cde9c74f15cde0 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 25 Dec 2019 07:13:01 +0100 Subject: [PATCH] Backport Added alternate Turbo-Mode 'Single Button' - For systems supporting only a single button, the turbo-button will toggle firing that button without the need to hold it. When holding the button turbo will be suspended and resumed when the button is released. Holding the button may have a different function to just tapping it, e.g. charging the beam in R-Type on C64/Amiga. The original implementation in RA is named 'Classic' because I have no idea where it originates from. --- config.def.h | 2 + configuration.c | 2 + configuration.h | 2 + input/input_driver.h | 22 +++++++++ intl/msg_hash_lbl.h | 4 ++ intl/msg_hash_us.c | 14 ++++++ intl/msg_hash_us.h | 16 ++++++ menu/cbs/menu_cbs_sublabel.c | 8 +++ menu/menu_displaylist.c | 8 +++ menu/menu_setting.c | 94 +++++++++++++++++++++++++++++++++++ msg_hash.h | 2 + retroarch.c | 95 ++++++++++++++++++++++++++++++------ 12 files changed, 254 insertions(+), 15 deletions(-) diff --git a/config.def.h b/config.def.h index abd1cc25b8..9a10753805 100644 --- a/config.def.h +++ b/config.def.h @@ -979,6 +979,8 @@ static const float analog_sensitivity = 1.0f; /* Describes speed of which turbo-enabled buttons toggle. */ static const unsigned turbo_period = 6; static const unsigned turbo_duty_cycle = 3; +static const unsigned turbo_mode = 0; +static const unsigned turbo_default_btn = RETRO_DEVICE_ID_JOYPAD_B; /* Enable input auto-detection. Will attempt to autoconfigure * gamepads, plug-and-play style. */ diff --git a/configuration.c b/configuration.c index 7249a4c035..3cf434e697 100644 --- a/configuration.c +++ b/configuration.c @@ -1735,6 +1735,8 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, SETTING_UINT("input_bind_hold", &settings->uints.input_bind_hold, true, input_bind_hold, false); SETTING_UINT("input_turbo_period", &settings->uints.input_turbo_period, true, turbo_period, false); SETTING_UINT("input_duty_cycle", &settings->uints.input_turbo_duty_cycle, true, turbo_duty_cycle, false); + SETTING_UINT("input_turbo_mode", &settings->uints.input_turbo_mode, true, turbo_mode, false); + SETTING_UINT("input_turbo_default_button", &settings->uints.input_turbo_default_button, true, turbo_default_btn, false); SETTING_UINT("input_max_users", input_driver_get_uint(INPUT_ACTION_MAX_USERS), true, input_max_users, false); SETTING_UINT("fps_update_interval", &settings->uints.fps_update_interval, true, DEFAULT_FPS_UPDATE_INTERVAL, false); SETTING_UINT("input_menu_toggle_gamepad_combo", &settings->uints.input_menu_toggle_gamepad_combo, true, menu_toggle_gamepad_combo, false); diff --git a/configuration.h b/configuration.h index 97648b3361..c14c307741 100644 --- a/configuration.h +++ b/configuration.h @@ -464,6 +464,8 @@ typedef struct settings unsigned input_turbo_period; unsigned input_turbo_duty_cycle; + unsigned input_turbo_mode; + unsigned input_turbo_default_button; unsigned input_bind_timeout; unsigned input_bind_hold; diff --git a/input/input_driver.h b/input/input_driver.h index 02cb1d15e8..a71e20a655 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -64,6 +64,28 @@ enum input_toggle_type INPUT_TOGGLE_LAST }; +enum input_turbo_mode +{ + INPUT_TURBO_MODE_CLASSIC = 0, + INPUT_TURBO_MODE_SINGLEBUTTON, + INPUT_TURBO_MODE_LAST +}; + +enum input_turbo_default_button +{ + INPUT_TURBO_DEFAULT_BUTTON_B = 0, + INPUT_TURBO_DEFAULT_BUTTON_Y, + INPUT_TURBO_DEFAULT_BUTTON_A, + INPUT_TURBO_DEFAULT_BUTTON_X, + INPUT_TURBO_DEFAULT_BUTTON_L, + INPUT_TURBO_DEFAULT_BUTTON_R, + INPUT_TURBO_DEFAULT_BUTTON_L2, + INPUT_TURBO_DEFAULT_BUTTON_R2, + INPUT_TURBO_DEFAULT_BUTTON_L3, + INPUT_TURBO_DEFAULT_BUTTON_R3, + INPUT_TURBO_DEFAULT_BUTTON_LAST +}; + enum input_action { INPUT_ACTION_NONE = 0, diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index f33f5e2a8e..075cb36624 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -2191,3 +2191,7 @@ MSG_HASH(MENU_ENUM_LABEL_INPUT_MENU_SETTINGS, "input_menu_settings") MSG_HASH(MENU_ENUM_LABEL_INPUT_HAPTIC_FEEDBACK_SETTINGS, "input_haptic_feedback_settings") +MSG_HASH(MENU_ENUM_LABEL_INPUT_TURBO_MODE, + "input_turbo_mode") +MSG_HASH(MENU_ENUM_LABEL_INPUT_TURBO_DEFAULT_BUTTON, + "input_turbo_default_button") diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 8b6d204c25..e74180ace1 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1613,6 +1613,20 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) "Numbers are described in frames." ); break; + case MENU_ENUM_LABEL_INPUT_TURBO_MODE: + snprintf(s, len, + "Turbo Mode.\n" + " \n" + "Selects the general behavior of turbo mode." + ); + break; + case MENU_ENUM_LABEL_INPUT_TURBO_DEFAULT_BUTTON: + snprintf(s, len, + "Turbo Default Button.\n" + " \n" + "Default active button for Turbo Mode 'Single Button'.\n" + ); + break; case MENU_ENUM_LABEL_INPUT_DUTY_CYCLE: snprintf(s, len, "Duty cycle.\n" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 143e9aa6b6..0ac897ebc7 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -1565,6 +1565,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, "Turbo Period" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, + "Turbo Mode" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, + "Turbo Default Button" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, "Port %u Binds" @@ -5615,6 +5623,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, "Describes how long the period of a turbo-enabled button should be. Numbers are described in frames." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_MODE, + "Selects the general behavior of turbo mode." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON, + "Default active button for Turbo Mode 'Single Button'." + ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VSYNC, "Synchronizes the output video of the graphics card to the refresh rate of the screen. Recommended." diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 22e156a12e..b75dff87c6 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -262,6 +262,8 @@ default_sublabel_macro(action_bind_sublabel_input_mouse_scale, MENU_ENUM_SUBLABE default_sublabel_macro(action_bind_sublabel_axis_threshold, MENU_ENUM_SUBLABEL_INPUT_BUTTON_AXIS_THRESHOLD) default_sublabel_macro(action_bind_sublabel_input_turbo_period, MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD) default_sublabel_macro(action_bind_sublabel_input_duty_cycle, MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE) + default_sublabel_macro(action_bind_sublabel_input_turbo_mode, MENU_ENUM_SUBLABEL_INPUT_TURBO_MODE) +default_sublabel_macro(action_bind_sublabel_input_turbo_default_button, MENU_ENUM_SUBLABEL_INPUT_TURBO_DEFAULT_BUTTON) default_sublabel_macro(action_bind_sublabel_video_vertical_sync, MENU_ENUM_SUBLABEL_VIDEO_VSYNC) default_sublabel_macro(action_bind_sublabel_video_adaptive_vsync, MENU_ENUM_SUBLABEL_VIDEO_ADAPTIVE_VSYNC) default_sublabel_macro(action_bind_sublabel_core_allow_rotate, MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE) @@ -2490,6 +2492,12 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_INPUT_TURBO_PERIOD: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_turbo_period); break; + case MENU_ENUM_LABEL_INPUT_TURBO_MODE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_turbo_mode); + break; + case MENU_ENUM_LABEL_INPUT_TURBO_DEFAULT_BUTTON: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_turbo_default_button); + break; case MENU_ENUM_LABEL_INPUT_BIND_TIMEOUT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_bind_timeout); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 03b6a68431..18e35aabab 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4591,6 +4591,14 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct MENU_ENUM_LABEL_INPUT_DUTY_CYCLE, PARSE_ONLY_UINT, false) == 0) count++; + if (menu_displaylist_parse_settings_enum(list, + MENU_ENUM_LABEL_INPUT_TURBO_MODE, + PARSE_ONLY_UINT, false) == 0) + count++; + if (menu_displaylist_parse_settings_enum(list, + MENU_ENUM_LABEL_INPUT_TURBO_DEFAULT_BUTTON, + PARSE_ONLY_UINT, false) == 0) + count++; if (menu_displaylist_parse_settings_enum(list, MENU_ENUM_LABEL_INPUT_BIND_MODE, PARSE_ONLY_UINT, false) == 0) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index cae490ab04..6a6650f2fa 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -5475,6 +5475,66 @@ static void setting_get_string_representation_toggle_gamepad_combo( } } +static void setting_get_string_representation_turbo_mode( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (!setting) + return; + + switch (*setting->value.target.unsigned_integer) + { + case INPUT_TURBO_MODE_CLASSIC: + strlcpy(s, "Classic", len); + break; + case INPUT_TURBO_MODE_SINGLEBUTTON: + strlcpy(s, "Single Button", len); + break; + } +} + +static void setting_get_string_representation_turbo_default_button( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (!setting) + return; + + switch (*setting->value.target.unsigned_integer) + { + case INPUT_TURBO_DEFAULT_BUTTON_B: + strlcpy(s, "B / Fire", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_Y: + strlcpy(s, "Y", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_A: + strlcpy(s, "A", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_X: + strlcpy(s, "X", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_L: + strlcpy(s, "L", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_R: + strlcpy(s, "R", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_L2: + strlcpy(s, "L2", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_R2: + strlcpy(s, "R2", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_L3: + strlcpy(s, "L3", len); + break; + case INPUT_TURBO_DEFAULT_BUTTON_R3: + strlcpy(s, "R3", len); + break; + } +} + #ifdef HAVE_NETWORKING static void setting_get_string_representation_netplay_share_digital( rarch_setting_t *setting, @@ -11215,6 +11275,40 @@ static bool setting_append_list( &subgroup_info, parent_group); + CONFIG_UINT( + list, list_info, + &settings->uints.input_turbo_mode, + MENU_ENUM_LABEL_INPUT_TURBO_MODE, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_MODE, + turbo_mode, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX; + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_turbo_mode; + menu_settings_list_current_add_range(list, list_info, 0, (INPUT_TURBO_MODE_LAST-1), 1, true, true); + + CONFIG_UINT( + list, list_info, + &settings->uints.input_turbo_default_button, + MENU_ENUM_LABEL_INPUT_TURBO_DEFAULT_BUTTON, + MENU_ENUM_LABEL_VALUE_INPUT_TURBO_DEFAULT_BUTTON, + turbo_default_btn, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX; + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_turbo_default_button; + menu_settings_list_current_add_range(list, list_info, 0, (INPUT_TURBO_DEFAULT_BUTTON_LAST-1), 1, true, true); + END_SUB_GROUP(list, list_info, parent_group); START_SUB_GROUP(list, list_info, "Binds", &group_info, &subgroup_info, parent_group); diff --git a/msg_hash.h b/msg_hash.h index 87f6f3eb69..8376bcafe1 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -691,6 +691,8 @@ enum msg_hash_enums MENU_ENUM_LABEL_INPUT_HOTKEY_BINDS_BEGIN, MENU_LABEL(INPUT_TURBO_PERIOD), + MENU_LABEL(INPUT_TURBO_MODE), + MENU_LABEL(INPUT_TURBO_DEFAULT_BUTTON), MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX, MENU_ENUM_LABEL_INPUT_PLAYER2_JOYPAD_INDEX, diff --git a/retroarch.c b/retroarch.c index 788fb94c8e..e0303c05a9 100644 --- a/retroarch.c +++ b/retroarch.c @@ -3216,6 +3216,8 @@ struct turbo_buttons { bool frame_enable[MAX_USERS]; uint16_t enable[MAX_USERS]; + bool mode1_enable[MAX_USERS]; + int32_t turbo_pressed[MAX_USERS]; unsigned count; }; @@ -13630,23 +13632,86 @@ static int16_t input_state_device( { /* * Apply turbo button if activated. - * - * If turbo button is held, all buttons pressed except - * for D-pad will go into a turbo mode. Until the button is - * released again, the input state will be modulated by a - * periodic pulse defined by the configured duty cycle. */ - if (res && input_driver_turbo_btns.frame_enable[port]) - input_driver_turbo_btns.enable[port] |= (1 << id); - else if (!res) - input_driver_turbo_btns.enable[port] &= ~(1 << id); - - if (input_driver_turbo_btns.enable[port] & (1 << id)) + if (settings->uints.input_turbo_mode == 1) { - /* if turbo button is enabled for this key ID */ - res = res && ((input_driver_turbo_btns.count - % settings->uints.input_turbo_period) - < settings->uints.input_turbo_duty_cycle); + /* Pressing turbo button toggles turbo mode on or off. + * Holding the button will + * pass through, else the pressed state will be modulated by a + * periodic pulse defined by the configured duty cycle. + */ + + /* Avoid detecting the turbo button being held as multiple toggles */ + if (!input_driver_turbo_btns.frame_enable[port]) + input_driver_turbo_btns.turbo_pressed[port] &= ~(1<<31); + else if (input_driver_turbo_btns.turbo_pressed[port]>=0) + { + input_driver_turbo_btns.turbo_pressed[port] |= (1<<31); + /* Toggle turbo for selected buttons. */ + if (!input_driver_turbo_btns.enable[port]) + { + static const int button_map[]={ + RETRO_DEVICE_ID_JOYPAD_B, + RETRO_DEVICE_ID_JOYPAD_Y, + RETRO_DEVICE_ID_JOYPAD_A, + RETRO_DEVICE_ID_JOYPAD_X, + RETRO_DEVICE_ID_JOYPAD_L, + RETRO_DEVICE_ID_JOYPAD_R, + RETRO_DEVICE_ID_JOYPAD_L2, + RETRO_DEVICE_ID_JOYPAD_R2, + RETRO_DEVICE_ID_JOYPAD_L3, + RETRO_DEVICE_ID_JOYPAD_R3}; + input_driver_turbo_btns.enable[port] = 1 << button_map[ + min( + sizeof(button_map)/sizeof(button_map[0])-1, + settings->uints.input_turbo_default_button)]; + } + input_driver_turbo_btns.mode1_enable[port] ^= 1; + } + + if (input_driver_turbo_btns.turbo_pressed[port] & 1<<31) + { + /* Avoid detecting buttons being held as multiple toggles */ + if (!res) + input_driver_turbo_btns.turbo_pressed[port] &= ~(1 << id); + else if (!(input_driver_turbo_btns.turbo_pressed[port] & (1 << id))) + { + input_driver_turbo_btns.turbo_pressed[port] |= 1 << id; + /* Toggle turbo for pressed button but make sure at least one button has turbo */ + uint16_t enable_new = input_driver_turbo_btns.enable[port] ^ (1 << id); + if (enable_new) + input_driver_turbo_btns.enable[port] = enable_new; + } + } + + if (!res && input_driver_turbo_btns.mode1_enable[port] && + input_driver_turbo_btns.enable[port] & (1 << id)) + { + /* if turbo button is enabled for this key ID */ + res = ((input_driver_turbo_btns.count + % settings->uints.input_turbo_period) + < settings->uints.input_turbo_duty_cycle); + } + } + else + { + /* If turbo button is held, all buttons pressed except + * for D-pad will go into a turbo mode. Until the button is + * released again, the input state will be modulated by a + * periodic pulse defined by the configured duty cycle. + */ + if (res && input_driver_turbo_btns.frame_enable[port]) + input_driver_turbo_btns.enable[port] |= (1 << id); + else if (!res) + input_driver_turbo_btns.enable[port] &= ~(1 << id); + + if (input_driver_turbo_btns.enable[port] & (1 << id)) + { + /* if turbo button is enabled for this key ID */ + res = res && ((input_driver_turbo_btns.count + % settings->uints.input_turbo_period) + < settings->uints.input_turbo_duty_cycle); + } } }