Skip to content

Commit da110c4

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 4ed05b0 commit da110c4

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
#ifdef HAVE_MENU

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;
@@ -757,6 +758,7 @@ typedef struct settings
757758
bool notification_show_cheats_applied;
758759
bool notification_show_patch_applied;
759760
bool notification_show_remap_load;
761+
bool notification_show_user_mapped_to_core_port;
760762
bool notification_show_config_override_load;
761763
bool notification_show_set_initial_disk;
762764
bool notification_show_disk_control;

input/input_driver.c

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

67046852
void 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+
67206891
void 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

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)