@@ -6013,6 +6013,103 @@ static void input_keys_pressed(
60136013 input_st -> input_hotkey_block_counter = 0 ;
60146014}
60156015
6016+ /* Ignore d-pad buttons to avoid false positives.
6017+ * Some wireless gamepad receivers report 0 values for all axes when the
6018+ * gamepad is powered off or not yet connected. Since 0 represents the
6019+ * "left" and "up" positions for d-pad axes, this creates false button
6020+ * presses that could trigger unwanted input mapping.
6021+ */
6022+ static bool any_button_ex_dpad_pressed (int32_t state )
6023+ {
6024+ static const uint32_t button_mask =
6025+ (1 << RETRO_DEVICE_ID_JOYPAD_A ) |
6026+ (1 << RETRO_DEVICE_ID_JOYPAD_B ) |
6027+ (1 << RETRO_DEVICE_ID_JOYPAD_X ) |
6028+ (1 << RETRO_DEVICE_ID_JOYPAD_Y ) |
6029+ (1 << RETRO_DEVICE_ID_JOYPAD_L ) |
6030+ (1 << RETRO_DEVICE_ID_JOYPAD_R ) |
6031+ (1 << RETRO_DEVICE_ID_JOYPAD_L2 ) |
6032+ (1 << RETRO_DEVICE_ID_JOYPAD_R2 ) |
6033+ (1 << RETRO_DEVICE_ID_JOYPAD_L3 ) |
6034+ (1 << RETRO_DEVICE_ID_JOYPAD_R3 ) |
6035+ (1 << RETRO_DEVICE_ID_JOYPAD_START ) |
6036+ (1 << RETRO_DEVICE_ID_JOYPAD_SELECT );
6037+
6038+ return (state & button_mask ) != 0 ;
6039+ }
6040+
6041+ /* Returns MAX_USERS if all core ports are mapped to a user. */
6042+ static unsigned get_first_free_core_port (settings_t * settings )
6043+ {
6044+ unsigned core_port_idx ;
6045+ for (core_port_idx = 0 ; core_port_idx < MAX_USERS ; core_port_idx ++ )
6046+ {
6047+ unsigned * core_port_users = settings -> uints .input_remap_port_map [core_port_idx ];
6048+ if (core_port_users [0 ] == MAX_USERS )
6049+ return core_port_idx ;
6050+ }
6051+
6052+ return MAX_USERS ;
6053+ }
6054+
6055+ static void map_user_to_first_free_core_port (unsigned user_idx , settings_t * settings )
6056+ {
6057+ unsigned core_port_idx ;
6058+
6059+ if (!settings || user_idx >= MAX_USERS )
6060+ {
6061+ RARCH_ERR ("[Automap] Invalid parameters\n" );
6062+ return ;
6063+ }
6064+
6065+ /* Check if user is already mapped */
6066+ if (settings -> uints .input_remap_ports [user_idx ] < MAX_USERS )
6067+ {
6068+ RARCH_LOG ("[Automap] User %u already mapped to core port %u\n" ,
6069+ user_idx , settings -> uints .input_remap_ports [user_idx ]);
6070+ return ;
6071+ }
6072+
6073+ core_port_idx = get_first_free_core_port (settings );
6074+
6075+ if (core_port_idx < MAX_USERS )
6076+ {
6077+ configuration_set_uint (settings ,
6078+ settings -> uints .input_remap_ports [user_idx ], core_port_idx );
6079+ configuration_set_uint (settings ,
6080+ settings -> uints .input_libretro_device [core_port_idx ], RETRO_DEVICE_JOYPAD );
6081+
6082+ input_remapping_update_port_map ();
6083+
6084+ RARCH_LOG ("[Automap] user %u mapped to core port %u\n" , user_idx , core_port_idx );
6085+
6086+ if (settings -> bools .notification_show_user_mapped_to_core_port )
6087+ {
6088+ unsigned joypad_idx = settings -> uints .input_joypad_index [user_idx ];
6089+ const char * device_display_name = input_config_get_device_display_name (joypad_idx );
6090+ char msg [128 ] = { '\0' };
6091+
6092+ if (string_is_empty (device_display_name ))
6093+ snprintf (msg , sizeof (msg ),
6094+ msg_hash_to_str (MSG_PORT_MAPPED_TO_CORE_PORT_NR ),
6095+ user_idx + 1 ,
6096+ core_port_idx + 1 );
6097+ else
6098+ snprintf (msg , sizeof (msg ),
6099+ msg_hash_to_str (MSG_DEVICE_MAPPED_TO_CORE_PORT_NR ),
6100+ device_display_name ,
6101+ core_port_idx + 1 );
6102+
6103+ runloop_msg_queue_push (msg , strlen (msg ), 1 , 180 , true, NULL ,
6104+ MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO );
6105+ }
6106+ }
6107+ else
6108+ {
6109+ RARCH_LOG ("[Automap] No free core ports - user %u not mapped\n" , user_idx );
6110+ }
6111+ }
6112+
60166113void input_driver_poll (void )
60176114{
60186115 size_t i , j ;
@@ -6029,9 +6126,27 @@ void input_driver_poll(void)
60296126 * sec_joypad = NULL ;
60306127#endif
60316128 bool input_remap_binds_enable = settings -> bools .input_remap_binds_enable ;
6129+ bool input_remap_ports_on_button_press
6130+ = settings -> bools .input_remap_ports_on_button_press ;
60326131 float input_axis_threshold = settings -> floats .input_axis_threshold ;
60336132 uint8_t max_users = (uint8_t )settings -> uints .input_max_users ;
60346133
6134+ /* This rarch_joypad_info_t struct contains the device index + autoconfig binds for the
6135+ * controller to be queried, and also (for unknown reasons) the analog axis threshold
6136+ * when mapping analog stick to dpad input. */
6137+ for (i = 0 ; i < max_users ; i ++ )
6138+ {
6139+ joypad_info [i ].axis_threshold = input_axis_threshold ;
6140+ joypad_info [i ].joy_idx = settings -> uints .input_joypad_index [i ];
6141+ joypad_info [i ].auto_binds = input_autoconf_binds [joypad_info [i ].joy_idx ];
6142+ }
6143+
6144+ #ifdef HAVE_MENU
6145+ input_remap_ports_on_button_press =
6146+ input_remap_ports_on_button_press
6147+ && !(menu_state_get_ptr ()-> flags & MENU_ST_FLAG_ALIVE );
6148+ #endif
6149+
60356150 if (joypad && joypad -> poll )
60366151 joypad -> poll ();
60376152 if (sec_joypad && sec_joypad -> poll )
@@ -6040,22 +6155,49 @@ void input_driver_poll(void)
60406155 && input_st -> current_driver -> poll )
60416156 input_st -> current_driver -> poll (input_st -> current_data );
60426157
6158+ if (input_remap_ports_on_button_press )
6159+ {
6160+ for (i = 0 ; i < max_users ; i ++ )
6161+ {
6162+ bool user_already_mapped = settings -> uints .input_remap_ports [i ] < MAX_USERS ;
6163+
6164+ if (!user_already_mapped )
6165+ {
6166+ int32_t buttons_st = input_state_wrap (input_st -> current_driver , input_st -> current_data ,
6167+ joypad , sec_joypad , & joypad_info [i ],
6168+ (* input_st -> libretro_input_binds ),
6169+ (input_st -> flags & INP_FLAG_KB_MAPPING_BLOCKED ) ? true : false,
6170+ (unsigned )i ,
6171+ RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_MASK );
6172+
6173+ if (any_button_ex_dpad_pressed (buttons_st ))
6174+ map_user_to_first_free_core_port (i , settings );
6175+ }
6176+ }
6177+ }
6178+
60436179#ifdef HAVE_OVERLAY
60446180 if ( input_st -> overlay_ptr
60456181 && (input_st -> overlay_ptr -> flags & INPUT_OVERLAY_ALIVE ))
60466182 {
60476183 unsigned input_analog_dpad_mode = settings -> uints .input_analog_dpad_mode [0 ];
6184+ unsigned mapped_port = settings -> uints .input_remap_ports [0 ];
6185+ bool first_user_is_mapped = mapped_port < MAX_USERS ;
60486186 float input_overlay_opacity = (input_st -> overlay_ptr -> flags & INPUT_OVERLAY_IS_OSK )
60496187 ? settings -> floats .input_osk_overlay_opacity
60506188 : settings -> floats .input_overlay_opacity ;
60516189
6190+ /* If user 0 is not mapped yet, use the port they would be mapped
6191+ * to on overlay button press to get the input_analog_dpad_mode. */
6192+ if (!first_user_is_mapped && input_remap_ports_on_button_press )
6193+ mapped_port = get_first_free_core_port (settings );
6194+
60526195 switch (input_analog_dpad_mode )
60536196 {
60546197 case ANALOG_DPAD_LSTICK :
60556198 case ANALOG_DPAD_RSTICK :
60566199 {
6057- unsigned mapped_port = settings -> uints .input_remap_ports [0 ];
6058- if (input_st -> analog_requested [mapped_port ])
6200+ if ((mapped_port < MAX_USERS ) && input_st -> analog_requested [mapped_port ])
60596201 input_analog_dpad_mode = ANALOG_DPAD_NONE ;
60606202 }
60616203 break ;
@@ -6077,6 +6219,12 @@ void input_driver_poll(void)
60776219 input_overlay_opacity ,
60786220 input_analog_dpad_mode ,
60796221 settings -> floats .input_axis_threshold );
6222+
6223+ if (!first_user_is_mapped && input_remap_ports_on_button_press )
6224+ {
6225+ if (input_st -> overlay_ptr -> overlay_state .buttons .data [0 ])
6226+ map_user_to_first_free_core_port (0 , settings );
6227+ }
60806228 }
60816229#endif
60826230
@@ -6089,9 +6237,6 @@ void input_driver_poll(void)
60896237 return ;
60906238 }
60916239
6092- /* This rarch_joypad_info_t struct contains the device index + autoconfig binds for the
6093- * controller to be queried, and also (for unknown reasons) the analog axis threshold
6094- * when mapping analog stick to dpad input. */
60956240 for (i = 0 ; i < max_users ; i ++ )
60966241 {
60976242 uint16_t button_id = RARCH_TURBO_ENABLE ;
@@ -6100,10 +6245,6 @@ void input_driver_poll(void)
61006245 if (settings -> ints .input_turbo_bind != -1 )
61016246 button_id = settings -> ints .input_turbo_bind ;
61026247
6103- joypad_info [i ].axis_threshold = input_axis_threshold ;
6104- joypad_info [i ].joy_idx = settings -> uints .input_joypad_index [i ];
6105- joypad_info [i ].auto_binds = input_autoconf_binds [joypad_info [i ].joy_idx ];
6106-
61076248 input_st -> turbo_btns .frame_enable [i ] =
61086249 (* input_st -> libretro_input_binds [i ])[button_id ].valid
61096250 && turbo_enable ?
@@ -6142,16 +6283,18 @@ void input_driver_poll(void)
61426283 {
61436284 input_bits_t current_inputs ;
61446285 unsigned mapped_port = settings -> uints .input_remap_ports [i ];
6145- unsigned device = settings -> uints .input_libretro_device [mapped_port ]
6146- & RETRO_DEVICE_MASK ;
6286+ unsigned device = ((mapped_port < MAX_USERS )
6287+ ? settings -> uints .input_libretro_device [mapped_port ]
6288+ : RETRO_DEVICE_NONE
6289+ ) & RETRO_DEVICE_MASK ;
61476290 input_bits_t * p_new_state = (input_bits_t * )& current_inputs ;
61486291 unsigned input_analog_dpad_mode = settings -> uints .input_analog_dpad_mode [i ];
61496292
61506293 switch (input_analog_dpad_mode )
61516294 {
61526295 case ANALOG_DPAD_LSTICK :
61536296 case ANALOG_DPAD_RSTICK :
6154- if (input_st -> analog_requested [mapped_port ])
6297+ if (( mapped_port < MAX_USERS ) && input_st -> analog_requested [mapped_port ])
61556298 input_analog_dpad_mode = ANALOG_DPAD_NONE ;
61566299 break ;
61576300 case ANALOG_DPAD_LSTICK_FORCED :
@@ -6705,6 +6848,11 @@ void input_remapping_update_port_map(void)
67056848 port_map_index [remap_port ]++ ;
67066849 }
67076850 }
6851+
6852+ /* Changing mapped port may leave a core port unused;
6853+ * reinitialise controllers to ensure that any such
6854+ * ports are set to 'RETRO_DEVICE_NONE' */
6855+ command_event (CMD_EVENT_CONTROLLER_INIT , NULL );
67086856}
67096857
67106858void input_remapping_deinit (bool save_remap )
@@ -6723,6 +6871,29 @@ void input_remapping_deinit(bool save_remap)
67236871 | RUNLOOP_FLAG_REMAPS_GAME_ACTIVE );
67246872}
67256873
6874+ void input_remapping_set_remap_ports_defaults (void )
6875+ {
6876+ unsigned i ;
6877+ settings_t * settings = config_get_ptr ();
6878+ bool remap_on_button_press = settings -> bools .input_remap_ports_on_button_press ;
6879+
6880+ for (i = 0 ; i < MAX_USERS ; i ++ )
6881+ {
6882+ configuration_set_uint (settings ,
6883+ settings -> uints .input_remap_ports [i ],
6884+ remap_on_button_press ? MAX_USERS : i );
6885+
6886+ configuration_set_uint (settings ,
6887+ settings -> uints .input_libretro_device [i ],
6888+ remap_on_button_press ? RETRO_DEVICE_NONE : RETRO_DEVICE_JOYPAD );
6889+ }
6890+
6891+ /* Need to call 'input_remapping_update_port_map()'
6892+ * whenever 'settings->uints.input_remap_ports'
6893+ * is modified */
6894+ input_remapping_update_port_map ();
6895+ }
6896+
67266897void input_remapping_set_defaults (bool clear_cache )
67276898{
67286899 unsigned i , j ;
@@ -6747,16 +6918,9 @@ void input_remapping_set_defaults(bool clear_cache)
67476918 for (j = RARCH_FIRST_CUSTOM_BIND ; j < (RARCH_FIRST_CUSTOM_BIND + 8 ); j ++ )
67486919 configuration_set_uint (settings ,
67496920 settings -> uints .input_remap_ids [i ][j ], j );
6750-
6751- /* Controller port remaps */
6752- configuration_set_uint (settings ,
6753- settings -> uints .input_remap_ports [i ], i );
67546921 }
67556922
6756- /* Need to call 'input_remapping_update_port_map()'
6757- * whenever 'settings->uints.input_remap_ports'
6758- * is modified */
6759- input_remapping_update_port_map ();
6923+ input_remapping_set_remap_ports_defaults ();
67606924
67616925 /* Restore 'global' settings that were cached on
67626926 * the last core init
0 commit comments