Skip to content

Commit 3fbb0af

Browse files
committed
Map users to core ports on first button press
The first user to press a button is mapped to core port 1 (player 1), the second is mapped to core port 2 (player 2), and so on. Configured by the input_remap_on_button_press option. When enabled, all users are unmapped by default (assigned to 'None'/MAX_USERS).
1 parent 850cc56 commit 3fbb0af

File tree

13 files changed

+323
-46
lines changed

13 files changed

+323
-46
lines changed

config.def.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,6 +1124,10 @@
11241124
* input remap file */
11251125
#define DEFAULT_NOTIFICATION_SHOW_REMAP_LOAD true
11261126

1127+
/* Display a notification when a user is mapped to a core
1128+
* port on first button press */
1129+
#define DEFAULT_NOTIFICATION_SHOW_USER_MAPPED_TO_CORE_PORT true
1130+
11271131
/* Display a notification when loading a
11281132
* configuration override file */
11291133
#define DEFAULT_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD true
@@ -1620,6 +1624,10 @@
16201624
* gamepads, plug-and-play style. */
16211625
#define DEFAULT_INPUT_AUTODETECT_ENABLE true
16221626

1627+
/* Map user to core port on first button press. First person
1628+
* to press a button is player 1, second is player 2, etc. */
1629+
#define DEFAULT_INPUT_REMAP_PORTS_ON_BUTTON_PRESS false
1630+
16231631
/* Enables accelerometer/gyroscope/illuminance
16241632
* sensor input, if supported */
16251633
#if defined(ANDROID)

configuration.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,7 @@ static struct config_bool_setting *populate_settings_bool(
19341934
SETTING_BOOL("notification_show_cheats_applied", &settings->bools.notification_show_cheats_applied, true, DEFAULT_NOTIFICATION_SHOW_CHEATS_APPLIED, false);
19351935
SETTING_BOOL("notification_show_patch_applied", &settings->bools.notification_show_patch_applied, true, DEFAULT_NOTIFICATION_SHOW_PATCH_APPLIED, false);
19361936
SETTING_BOOL("notification_show_remap_load", &settings->bools.notification_show_remap_load, true, DEFAULT_NOTIFICATION_SHOW_REMAP_LOAD, false);
1937+
SETTING_BOOL("notification_show_user_mapped_to_core_port", &settings->bools.notification_show_user_mapped_to_core_port, true, DEFAULT_NOTIFICATION_SHOW_USER_MAPPED_TO_CORE_PORT, false);
19371938
SETTING_BOOL("notification_show_config_override_load", &settings->bools.notification_show_config_override_load, true, DEFAULT_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, false);
19381939
SETTING_BOOL("notification_show_set_initial_disk", &settings->bools.notification_show_set_initial_disk, true, DEFAULT_NOTIFICATION_SHOW_SET_INITIAL_DISK, false);
19391940
SETTING_BOOL("notification_show_disk_control", &settings->bools.notification_show_disk_control, true, DEFAULT_NOTIFICATION_SHOW_DISK_CONTROL, false);
@@ -2177,6 +2178,7 @@ static struct config_bool_setting *populate_settings_bool(
21772178
SETTING_BOOL("input_turbo_allow_dpad", &settings->bools.input_turbo_allow_dpad, true, DEFAULT_TURBO_ALLOW_DPAD, false);
21782179
SETTING_BOOL("input_auto_mouse_grab", &settings->bools.input_auto_mouse_grab, true, DEFAULT_INPUT_AUTO_MOUSE_GRAB, false);
21792180
SETTING_BOOL("input_remap_binds_enable", &settings->bools.input_remap_binds_enable, true, true, false);
2181+
SETTING_BOOL("input_remap_ports_on_button_press", &settings->bools.input_remap_ports_on_button_press, true, DEFAULT_INPUT_REMAP_PORTS_ON_BUTTON_PRESS, false);
21802182
SETTING_BOOL("input_remap_sort_by_controller_enable", &settings->bools.input_remap_sort_by_controller_enable, true, false, false);
21812183
SETTING_BOOL("input_hotkey_device_merge", &settings->bools.input_hotkey_device_merge, true, DEFAULT_INPUT_HOTKEY_DEVICE_MERGE, false);
21822184
SETTING_BOOL("input_hotkey_follows_player1", &settings->bools.input_hotkey_follows_player1, true, DEFAULT_INPUT_HOTKEY_FOLLOWS_PLAYER1, false);

configuration.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ typedef struct settings
702702
/* Input */
703703
bool input_remap_binds_enable;
704704
bool input_remap_sort_by_controller_enable;
705+
bool input_remap_ports_on_button_press;
705706
bool input_autodetect_enable;
706707
bool input_sensors_enable;
707708
bool input_overlay_enable;
@@ -758,6 +759,7 @@ typedef struct settings
758759
bool notification_show_cheats_applied;
759760
bool notification_show_patch_applied;
760761
bool notification_show_remap_load;
762+
bool notification_show_user_mapped_to_core_port;
761763
bool notification_show_config_override_load;
762764
bool notification_show_set_initial_disk;
763765
bool notification_show_disk_control;

input/input_driver.c

Lines changed: 184 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
60166113
void 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

67106858
void 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+
67266897
void 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

input/input_remapping.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,30 @@ void input_remapping_deinit(bool save_remap);
9292
*/
9393
void input_remapping_set_defaults(bool clear_cache);
9494

95+
/**
96+
* Used to set the default port mapping values within the `settings` struct.
97+
* Only sets port mapping related values, not button/keyboard/analog remaps.
98+
*
99+
* If settings->bools.input_remap_ports_on_button_press is true, leave all
100+
* users/devices disconnected. Users will be mapped to a core port on first
101+
* button press.
102+
*
103+
* user 0 -> core port MAX_USERS (RETRO_DEVICE_NONE)
104+
* user 1 -> core port MAX_USERS (RETRO_DEVICE_NONE)
105+
* ...
106+
* user n -> core port MAX_USERS (RETRO_DEVICE_NONE)
107+
*
108+
* Else map each user to a core port and set all devices to RETRO_DEVICE_JOYPAD:
109+
*
110+
* user 0 -> core port 0 (RETRO_DEVICE_JOYPAD)
111+
* user 1 -> core port 1 (RETRO_DEVICE_JOYPAD)
112+
* ...
113+
* user n -> core port n (RETRO_DEVICE_JOYPAD)
114+
*
115+
* (where n = MAX_USERS - 1)
116+
*/
117+
void input_remapping_set_remap_ports_defaults(void);
118+
95119
/**
96120
* Checks `input_config_bind_map` for the requested `input_bind_map`, and if
97121
* the bind has been registered, returns its base.

0 commit comments

Comments
 (0)