Skip to content

Commit

Permalink
Add support for mapping multiple controllers to a single input device
Browse files Browse the repository at this point in the history
  • Loading branch information
jdgleaver committed Jun 17, 2021
1 parent a129764 commit 0e95e5c
Show file tree
Hide file tree
Showing 19 changed files with 711 additions and 247 deletions.
56 changes: 41 additions & 15 deletions configuration.c
Expand Up @@ -2435,10 +2435,8 @@ void config_set_defaults(void *data)
#endif

input_config_reset();
#ifdef HAVE_CONFIGFILE
input_remapping_deinit();
input_remapping_set_defaults();
#endif

/* Verify that binds are in proper order. */
for (i = 0; i < MAX_USERS; i++)
Expand All @@ -2461,7 +2459,7 @@ void config_set_defaults(void *data)

for (i = 0; i < MAX_USERS; i++)
{
settings->uints.input_joypad_map[i] = i;
settings->uints.input_joypad_index[i] = i;
#ifdef SWITCH /* Switch prefered default dpad mode */
settings->uints.input_analog_dpad_mode[i] = ANALOG_DPAD_LSTICK;
#else
Expand Down Expand Up @@ -3196,7 +3194,7 @@ static bool config_load_file(global_t *global,
buf[0] = '\0';

snprintf(buf, sizeof(buf), "input_player%u_joypad_index", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_joypad_map[i], buf);
CONFIG_GET_INT_BASE(conf, settings, uints.input_joypad_index[i], buf);

snprintf(buf, sizeof(buf), "input_player%u_analog_dpad_mode", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], buf);
Expand Down Expand Up @@ -3856,9 +3854,7 @@ bool config_load_remap(const char *directory_input_remapping,
FILE_PATH_REMAP_EXTENSION,
sizeof(game_path));

#ifdef HAVE_CONFIGFILE
input_remapping_set_defaults();
#endif

/* If a game remap file exists, load it. */
if ((new_conf = config_file_new_from_path_to_string(game_path)))
Expand Down Expand Up @@ -4229,7 +4225,7 @@ bool config_save_file(const char *path)
snprintf(cfg, sizeof(cfg), "input_device_p%u", i + 1);
config_set_int(conf, cfg, settings->uints.input_device[i]);
snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1);
config_set_int(conf, cfg, settings->uints.input_joypad_map[i]);
config_set_int(conf, cfg, settings->uints.input_joypad_index[i]);
snprintf(cfg, sizeof(cfg), "input_libretro_device_p%u", i + 1);
config_set_int(conf, cfg, input_config_get_device(i));
snprintf(cfg, sizeof(cfg), "input_player%u_analog_dpad_mode", i + 1);
Expand Down Expand Up @@ -4492,11 +4488,11 @@ bool config_save_overrides(enum override_type type, void *data)
config_set_int(conf, cfg, overrides->uints.input_device[i]);
}

if (settings->uints.input_joypad_map[i]
!= overrides->uints.input_joypad_map[i])
if (settings->uints.input_joypad_index[i]
!= overrides->uints.input_joypad_index[i])
{
snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1);
config_set_int(conf, cfg, overrides->uints.input_joypad_map[i]);
config_set_int(conf, cfg, overrides->uints.input_joypad_index[i]);
}
}

Expand Down Expand Up @@ -4617,9 +4613,6 @@ bool input_remapping_load_file(void *data, const char *path)
{
char s1[32], s2[32], s3[32];

global->old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i];
global->old_libretro_device[i] = settings->uints.input_libretro_device[i];

s1[0] = '\0';
s2[0] = '\0';
s3[0] = '\0';
Expand Down Expand Up @@ -4705,8 +4698,13 @@ bool input_remapping_load_file(void *data, const char *path)

snprintf(s1, sizeof(s1), "input_libretro_device_p%u", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], s1);

snprintf(s1, sizeof(s1), "input_remap_port_p%u", i + 1);
CONFIG_GET_INT_BASE(conf, settings, uints.input_remap_ports[i], s1);
}

