diff --git a/config.def.h b/config.def.h index 51674612180..52f3bcb5fb5 100644 --- a/config.def.h +++ b/config.def.h @@ -623,6 +623,8 @@ #define DEFAULT_INPUT_OVERLAY_POINTER_ENABLE false #endif +#define DEFAULT_INPUT_OVERLAY_ANALOG_RECENTER_ZONE 0 + #define DEFAULT_INPUT_OVERLAY_LIGHTGUN_PORT -1 #define DEFAULT_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH true #define DEFAULT_INPUT_OVERLAY_LIGHTGUN_TRIGGER_DELAY 1 diff --git a/configuration.c b/configuration.c index 8098143c08b..7eb6c08e1e2 100644 --- a/configuration.c +++ b/configuration.c @@ -2514,6 +2514,7 @@ static struct config_uint_setting *populate_settings_uint( SETTING_UINT("input_overlay_show_inputs_port", &settings->uints.input_overlay_show_inputs_port, true, DEFAULT_OVERLAY_SHOW_INPUTS_PORT, false); SETTING_UINT("input_overlay_dpad_diagonal_sensitivity", &settings->uints.input_overlay_dpad_diagonal_sensitivity, true, DEFAULT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, false); SETTING_UINT("input_overlay_abxy_diagonal_sensitivity", &settings->uints.input_overlay_abxy_diagonal_sensitivity, true, DEFAULT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, false); + SETTING_UINT("input_overlay_analog_recenter_zone", &settings->uints.input_overlay_analog_recenter_zone, true, DEFAULT_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, false); #endif #ifdef HAVE_LIBNX diff --git a/configuration.h b/configuration.h index 611678c510f..b61d3a22c95 100644 --- a/configuration.h +++ b/configuration.h @@ -332,6 +332,7 @@ typedef struct settings unsigned input_overlay_show_inputs_port; unsigned input_overlay_dpad_diagonal_sensitivity; unsigned input_overlay_abxy_diagonal_sensitivity; + unsigned input_overlay_analog_recenter_zone; unsigned input_overlay_lightgun_trigger_delay; unsigned input_overlay_lightgun_two_touch_input; unsigned input_overlay_lightgun_three_touch_input; diff --git a/input/input_driver.c b/input/input_driver.c index 4566b7171d0..5c4f44ed7e4 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -2248,6 +2248,68 @@ static INLINE void input_overlay_get_eightway_state( bits_or_bits(out->data, data, CUSTOM_BINDS_U32_COUNT); } +/** + * input_overlay_get_analog_state: + * @out : Overlay input state to be modified + * @desc : Overlay descriptor handle + * @base : 0 or 2 for analog_left or analog_right + * @x : X coordinate + * @y : Y coordinate + * @x_dist : X offset from analog center + * @y_dist : Y offset from analog center + * @first_touch : Set true if analog was not controlled in previous poll + * + * Gets the analog input state based on @x and @y, and applies to @out. + */ +static void input_overlay_get_analog_state( + input_overlay_state_t *out, struct overlay_desc *desc, + unsigned base, float x, float y, float *x_dist, float *y_dist, + bool first_touch) +{ + float x_val, y_val; + float x_val_sat, y_val_sat; + const int b = base / 2; + + static float x_center[2]; + static float y_center[2]; + + if (first_touch) + { + unsigned recenter_zone = + config_get_ptr()->uints.input_overlay_analog_recenter_zone; + + /* Reset analog center */ + x_center[b] = desc->x_shift; + y_center[b] = desc->y_shift; + + if (recenter_zone != 0) + { + /* Get analog state without adjusting center or saturation */ + x_val = (x - desc->x_shift) / desc->range_x; + y_val = (y - desc->y_shift) / desc->range_y; + + /* Recenter if within zone */ + if ( (x_val * x_val + y_val * y_val) * 1e4 + < (recenter_zone * recenter_zone) + || recenter_zone >= 100) + { + x_center[b] = x; + y_center[b] = y; + } + } + } + + *x_dist = x - x_center[b]; + *y_dist = y - y_center[b]; + x_val = *x_dist / desc->range_x; + y_val = *y_dist / desc->range_y; + x_val_sat = x_val / desc->analog_saturate_pct; + y_val_sat = y_val / desc->analog_saturate_pct; + + out->analog[base + 0] = clamp_float(x_val_sat, -1.0f, 1.0f) * 32767.0f; + out->analog[base + 1] = clamp_float(y_val_sat, -1.0f, 1.0f) * 32767.0f; +} + /** * input_overlay_coords_inside_hitbox: * @desc : Overlay descriptor handle. @@ -2398,16 +2460,9 @@ static bool input_overlay_poll( base = 2; /* fall-through */ default: - { - float x_val = x_dist / desc->range_x; - float y_val = y_dist / desc->range_y; - float x_val_sat = x_val / desc->analog_saturate_pct; - float y_val_sat = y_val / desc->analog_saturate_pct; - out->analog[base + 0] = clamp_float(x_val_sat, -1.0f, 1.0f) - * 32767.0f; - out->analog[base + 1] = clamp_float(y_val_sat, -1.0f, 1.0f) - * 32767.0f; - } + input_overlay_get_analog_state( + out, desc, base, x, y, + &x_dist, &y_dist, !use_range_mod); break; } diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 7fa421a1ca3..802b005e065 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -2140,6 +2140,10 @@ MSG_HASH( MENU_ENUM_LABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "input_overlay_abxy_diagonal_sensitivity" ) +MSG_HASH( + MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "input_overlay_analog_recenter_zone" + ) MSG_HASH( MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, "input_poll_type_behavior" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 5b1caf258b3..89118f23295 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -5450,6 +5450,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, "Adjust the size of overlap zones in the face button diamond. Set to 100% for 8-way symmetry." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog Recentering Zone" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + "Analog stick input will be relative to first touch if pressed within this zone." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_OVERLAY, "Overlay" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 493275ff097..9df92f8806f 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -718,6 +718,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_auto_scale, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_osk_overlay_auto_scale, MENU_ENUM_SUBLABEL_INPUT_OSK_OVERLAY_AUTO_SCALE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_dpad_diag_sens, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_abxy_diag_sens, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_analog_recenter_zone, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_content_collection_list, MENU_ENUM_SUBLABEL_PLAYLISTS_TAB) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_scale_integer, MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_scale_integer_axis, MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_AXIS) @@ -4283,6 +4284,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_abxy_diag_sens); break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_analog_recenter_zone); + break; case MENU_ENUM_LABEL_VIDEO_FONT_SIZE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_font_size); break; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index c8791dcccef..2a7db944aff 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -10183,6 +10183,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_MOUSE_CURSOR, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, PARSE_ONLY_UINT, false }, {MENU_ENUM_LABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, PARSE_ONLY_UINT, false }, + {MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, PARSE_ONLY_UINT, false }, {MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_ROTATE, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_SCALE, PARSE_ONLY_BOOL, false }, {MENU_ENUM_LABEL_OVERLAY_SCALE_LANDSCAPE, PARSE_ONLY_FLOAT, false }, @@ -10251,6 +10252,12 @@ unsigned menu_displaylist_build_list( BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_ABXY_AREA)) build_list[i].checked = true; break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE: + if (input_overlay_enable && + (BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_ANALOG_LEFT) + || BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_ANALOG_RIGHT))) + build_list[i].checked = true; + break; case MENU_ENUM_LABEL_OVERLAY_LIGHTGUN_SETTINGS: case MENU_ENUM_LABEL_OVERLAY_MOUSE_SETTINGS: if (input_overlay_enable && input_overlay_ptr_enable) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index d93d08e3a1e..589cbe7f490 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -17652,6 +17652,23 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0, 100, 1, true, true); SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_CMD_APPLY_AUTO); + CONFIG_UINT( + list, list_info, + &settings->uints.input_overlay_analog_recenter_zone, + MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + DEFAULT_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler + ); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_percentage; + menu_settings_list_current_add_range(list, list_info, 0, 100, 1, true, true); + CONFIG_FLOAT( list, list_info, &settings->floats.input_overlay_scale_landscape, diff --git a/msg_hash.h b/msg_hash.h index 16b35e4da2a..bc9404d5aac 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1335,6 +1335,7 @@ enum msg_hash_enums MENU_LABEL(INPUT_OSK_OVERLAY_AUTO_SCALE), MENU_LABEL(INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY), MENU_LABEL(INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY), + MENU_LABEL(INPUT_OVERLAY_ANALOG_RECENTER_ZONE), MENU_LABEL(INPUT_OVERLAY_POINTER_ENABLE), MENU_LABEL(INPUT_OVERLAY_LIGHTGUN_PORT), MENU_LABEL(INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH),