@@ -6007,6 +6007,103 @@ static void input_keys_pressed(
60076007 input_st -> input_hotkey_block_counter = 0 ;
60086008}
60096009
6010+ /* Ignore d-pad buttons to avoid false positives.
6011+ * Some wireless gamepad receivers report 0 values for all axes when the
6012+ * gamepad is powered off or not yet connected. Since 0 represents the
6013+ * "left" and "up" positions for d-pad axes, this creates false button
6014+ * presses that could trigger unwanted input mapping.
6015+ */
6016+ static bool any_button_ex_dpad_pressed (int32_t state )
6017+ {
6018+ static const uint32_t button_mask =
6019+ (1 << RETRO_DEVICE_ID_JOYPAD_A ) |
6020+ (1 << RETRO_DEVICE_ID_JOYPAD_B ) |
6021+ (1 << RETRO_DEVICE_ID_JOYPAD_X ) |
6022+ (1 << RETRO_DEVICE_ID_JOYPAD_Y ) |
6023+ (1 << RETRO_DEVICE_ID_JOYPAD_L ) |
6024+ (1 << RETRO_DEVICE_ID_JOYPAD_R ) |
6025+ (1 << RETRO_DEVICE_ID_JOYPAD_L2 ) |
6026+ (1 << RETRO_DEVICE_ID_JOYPAD_R2 ) |
6027+ (1 << RETRO_DEVICE_ID_JOYPAD_L3 ) |
6028+ (1 << RETRO_DEVICE_ID_JOYPAD_R3 ) |
6029+ (1 << RETRO_DEVICE_ID_JOYPAD_START ) |
6030+ (1 << RETRO_DEVICE_ID_JOYPAD_SELECT );
6031+
6032+ return (state & button_mask ) != 0 ;
6033+ }
6034+
6035+ /* Returns MAX_USERS if all core ports are mapped to a user. */
6036+ static unsigned get_first_free_core_port (settings_t * settings )
6037+ {
6038+ unsigned core_port_idx ;
6039+ for (core_port_idx = 0 ; core_port_idx < MAX_USERS ; core_port_idx ++ )
6040+ {
6041+ unsigned * core_port_users = settings -> uints .input_remap_port_map [core_port_idx ];
6042+ if (core_port_users [0 ] == MAX_USERS )
6043+ return core_port_idx ;
6044+ }
6045+
6046+ return MAX_USERS ;
6047+ }
6048+
6049+ static void map_user_to_first_free_core_port (unsigned user_idx , settings_t * settings )
6050+ {
6051+ unsigned core_port_idx ;
6052+
6053+ if (!settings || user_idx >= MAX_USERS )
6054+ {
6055+ RARCH_ERR ("[Automap] Invalid parameters\n" );
6056+ return ;
6057+ }
6058+
6059+ /* Check if user is already mapped */
6060+ if (settings -> uints .input_remap_ports [user_idx ] < MAX_USERS )
6061+ {
6062+ RARCH_LOG ("[Automap] User %u already mapped to core port %u\n" ,
6063+ user_idx , settings -> uints .input_remap_ports [user_idx ]);
6064+ return ;
6065+ }
6066+
6067+ core_port_idx = get_first_free_core_port (settings );
6068+
6069+ if (core_port_idx < MAX_USERS )
6070+ {
6071+ configuration_set_uint (settings ,
6072+ settings -> uints .input_remap_ports [user_idx ], core_port_idx );
6073+ configuration_set_uint (settings ,
6074+ settings -> uints .input_libretro_device [core_port_idx ], RETRO_DEVICE_JOYPAD );
6075+
6076+ input_remapping_update_port_map ();
6077+
6078+ RARCH_LOG ("[Automap] user %u mapped to core port %u\n" , user_idx , core_port_idx );
6079+
6080+ if (settings -> bools .notification_show_user_mapped_to_core_port )
6081+ {
6082+ unsigned joypad_idx = settings -> uints .input_joypad_index [user_idx ];
6083+ const char * device_display_name = input_config_get_device_display_name (joypad_idx );
6084+ char msg [128 ] = { '\0' };
6085+
6086+ if (string_is_empty (device_display_name ))
6087+ snprintf (msg , sizeof (msg ),
6088+ msg_hash_to_str (MSG_PORT_MAPPED_TO_CORE_PORT_NR ),
6089+ user_idx + 1 ,
6090+ core_port_idx + 1 );
6091+ else
6092+ snprintf (msg , sizeof (msg ),
6093+ msg_hash_to_str (MSG_DEVICE_MAPPED_TO_CORE_PORT_NR ),
6094+ device_display_name ,
6095+ core_port_idx + 1 );
6096+
6097+ runloop_msg_queue_push (msg , strlen (msg ), 1 , 180 , true, NULL ,
6098+ MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO );
6099+ }
6100+ }
6101+ else
6102+ {
6103+ RARCH_LOG ("[Automap] No free core ports - user %u not mapped\n" , user_idx );
6104+ }
6105+ }
6106+
60106107void input_driver_poll (void )
60116108{
60126109 size_t i , j ;
@@ -6023,9 +6120,27 @@ void input_driver_poll(void)
60236120 * sec_joypad = NULL ;
60246121#endif
60256122 bool input_remap_binds_enable = settings -> bools .input_remap_binds_enable ;
6123+ bool input_remap_ports_on_button_press
6124+ = settings -> bools .input_remap_ports_on_button_press ;
60266125 float input_axis_threshold = settings -> floats .input_axis_threshold ;
60276126 uint8_t max_users = (uint8_t )settings -> uints .input_max_users ;
60286127
6128+ /* This rarch_joypad_info_t struct contains the device index + autoconfig binds for the
6129+ * controller to be queried, and also (for unknown reasons) the analog axis threshold
6130+ * when mapping analog stick to dpad input. */
6131+ for (i = 0 ; i < max_users ; i ++ )
6132+ {
6133+ joypad_info [i ].axis_threshold = input_axis_threshold ;
6134+ joypad_info [i ].joy_idx = settings -> uints .input_joypad_index [i ];
6135+ joypad_info [i ].auto_binds = input_autoconf_binds [joypad_info [i ].joy_idx ];
6136+ }
6137+
6138+ #ifdef HAVE_MENU
6139+ input_remap_ports_on_button_press =
6140+ input_remap_ports_on_button_press
6141+ && !(menu_state_get_ptr ()-> flags & MENU_ST_FLAG_ALIVE );
6142+ #endif
6143+
60296144 if (joypad && joypad -> poll )
60306145 joypad -> poll ();
60316146 if (sec_joypad && sec_joypad -> poll )
@@ -6034,22 +6149,49 @@ void input_driver_poll(void)
60346149 && input_st -> current_driver -> poll )
60356150 input_st -> current_driver -> poll (input_st -> current_data );
60366151
6152+ if (input_remap_ports_on_button_press )
6153+ {
6154+ for (i = 0 ; i < max_users ; i ++ )
6155+ {
6156+ bool user_already_mapped = settings -> uints .input_remap_ports [i ] < MAX_USERS ;
6157+
6158+ if (!user_already_mapped )
6159+ {
6160+ int32_t buttons_st = input_state_wrap (input_st -> current_driver , input_st -> current_data ,
6161+ joypad , sec_joypad , & joypad_info [i ],
6162+ (* input_st -> libretro_input_binds ),
6163+ (input_st -> flags & INP_FLAG_KB_MAPPING_BLOCKED ) ? true : false,
6164+ (unsigned )i ,
6165+ RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_MASK );
6166+
6167+ if (any_button_ex_dpad_pressed (buttons_st ))
6168+ map_user_to_first_free_core_port (i , settings );
6169+ }
6170+ }
6171+ }
6172+
60376173#ifdef HAVE_OVERLAY
60386174 if ( input_st -> overlay_ptr
60396175 && (input_st -> overlay_ptr -> flags & INPUT_OVERLAY_ALIVE ))
60406176 {
60416177 unsigned input_analog_dpad_mode = settings -> uints .input_analog_dpad_mode [0 ];
6178+ unsigned mapped_port = settings -> uints .input_remap_ports [0 ];
6179+ bool first_user_is_mapped = mapped_port < MAX_USERS ;
60426180 float input_overlay_opacity = (input_st -> overlay_ptr -> flags & INPUT_OVERLAY_IS_OSK )
60436181 ? settings -> floats .input_osk_overlay_opacity
60446182 : settings -> floats .input_overlay_opacity ;
60456183
6184+ /* If user 0 is not mapped yet, use the port they would be mapped
6185+ * to on overlay button press to get the input_analog_dpad_mode. */
6186+ if (!first_user_is_mapped && input_remap_ports_on_button_press )
6187+ mapped_port = get_first_free_core_port (settings );
6188+
60466189 switch (input_analog_dpad_mode )
60476190 {
60486191 case ANALOG_DPAD_LSTICK :
60496192 case ANALOG_DPAD_RSTICK :
60506193 {
6051- unsigned mapped_port = settings -> uints .input_remap_ports [0 ];
6052- if (input_st -> analog_requested [mapped_port ])
6194+ if ((mapped_port < MAX_USERS ) && input_st -> analog_requested [mapped_port ])
60536195 input_analog_dpad_mode = ANALOG_DPAD_NONE ;
60546196 }
60556197 break ;
@@ -6071,6 +6213,12 @@ void input_driver_poll(void)
60716213 input_overlay_opacity ,
60726214 input_analog_dpad_mode ,
60736215 settings -> floats .input_axis_threshold );
6216+
6217+ if (!first_user_is_mapped && input_remap_ports_on_button_press )
6218+ {
6219+ if (input_st -> overlay_ptr -> overlay_state .buttons .data [0 ])
6220+ map_user_to_first_free_core_port (0 , settings );
6221+ }
60746222 }
60756223#endif
60766224
@@ -6083,9 +6231,6 @@ void input_driver_poll(void)
60836231 return ;
60846232 }
60856233
6086- /* This rarch_joypad_info_t struct contains the device index + autoconfig binds for the
6087- * controller to be queried, and also (for unknown reasons) the analog axis threshold
6088- * when mapping analog stick to dpad input. */
60896234 for (i = 0 ; i < max_users ; i ++ )
60906235 {
60916236 uint16_t button_id = RARCH_TURBO_ENABLE ;
@@ -6094,10 +6239,6 @@ void input_driver_poll(void)
60946239 if (settings -> ints .input_turbo_bind != -1 )
60956240 button_id = settings -> ints .input_turbo_bind ;
60966241
6097- joypad_info [i ].axis_threshold = input_axis_threshold ;
6098- joypad_info [i ].joy_idx = settings -> uints .input_joypad_index [i ];
6099- joypad_info [i ].auto_binds = input_autoconf_binds [joypad_info [i ].joy_idx ];
6100-
61016242 input_st -> turbo_btns .frame_enable [i ] =
61026243 (* input_st -> libretro_input_binds [i ])[button_id ].valid
61036244 && turbo_enable ?
@@ -6136,16 +6277,18 @@ void input_driver_poll(void)
61366277 {
61376278 input_bits_t current_inputs ;
61386279 unsigned mapped_port = settings -> uints .input_remap_ports [i ];
6139- unsigned device = settings -> uints .input_libretro_device [mapped_port ]
6140- & RETRO_DEVICE_MASK ;
6280+ unsigned device = ((mapped_port < MAX_USERS )
6281+ ? settings -> uints .input_libretro_device [mapped_port ]
6282+ : RETRO_DEVICE_NONE
6283+ ) & RETRO_DEVICE_MASK ;
61416284 input_bits_t * p_new_state = (input_bits_t * )& current_inputs ;
61426285 unsigned input_analog_dpad_mode = settings -> uints .input_analog_dpad_mode [i ];
61436286
61446287 switch (input_analog_dpad_mode )
61456288 {
61466289 case ANALOG_DPAD_LSTICK :
61476290 case ANALOG_DPAD_RSTICK :
6148- if (input_st -> analog_requested [mapped_port ])
6291+ if (( mapped_port < MAX_USERS ) && input_st -> analog_requested [mapped_port ])
61496292 input_analog_dpad_mode = ANALOG_DPAD_NONE ;
61506293 break ;
61516294 case ANALOG_DPAD_LSTICK_FORCED :
@@ -6699,6 +6842,11 @@ void input_remapping_update_port_map(void)
66996842 port_map_index [remap_port ]++ ;
67006843 }
67016844 }
6845+
6846+ /* Changing mapped port may leave a core port unused;
6847+ * reinitialise controllers to ensure that any such
6848+ * ports are set to 'RETRO_DEVICE_NONE' */
6849+ command_event (CMD_EVENT_CONTROLLER_INIT , NULL );
67026850}
67036851
67046852void input_remapping_deinit (bool save_remap )
@@ -6717,6 +6865,29 @@ void input_remapping_deinit(bool save_remap)
67176865 | RUNLOOP_FLAG_REMAPS_GAME_ACTIVE );
67186866}
67196867
6868+ void input_remapping_set_remap_ports_defaults (void )
6869+ {
6870+ unsigned i ;
6871+ settings_t * settings = config_get_ptr ();
6872+ bool remap_on_button_press = settings -> bools .input_remap_ports_on_button_press ;
6873+
6874+ for (i = 0 ; i < MAX_USERS ; i ++ )
6875+ {
6876+ configuration_set_uint (settings ,
6877+ settings -> uints .input_remap_ports [i ],
6878+ remap_on_button_press ? MAX_USERS : i );
6879+
6880+ configuration_set_uint (settings ,
6881+ settings -> uints .input_libretro_device [i ],
6882+ remap_on_button_press ? RETRO_DEVICE_NONE : RETRO_DEVICE_JOYPAD );
6883+ }
6884+
6885+ /* Need to call 'input_remapping_update_port_map()'
6886+ * whenever 'settings->uints.input_remap_ports'
6887+ * is modified */
6888+ input_remapping_update_port_map ();
6889+ }
6890+
67206891void input_remapping_set_defaults (bool clear_cache )
67216892{
67226893 unsigned i , j ;
@@ -6741,16 +6912,9 @@ void input_remapping_set_defaults(bool clear_cache)
67416912 for (j = RARCH_FIRST_CUSTOM_BIND ; j < (RARCH_FIRST_CUSTOM_BIND + 8 ); j ++ )
67426913 configuration_set_uint (settings ,
67436914 settings -> uints .input_remap_ids [i ][j ], j );
6744-
6745- /* Controller port remaps */
6746- configuration_set_uint (settings ,
6747- settings -> uints .input_remap_ports [i ], i );
67486915 }
67496916
6750- /* Need to call 'input_remapping_update_port_map()'
6751- * whenever 'settings->uints.input_remap_ports'
6752- * is modified */
6753- input_remapping_update_port_map ();
6917+ input_remapping_set_remap_ports_defaults ();
67546918
67556919 /* Restore 'global' settings that were cached on
67566920 * the last core init
0 commit comments