input_remapping_update_port_map();

return true;
}

Expand Down Expand Up @@ -4745,14 +4743,38 @@ bool input_remapping_save_file(const char *path)
return false;
}

for (i = 0; i < max_users; i++)
for (i = 0; i < MAX_USERS; i++)
{
char s1[32], s2[32], s3[32];
bool skip_port = true;
char s1[32];
char s2[32];
char s3[32];

s1[0] = '\0';
s2[0] = '\0';
s3[0] = '\0';

/* We must include all mapped ports + all those
* with an index less than max_users */
if (i < max_users)
skip_port = false;
else
{
/* Check whether current port is mapped
* to an input device */
for (j = 0; j < max_users; j++)
{
if (i == settings->uints.input_remap_ports[j])
{
skip_port = false;
break;
}
}
}

if (skip_port)
continue;

snprintf(s1, sizeof(s1), "input_player%u_btn", i + 1);
snprintf(s2, sizeof(s2), "input_player%u_key", i + 1);
snprintf(s3, sizeof(s3), "input_player%u_stk", i + 1);
Expand Down Expand Up @@ -4825,8 +4847,12 @@ bool input_remapping_save_file(const char *path)

snprintf(s1, sizeof(s1), "input_libretro_device_p%u", i + 1);
config_set_int(conf, s1, input_config_get_device(i));

snprintf(s1, sizeof(s1), "input_player%u_analog_dpad_mode", i + 1);
config_set_int(conf, s1, settings->uints.input_analog_dpad_mode[i]);

snprintf(s1, sizeof(s1), "input_remap_port_p%u", i + 1);
config_set_int(conf, s1, settings->uints.input_remap_ports[i]);
}

ret = config_file_write(conf, remap_file, true);
Expand Down
7 changes: 4 additions & 3 deletions configuration.h
Expand Up @@ -122,17 +122,18 @@ typedef struct settings
unsigned placeholder;

unsigned input_split_joycon[MAX_USERS];
unsigned input_joypad_map[MAX_USERS];
unsigned input_joypad_index[MAX_USERS];
unsigned input_device[MAX_USERS];
unsigned input_mouse_index[MAX_USERS];
/* Set by autoconfiguration in joypad_autoconfig_dir.
* Does not override main binds. */
unsigned input_libretro_device[MAX_USERS];
unsigned input_analog_dpad_mode[MAX_USERS];

unsigned input_keymapper_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];

unsigned input_remap_ports[MAX_USERS];
unsigned input_remap_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];
unsigned input_keymapper_ids[MAX_USERS][RARCH_CUSTOM_BIND_LIST_END];
unsigned input_remap_port_map[MAX_USERS][MAX_USERS + 1];

unsigned led_map[MAX_LEDS];

Expand Down
4 changes: 2 additions & 2 deletions input/drivers_joypad/gx_joypad.c
Expand Up @@ -220,7 +220,7 @@ static void handle_hotplug(unsigned port, uint32_t ptype)
static void check_port0_active(uint8_t pad_count)
{
settings_t *settings = config_get_ptr();
int idx = settings->uints.input_joypad_map[0];
int idx = settings->uints.input_joypad_index[0];

if(pad_count < 2 && idx != 0)
{
Expand All @@ -229,7 +229,7 @@ static void check_port0_active(uint8_t pad_count)
#else
pad_type[0] = WPAD_EXP_GAMECUBE;
#endif
settings->uints.input_joypad_map[0] = 0;
settings->uints.input_joypad_index[0] = 0;

input_autoconfigure_connect(
gx_joypad_name(0),
Expand Down
6 changes: 5 additions & 1 deletion input/input_remapping.h
Expand Up @@ -48,8 +48,12 @@ bool input_remapping_save_file(const char *path);
bool input_remapping_remove_file(const char *path,
const char *dir_input_remapping);

void input_remapping_deinit(void);
void input_remapping_cache_global_config(void);
void input_remapping_restore_global_config(void);

void input_remapping_update_port_map(void);

void input_remapping_deinit(void);
void input_remapping_set_defaults(void);

RETRO_END_DECLS
Expand Down
20 changes: 16 additions & 4 deletions intl/msg_hash_lbl.h
Expand Up @@ -1490,6 +1490,22 @@ MSG_HASH(
MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE,
"input_libretro_device_p%u"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE,
"input_player%u_analog_dpad_mode"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_DEVICE_INDEX,
"input_device_p%u"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_MOUSE_INDEX,
"input_player%u_mouse_index"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_REMAP_PORT,
"input_remap_port_p%u"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_MAX_USERS,
"input_max_users"
Expand Down Expand Up @@ -1534,10 +1550,6 @@ MSG_HASH(
MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_SCALE,
"input_overlay_auto_scale"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE,
"input_player%u_analog_dpad_mode"
)
MSG_HASH(
MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR,
"input_poll_type_behavior"
Expand Down
4 changes: 4 additions & 0 deletions intl/msg_hash_us.h
Expand Up @@ -2668,6 +2668,10 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX,
"Device Index"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT,
"Mapped Port"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL,
"Set All Controls"
Expand Down
15 changes: 12 additions & 3 deletions menu/cbs/menu_cbs_ok.c
Expand Up @@ -3411,7 +3411,6 @@ static int generic_action_ok_remap_file_operation(const char *path,
{
if (input_remapping_remove_file(file, path_dir_input_remapping))
{
#ifdef HAVE_CONFIGFILE
switch (action_type)
{
case ACTION_OK_REMAP_FILE_REMOVE_CORE:
Expand All @@ -3436,7 +3435,6 @@ static int generic_action_ok_remap_file_operation(const char *path,
}
break;
}
#endif

runloop_msg_queue_push(
msg_hash_to_str(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY),
Expand Down Expand Up @@ -6520,7 +6518,7 @@ static int action_ok_push_dropdown_item_input_device_index(const char *path,
if (!setting)
return menu_cbs_exit();

settings->uints.input_joypad_map[setting->index_offset] = (unsigned)entry_idx;
settings->uints.input_joypad_index[setting->index_offset] = (unsigned)entry_idx;

return action_cancel_pop_default(NULL, NULL, 0, 0);
}
Expand Down Expand Up @@ -6857,6 +6855,17 @@ static int action_ok_disk_index_dropdown_box_list(const char *path,
static int action_ok_input_description_dropdown_box_list(const char *path,
const char *label, unsigned type, size_t idx, size_t entry_idx)
{
menu_handle_t *menu = menu_driver_get_ptr();
unsigned port = string_to_unsigned(label);

if (!menu)
return menu_cbs_exit();

/* Ugly hack: We have no other mechanism for
* passing 'physical' port number to
* menu_cbs_title.c */
menu->scratchpad.unsigned_var = port;

return generic_action_ok_displaylist_push(
path, NULL, label, type, idx, entry_idx,
ACTION_OK_DL_DROPDOWN_BOX_LIST_INPUT_DESCRIPTION);
Expand Down
2 changes: 0 additions & 2 deletions menu/cbs/menu_cbs_start.c
Expand Up @@ -80,10 +80,8 @@ static int action_start_remap_file_load(
const char *path, const char *label,
unsigned type, size_t idx, size_t entry_idx)
{
#ifdef HAVE_CONFIGFILE
input_remapping_deinit();
input_remapping_set_defaults();
#endif
return 0;
}

Expand Down
39 changes: 32 additions & 7 deletions menu/cbs/menu_cbs_sublabel.c
Expand Up @@ -1199,16 +1199,41 @@ static int action_bind_sublabel_remap_sublabel(
const char *label, const char *path,
char *s, size_t len)
{
unsigned offset = (type - MENU_SETTINGS_INPUT_DESC_BEGIN)
/ (RARCH_FIRST_CUSTOM_BIND + 8);
unsigned port;
unsigned mapped_port;
menu_entry_t entry;
settings_t *settings = config_get_ptr();

if (!settings)
return 0;

MENU_ENTRY_INIT(entry);
entry.path_enabled = false;
entry.label_enabled = true;
entry.rich_label_enabled = false;
entry.value_enabled = false;
entry.sublabel_enabled = false;
menu_entry_get(&entry, 0, i, NULL, false);

port = string_to_unsigned(entry.label);

if (port >= MAX_USERS)
return 0;

/* Device name is set per-port
* If the user changes the device index for
* a port, then we are effectively changing
* the port to which the corresponding
* controller is connected... */
mapped_port = settings->uints.input_joypad_index[port];

snprintf(s, len, "%s #%d: %s",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT),
offset + 1,
input_config_get_device_display_name(offset) ?
input_config_get_device_display_name(offset) :
(input_config_get_device_name(offset) ?
input_config_get_device_name(offset) :
port + 1,
input_config_get_device_display_name(mapped_port) ?
input_config_get_device_display_name(mapped_port) :
(input_config_get_device_name(mapped_port) ?
input_config_get_device_name(mapped_port) :
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)));
return 0;
}
Expand Down
19 changes: 17 additions & 2 deletions menu/cbs/menu_cbs_title.c
Expand Up @@ -328,6 +328,11 @@ static int action_get_title_dropdown_item(
(enum_idx <= MENU_ENUM_LABEL_INPUT_MOUSE_INDEX_LAST))
enum_idx = MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX;

/* Mapped Port (virtual -> 'physical' port mapping) */
if ((enum_idx >= MENU_ENUM_LABEL_INPUT_REMAP_PORT) &&
(enum_idx <= MENU_ENUM_LABEL_INPUT_REMAP_PORT_LAST))
enum_idx = MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT;

{
const char *title = msg_hash_to_str(enum_idx);

Expand Down Expand Up @@ -520,8 +525,18 @@ static int action_get_title_dropdown_input_description_common(
static int action_get_title_dropdown_input_description(
const char *path, const char *label, unsigned menu_type, char *s, size_t len)
{
unsigned port = (menu_type - MENU_SETTINGS_INPUT_DESC_BEGIN) /
(RARCH_FIRST_CUSTOM_BIND + 8);
menu_handle_t *menu = menu_driver_get_ptr();
unsigned port;

/* Ugly hack: We have no other mechanism for
* accessing 'physical' port number here
* (Use mapped port if 'menu' is NULL; this
* is better than simply failing...) */
if (menu)
port = menu->scratchpad.unsigned_var;
else
port = (menu_type - MENU_SETTINGS_INPUT_DESC_BEGIN) /
(RARCH_FIRST_CUSTOM_BIND + 8);

return action_get_title_dropdown_input_description_common(
path, port, s, len);
Expand Down
1 change: 1 addition & 0 deletions menu/drivers/ozone/ozone_texture.c
Expand Up @@ -453,6 +453,7 @@ uintptr_t ozone_entries_icon_get_texture(ozone_handle_t *ozone,
case MENU_SETTING_ACTION:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING];
case MENU_SETTINGS_INPUT_LIBRETRO_DEVICE:
case MENU_SETTINGS_INPUT_INPUT_REMAP_PORT:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_SETTING];
case MENU_SETTINGS_INPUT_ANALOG_DPAD_MODE:
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_INPUT_ADC];
Expand Down
1 change: 1 addition & 0 deletions menu/drivers/xmb.c
Expand Up @@ -2946,6 +2946,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
return xmb->textures.list[XMB_TEXTURE_ROOM_RELAY];
#endif
case MENU_SETTINGS_INPUT_LIBRETRO_DEVICE:
case MENU_SETTINGS_INPUT_INPUT_REMAP_PORT:
return xmb->textures.list[XMB_TEXTURE_SETTING];
case MENU_SETTINGS_INPUT_ANALOG_DPAD_MODE:
return xmb->textures.list[XMB_TEXTURE_INPUT_ADC];
Expand Down

0 comments on commit 0e95e5c

Please sign in to comment.