diff --git a/configuration.c b/configuration.c index 6850178974d4..c3bce0ab1e54 100644 --- a/configuration.c +++ b/configuration.c @@ -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++) @@ -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 @@ -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); @@ -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))) @@ -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); @@ -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]); } } @@ -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'; @@ -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; } @@ -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); @@ -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); diff --git a/configuration.h b/configuration.h index 81a2f3cd811f..29f52bfd2eaa 100644 --- a/configuration.h +++ b/configuration.h @@ -122,7 +122,7 @@ 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. @@ -130,9 +130,10 @@ typedef struct settings 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]; diff --git a/input/drivers_joypad/gx_joypad.c b/input/drivers_joypad/gx_joypad.c index 7babd857af6b..8bb1857af1e4 100644 --- a/input/drivers_joypad/gx_joypad.c +++ b/input/drivers_joypad/gx_joypad.c @@ -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) { @@ -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), diff --git a/input/input_remapping.h b/input/input_remapping.h index 668445328b1c..18947e62b9fc 100644 --- a/input/input_remapping.h +++ b/input/input_remapping.h @@ -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 diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 6f98595fc82d..aebd44e3ef73 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -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" @@ -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" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 6c2120f208f9..a3d3e086d25c 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -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" diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 11a2531bf786..ffb7e3a41ec5 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -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: @@ -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), @@ -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); } @@ -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); diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index 90aa1f286788..a66eb1e2337d 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -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; } diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index c44f72106b07..4fdcf7f1677d 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -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; } diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c index a165d231ac95..458a05e3ceee 100644 --- a/menu/cbs/menu_cbs_title.c +++ b/menu/cbs/menu_cbs_title.c @@ -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); @@ -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); diff --git a/menu/drivers/ozone/ozone_texture.c b/menu/drivers/ozone/ozone_texture.c index ead4dcf8a886..8390d858237d 100644 --- a/menu/drivers/ozone/ozone_texture.c +++ b/menu/drivers/ozone/ozone_texture.c @@ -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]; diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index f39ba20744d0..1b8554b63a51 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -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]; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index f88e3e61f295..5d87251e1810 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -1354,7 +1354,7 @@ static unsigned menu_displaylist_parse_system_info(file_list_t *list) MENU_SETTINGS_CORE_INFO_NONE, 0, 0)) count++; snprintf(tmp, sizeof(tmp), " Device config name: %s", - input_config_get_device_display_name(controller) ? + input_config_get_device_config_name(controller) ? input_config_get_device_config_name(controller) : msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)); if (menu_entries_append_enum(list, tmp, "", @@ -4415,7 +4415,7 @@ static int menu_displaylist_parse_input_device_index_list( goto end; port = setting->index_offset; - map = settings->uints.input_joypad_map[port]; + map = settings->uints.input_joypad_index[port]; if (port >= MAX_USERS) goto end; @@ -9577,22 +9577,27 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, const char *menu_driver = menu_driver_ident(); bool is_rgui = string_is_equal(menu_driver, "rgui"); file_list_t *list = info->list; - unsigned p = atoi(info->path); + unsigned port = string_to_unsigned(info->path); + unsigned mapped_port = settings->uints.input_remap_ports[port]; size_t selection = menu_navigation_get_selection(); menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); { - char key_type[PATH_MAX_LENGTH]; - char key_analog[PATH_MAX_LENGTH]; - unsigned val = p + 1; + char key_type[64]; + char key_analog[64]; + char key_port[64]; - key_type[0] = key_analog[0] = '\0'; + key_type[0] = '\0'; + key_analog[0] = '\0'; + key_port[0] = '\0'; snprintf(key_type, sizeof(key_type), - msg_hash_to_str(MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE), val); + msg_hash_to_str(MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE), mapped_port + 1); snprintf(key_analog, sizeof(key_analog), - msg_hash_to_str(MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE), val); + msg_hash_to_str(MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE), mapped_port + 1); + snprintf(key_port, sizeof(key_port), + msg_hash_to_str(MENU_ENUM_LABEL_INPUT_REMAP_PORT), port + 1); if (MENU_DISPLAYLIST_PARSE_SETTINGS(list, key_type, PARSE_ONLY_UINT, true, MENU_SETTINGS_INPUT_LIBRETRO_DEVICE) == 0) @@ -9600,12 +9605,15 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, if (MENU_DISPLAYLIST_PARSE_SETTINGS(list, key_analog, PARSE_ONLY_UINT, true, MENU_SETTINGS_INPUT_ANALOG_DPAD_MODE) == 0) count++; + if (MENU_DISPLAYLIST_PARSE_SETTINGS(list, + key_port, PARSE_ONLY_UINT, true, MENU_SETTINGS_INPUT_INPUT_REMAP_PORT) == 0) + count++; } { unsigned retro_id, j; - unsigned device = settings->uints.input_libretro_device[p]; - device &= RETRO_DEVICE_MASK; + unsigned device = settings->uints.input_libretro_device[mapped_port]; + device &= RETRO_DEVICE_MASK; if (device == RETRO_DEVICE_JOYPAD || device == RETRO_DEVICE_ANALOG) { @@ -9621,10 +9629,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, ? input_config_bind_order[j] : j; keybind = - &input_config_binds[p][retro_id]; + &input_config_binds[port][retro_id]; auto_bind = (const struct retro_keybind*) - input_config_get_bind_auto(p, retro_id); + input_config_get_bind_auto(port, retro_id); input_config_get_bind_string(descriptor, keybind, auto_bind, sizeof(descriptor)); @@ -9632,7 +9640,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, if (!strstr(descriptor, "Auto")) { const struct retro_keybind *keyptr = - &input_config_binds[p][retro_id]; + &input_config_binds[port][retro_id]; snprintf(desc_label, sizeof(desc_label), "%s %s", msg_hash_to_str(keyptr->enum_idx), descriptor); @@ -9646,14 +9654,15 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, && !settings->bools.menu_show_sublabels) { snprintf(desc_label, sizeof(desc_label), - "%s [%s %u]", descriptor, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT), p + 1); + "%s [%s %u]", descriptor, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT), port + 1); strlcpy(descriptor, desc_label, sizeof(descriptor)); } + /* Note: 'physical' port is passed as label */ if (menu_entries_append_enum(list, descriptor, info->path, MSG_UNKNOWN, MENU_SETTINGS_INPUT_DESC_BEGIN + - (p * (RARCH_FIRST_CUSTOM_BIND + 8)) + retro_id, 0, 0)) + (mapped_port * (RARCH_FIRST_CUSTOM_BIND + 8)) + retro_id, 0, 0)) count++; } } @@ -9671,10 +9680,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, ? input_config_bind_order[j] : j; keybind = - &input_config_binds[p][retro_id]; + &input_config_binds[port][retro_id]; auto_bind = (const struct retro_keybind*) - input_config_get_bind_auto(p, retro_id); + input_config_get_bind_auto(port, retro_id); input_config_get_bind_string(descriptor, keybind, auto_bind, sizeof(descriptor)); @@ -9682,7 +9691,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, if (!strstr(descriptor, "Auto")) { const struct retro_keybind *keyptr = - &input_config_binds[p][retro_id]; + &input_config_binds[port][retro_id]; snprintf(desc_label, sizeof(desc_label), "%s %s", msg_hash_to_str(keyptr->enum_idx), descriptor); @@ -9697,14 +9706,15 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, { snprintf(desc_label, sizeof(desc_label), "%s [%s %u]", descriptor, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT), p + 1); + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT), port + 1); strlcpy(descriptor, desc_label, sizeof(descriptor)); } + /* Note: 'physical' port is passed as label */ if (menu_entries_append_enum(list, descriptor, info->path, MSG_UNKNOWN, MENU_SETTINGS_INPUT_DESC_KBD_BEGIN + - (p * RARCH_ANALOG_BIND_LIST_END) + retro_id, 0, 0)) + (mapped_port * RARCH_ANALOG_BIND_LIST_END) + retro_id, 0, 0)) count++; } } diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 1cff563d3000..53563fc1b140 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -188,6 +188,7 @@ enum menu_settings_type MENU_SETTINGS_INPUT_LIBRETRO_DEVICE, MENU_SETTINGS_INPUT_ANALOG_DPAD_MODE, + MENU_SETTINGS_INPUT_INPUT_REMAP_PORT, MENU_SETTINGS_INPUT_BEGIN, MENU_SETTINGS_INPUT_END = MENU_SETTINGS_INPUT_BEGIN + RARCH_CUSTOM_BIND_LIST_END + 6, MENU_SETTINGS_INPUT_DESC_BEGIN, diff --git a/menu/menu_setting.c b/menu/menu_setting.c index a259b4f8d303..993c831e83cf 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -96,6 +96,7 @@ #include "../verbosity.h" #include "../playlist.h" #include "../manual_content_scan.h" +#include "../input/input_remapping.h" #include "../tasks/tasks_internal.h" @@ -5386,6 +5387,37 @@ static int setting_action_left_libretro_device_type( return 0; } +static int setting_action_left_input_remap_port( + rarch_setting_t *setting, size_t idx, bool wraparound) +{ + bool refresh = false; + unsigned port = 0; + settings_t *settings = config_get_ptr(); + + if (!setting) + return -1; + + port = setting->index_offset; + + if (settings->uints.input_remap_ports[port] > 0) + settings->uints.input_remap_ports[port]--; + else + settings->uints.input_remap_ports[port] = MAX_USERS - 1; + + /* Must be called whenever settings->uints.input_remap_ports + * is modified */ + input_remapping_update_port_map(); + + /* Changing mapped port may leave a core port unused; + * reinitialise controllers to ensure that any such + * ports are set to 'RETRO_DEVICE_NONE' */ + command_event(CMD_EVENT_CONTROLLER_INIT, NULL); + + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + return 0; +} + static int setting_uint_action_left_crt_switch_resolution_super( rarch_setting_t *setting, size_t idx, bool wraparound) { @@ -5427,7 +5459,7 @@ static int setting_action_left_bind_device( index_offset = setting->index_offset; - p = &settings->uints.input_joypad_map[index_offset]; + p = &settings->uints.input_joypad_index[index_offset]; if ((*p) >= max_devices) *p = max_devices - 1; @@ -6242,6 +6274,14 @@ static void setting_get_string_representation_uint_analog_dpad_mode( strlcpy(s, modes[*setting->value.target.unsigned_integer % ANALOG_DPAD_LAST], len); } +static void setting_get_string_representation_uint_input_remap_port( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (setting) + snprintf(s, len, "%u", *setting->value.target.unsigned_integer + 1); +} + #ifdef HAVE_THREADS static void setting_get_string_representation_uint_autosave_interval( rarch_setting_t *setting, @@ -6860,7 +6900,7 @@ static int setting_action_start_bind_device(rarch_setting_t *setting) return -1; configuration_set_uint(settings, - settings->uints.input_joypad_map[setting->index_offset], setting->index_offset); + settings->uints.input_joypad_index[setting->index_offset], setting->index_offset); return 0; } @@ -6962,6 +7002,32 @@ static int setting_action_start_libretro_device_type(rarch_setting_t *setting) return 0; } +static int setting_action_start_input_remap_port(rarch_setting_t *setting) +{ + bool refresh = false; + settings_t *settings = config_get_ptr(); + unsigned port; + + if (!setting) + return -1; + + port = setting->index_offset; + settings->uints.input_remap_ports[port] = port; + + /* Must be called whenever settings->uints.input_remap_ports + * is modified */ + input_remapping_update_port_map(); + + /* Changing mapped port may leave a core port unused; + * reinitialise controllers to ensure that any such + * ports are set to 'RETRO_DEVICE_NONE' */ + command_event(CMD_EVENT_CONTROLLER_INIT, NULL); + + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + return 0; +} + static int setting_action_start_video_refresh_rate_auto( rarch_setting_t *setting) { @@ -7045,6 +7111,37 @@ static int setting_action_right_libretro_device_type( return 0; } +static int setting_action_right_input_remap_port( + rarch_setting_t *setting, size_t idx, bool wraparound) +{ + bool refresh = false; + unsigned port = 0; + settings_t *settings = config_get_ptr(); + + if (!setting) + return -1; + + port = setting->index_offset; + + if (settings->uints.input_remap_ports[port] < MAX_USERS - 1) + settings->uints.input_remap_ports[port]++; + else + settings->uints.input_remap_ports[port] = 0; + + /* Must be called whenever settings->uints.input_remap_ports + * is modified */ + input_remapping_update_port_map(); + + /* Changing mapped port may leave a core port unused; + * reinitialise controllers to ensure that any such + * ports are set to 'RETRO_DEVICE_NONE' */ + command_event(CMD_EVENT_CONTROLLER_INIT, NULL); + + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + return 0; +} + static int setting_action_right_bind_device( rarch_setting_t *setting, size_t idx, bool wraparound) { @@ -7058,7 +7155,7 @@ static int setting_action_right_bind_device( index_offset = setting->index_offset; - p = &settings->uints.input_joypad_map[index_offset]; + p = &settings->uints.input_joypad_index[index_offset]; if (*p < max_devices) (*p)++; @@ -7142,7 +7239,7 @@ static void get_string_representation_bind_device(rarch_setting_t *setting, char return; index_offset = setting->index_offset; - map = settings->uints.input_joypad_map[index_offset]; + map = settings->uints.input_joypad_index[index_offset]; if (map < max_devices) { @@ -7213,7 +7310,7 @@ static void general_read_handler(rarch_setting_t *setting) case MENU_ENUM_LABEL_INPUT_PLAYER3_JOYPAD_INDEX: case MENU_ENUM_LABEL_INPUT_PLAYER4_JOYPAD_INDEX: case MENU_ENUM_LABEL_INPUT_PLAYER5_JOYPAD_INDEX: - *setting->value.target.integer = settings->uints.input_joypad_map[setting->enum_idx - MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX]; + *setting->value.target.integer = settings->uints.input_joypad_index[setting->enum_idx - MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX]; break; default: break; @@ -7474,7 +7571,7 @@ static void general_write_handler(rarch_setting_t *setting) { settings_t *settings = config_get_ptr(); settings->modified = true; - settings->uints.input_joypad_map[setting->enum_idx - MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX] = *setting->value.target.integer; + settings->uints.input_joypad_index[setting->enum_idx - MENU_ENUM_LABEL_INPUT_PLAYER1_JOYPAD_INDEX] = *setting->value.target.integer; } break; case MENU_ENUM_LABEL_LOG_TO_FILE: @@ -7865,6 +7962,24 @@ static void general_write_handler(rarch_setting_t *setting) } break; default: + /* Special cases */ + + /* > Mapped Port (virtual -> 'physical' port mapping) + * Occupies a range of enum indices, so cannot + * simply switch on the value */ + if ((setting->enum_idx >= MENU_ENUM_LABEL_INPUT_REMAP_PORT) && + (setting->enum_idx <= MENU_ENUM_LABEL_INPUT_REMAP_PORT_LAST)) + { + /* Must be called whenever settings->uints.input_remap_ports + * is modified */ + input_remapping_update_port_map(); + + /* Changing mapped port may leave a core port unused; + * reinitialise controllers to ensure that any such + * ports are set to 'RETRO_DEVICE_NONE' */ + command_event(CMD_EVENT_CONTROLLER_INIT, NULL); + } + break; } @@ -8398,6 +8513,72 @@ static bool setting_append_list_input_player_options( return true; } +static bool setting_append_list_input_remap_port_options( + rarch_setting_t **list, + rarch_setting_info_t *list_info, + const char *parent_group) +{ + settings_t *settings = config_get_ptr(); + rarch_setting_group_info_t group_info; + rarch_setting_group_info_t subgroup_info; + static char key_port[MAX_USERS][64]; + static char label_port[MAX_USERS][64]; + unsigned user; + + group_info.name = NULL; + subgroup_info.name = NULL; + + START_GROUP(list, list_info, &group_info, + "Mapped Ports", parent_group); + + parent_group = msg_hash_to_str(MENU_ENUM_LABEL_SETTINGS); + + START_SUB_GROUP(list, list_info, "State", &group_info, + &subgroup_info, parent_group); + + for (user = 0; user < MAX_USERS; user++) + { + key_port[user][0] = '\0'; + label_port[user][0] = '\0'; + + snprintf(key_port[user], sizeof(key_port[user]), + msg_hash_to_str(MENU_ENUM_LABEL_INPUT_REMAP_PORT), + user + 1); + + snprintf(label_port[user], sizeof(label_port[user]), "%s", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT)); + + CONFIG_UINT_ALT( + list, list_info, + &settings->uints.input_remap_ports[user], + key_port[user], + label_port[user], + user, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].index = user + 1; + (*list)[list_info->index - 1].index_offset = user; + (*list)[list_info->index - 1].action_left = &setting_action_left_input_remap_port; + (*list)[list_info->index - 1].action_right = &setting_action_right_input_remap_port; + (*list)[list_info->index - 1].action_select = &setting_action_right_input_remap_port; + (*list)[list_info->index - 1].action_start = &setting_action_start_input_remap_port; + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_uint_input_remap_port; + menu_settings_list_current_add_range(list, list_info, 0, MAX_USERS-1, 1.0, true, true); + MENU_SETTINGS_LIST_CURRENT_ADD_ENUM_IDX_PTR(list, list_info, + (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_REMAP_PORT + user)); + } + + END_SUB_GROUP(list, list_info, parent_group); + END_GROUP(list, list_info, parent_group); + + return true; +} + /** * config_get_audio_resampler_driver_options: * @@ -9244,6 +9425,8 @@ static bool setting_append_list( for (user = 0; user < MAX_USERS; user++) setting_append_list_input_player_options(list, list_info, parent_group, user); + setting_append_list_input_remap_port_options(list, list_info, parent_group); + END_SUB_GROUP(list, list_info, parent_group); END_GROUP(list, list_info, parent_group); break; diff --git a/msg_hash.h b/msg_hash.h index 5482a54df0f6..332c27f75be9 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -742,6 +742,9 @@ enum msg_hash_enums MENU_ENUM_LABEL_INPUT_DEVICE_INDEX_LAST = MENU_ENUM_LABEL_INPUT_DEVICE_INDEX + MAX_USERS, MENU_ENUM_LABEL_INPUT_MOUSE_INDEX, MENU_ENUM_LABEL_INPUT_MOUSE_INDEX_LAST = MENU_ENUM_LABEL_INPUT_MOUSE_INDEX + MAX_USERS, + MENU_ENUM_LABEL_INPUT_REMAP_PORT, + MENU_ENUM_LABEL_INPUT_REMAP_PORT_LAST = MENU_ENUM_LABEL_INPUT_REMAP_PORT + MAX_USERS, + MENU_ENUM_LABEL_INPUT_SETTINGS_BEGIN, MENU_LABEL(INPUT_HOTKEY_BINDS), @@ -889,6 +892,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_INDEX, + MENU_ENUM_LABEL_VALUE_INPUT_REMAP_PORT, MENU_ENUM_SUBLABEL_INPUT_META_FAST_FORWARD_KEY, MENU_ENUM_SUBLABEL_INPUT_META_FAST_FORWARD_HOLD_KEY, diff --git a/retroarch.c b/retroarch.c index 4e643c2af72d..664f72bc10bf 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1372,7 +1372,7 @@ bool menu_input_key_bind_set_mode( return false; index_offset = setting->index_offset; - binds->port = settings->uints.input_joypad_map[index_offset]; + binds->port = settings->uints.input_joypad_index[index_offset]; menu_input_key_bind_poll_bind_get_rested_axes( p_rarch->joypad, @@ -1382,7 +1382,7 @@ bool menu_input_key_bind_set_mode( NULL, #endif binds); - menu_input_key_bind_poll_bind_state(p_rarch, settings->uints.input_joypad_map[binds->port], + menu_input_key_bind_poll_bind_state(p_rarch, settings->uints.input_joypad_index[binds->port], binds, false); current_usec = cpu_features_get_time_usec(); @@ -1495,7 +1495,7 @@ static bool menu_input_key_bind_iterate( p_rarch->keyboard_mapping_blocked = false; menu_input_key_bind_poll_bind_state(p_rarch, - settings->uints.input_joypad_map[new_binds.port], + settings->uints.input_joypad_index[new_binds.port], &new_binds, timed_out); #ifdef ANDROID @@ -12139,20 +12139,39 @@ static void command_event_set_mixer_volume( * Initialize libretro controllers. **/ static void command_event_init_controllers(rarch_system_info_t *info, - unsigned num_active_users) + settings_t *settings, unsigned num_active_users) { - unsigned i; - unsigned ports_size = info->ports.size; + unsigned num_core_ports = info->ports.size; + unsigned port; - for (i = 0; i < ports_size; i++) + for (port = 0; port < num_core_ports; port++) { + unsigned device = RETRO_DEVICE_NONE; + const struct retro_controller_description *desc = NULL; retro_ctx_controller_info_t pad; - unsigned device = (i < num_active_users) - ? input_config_get_device(i) - : RETRO_DEVICE_NONE; - const struct retro_controller_description *desc = - libretro_find_controller_description( - &info->ports.data[i], device); + unsigned i; + + /* Check whether current core port is mapped + * to an input device + * > If is not, leave 'device' set to + * 'RETRO_DEVICE_NONE' + * > For example: if input ports 0 and 1 are + * mapped to core port 0, core port 1 will + * be unmapped and should be disabled */ + for (i = 0; i < num_active_users; i++) + { + if (i >= MAX_USERS) + break; + + if (port == settings->uints.input_remap_ports[i]) + { + device = input_config_get_device(port); + break; + } + } + + desc = libretro_find_controller_description( + &info->ports.data[port], device); if (desc && !desc->desc) { @@ -12171,7 +12190,7 @@ static void command_event_init_controllers(rarch_system_info_t *info, } pad.device = device; - pad.port = i; + pad.port = port; core_set_controller_port_device(&pad); } } @@ -12183,46 +12202,6 @@ static void command_event_disable_overrides(struct rarch_state *p_rarch) config_unload_override(); runloop_state.overrides_active = false; } - -void input_remapping_set_defaults(void) -{ - unsigned i, j; - struct rarch_state *p_rarch = &rarch_st; - settings_t *settings = p_rarch->configuration_settings; - global_t *global = &p_rarch->g_extern; - - for (i = 0; i < MAX_USERS; i++) - { - for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++) - { - const struct retro_keybind *keybind = &input_config_binds[i][j]; - if (keybind) - configuration_set_uint(settings, - settings->uints.input_remap_ids[i][j], keybind->id); - configuration_set_uint(settings, - settings->uints.input_keymapper_ids[i][j], RETROK_UNKNOWN); - } - - for (j = RARCH_FIRST_CUSTOM_BIND; j < (RARCH_FIRST_CUSTOM_BIND + 8); j++) - configuration_set_uint(settings, - settings->uints.input_remap_ids[i][j], j); - } - - if (global) - { - for (i = 0; i < MAX_USERS; i++) - { - if (global->old_analog_dpad_mode[i]) - configuration_set_uint(settings, - settings->uints.input_analog_dpad_mode[i], - global->old_analog_dpad_mode[i]); - if (global->old_libretro_device[i]) - configuration_set_uint(settings, - settings->uints.input_libretro_device[i], - global->old_libretro_device[i]); - } - } -} #endif static void command_event_deinit_core( @@ -12254,7 +12233,6 @@ static void command_event_deinit_core( p_rarch->runtime_shader_preset[0] = '\0'; #endif -#ifdef HAVE_CONFIGFILE if ( runloop_state.remaps_core_active || runloop_state.remaps_content_dir_active || runloop_state.remaps_game_active @@ -12263,7 +12241,8 @@ static void command_event_deinit_core( input_remapping_deinit(); input_remapping_set_defaults(); } -#endif + else + input_remapping_restore_global_config(); } #ifdef HAVE_CHEATS @@ -12770,6 +12749,15 @@ static bool command_event_init_core( p_rarch->current_core.retro_set_environment(rarch_environment_cb); + /* Load any input remap files + * > Note that we always cache the current global + * input settings when initialising a core + * (regardless of whether remap files are loaded) + * so settings can be restored when the core is + * unloaded - i.e. core remapping options modified + * at runtime should not 'bleed through' into the + * master config file */ + input_remapping_cache_global_config(); #ifdef HAVE_CONFIGFILE if (auto_remaps_enable) config_load_remap(dir_input_remapping, &runloop_state.system); @@ -13202,18 +13190,147 @@ static bool command_event_resize_windowed_scale(struct rarch_state *p_rarch) return true; } +void input_remapping_cache_global_config(void) +{ + struct rarch_state *p_rarch = &rarch_st; + settings_t *settings = p_rarch->configuration_settings; + global_t *global = &p_rarch->g_extern; + unsigned i; + + for (i = 0; i < MAX_USERS; i++) + { + global->old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; + global->old_analog_dpad_mode_set[i] = true; + + global->old_libretro_device[i] = settings->uints.input_libretro_device[i]; + global->old_libretro_device_set[i] = true; + } +} + +void input_remapping_restore_global_config(void) +{ + struct rarch_state *p_rarch = &rarch_st; + settings_t *settings = p_rarch->configuration_settings; + global_t *global = &p_rarch->g_extern; + unsigned i; + + for (i = 0; i < MAX_USERS; i++) + { + if (global->old_analog_dpad_mode_set[i] && + (settings->uints.input_analog_dpad_mode[i] != + global->old_analog_dpad_mode[i])) + configuration_set_uint(settings, + settings->uints.input_analog_dpad_mode[i], + global->old_analog_dpad_mode[i]); + + if (global->old_libretro_device_set[i] && + (settings->uints.input_libretro_device[i] != + global->old_libretro_device[i])) + configuration_set_uint(settings, + settings->uints.input_libretro_device[i], + global->old_libretro_device[i]); + } +} + +void input_remapping_update_port_map(void) +{ + unsigned i, j; + struct rarch_state *p_rarch = &rarch_st; + settings_t *settings = p_rarch->configuration_settings; + unsigned port_map_index[MAX_USERS] = {0}; + + /* First pass: 'reset' port map */ + for (i = 0; i < MAX_USERS; i++) + for (j = 0; j < (MAX_USERS + 1); j++) + settings->uints.input_remap_port_map[i][j] = MAX_USERS; + + /* Second pass: assign port indices from + * 'input_remap_ports' */ + for (i = 0; i < MAX_USERS; i++) + { + unsigned remap_port = settings->uints.input_remap_ports[i]; + + if (remap_port < MAX_USERS) + { + /* 'input_remap_port_map' provides a list of + * 'physical' ports for each 'virtual' port + * sampled in input_state(). + * (Note: in the following explanation, port + * index starts from 0, rather than the frontend + * display convention of 1) + * For example - the following remap configuration + * will map input devices 0+1 to port 0, and input + * device 2 to port 1 + * > input_remap_ports[0] = 0; + * input_remap_ports[1] = 0; + * input_remap_ports[2] = 1; + * This gives a port map of: + * > input_remap_port_map[0] = { 0, 1, MAX_USERS, ... }; + * input_remap_port_map[1] = { 2, MAX_USERS, ... } + * input_remap_port_map[2] = { MAX_USERS, ... } + * ... + * A port map value of MAX_USERS indicates the end + * of the 'physical' port list */ + settings->uints.input_remap_port_map[remap_port] + [port_map_index[remap_port]] = i; + port_map_index[remap_port]++; + } + } +} + void input_remapping_deinit(void) { struct rarch_state *p_rarch = &rarch_st; - global_t *global = &p_rarch->g_extern; - if (!string_is_empty(global->name.remapfile)) + global_t *global = &p_rarch->g_extern; + if (global->name.remapfile) free(global->name.remapfile); - global->name.remapfile = NULL; + global->name.remapfile = NULL; runloop_state.remaps_core_active = false; runloop_state.remaps_content_dir_active = false; runloop_state.remaps_game_active = false; } +void input_remapping_set_defaults(void) +{ + unsigned i, j; + struct rarch_state *p_rarch = &rarch_st; + settings_t *settings = p_rarch->configuration_settings; + + for (i = 0; i < MAX_USERS; i++) + { + /* Button/keyboard remaps */ + for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++) + { + const struct retro_keybind *keybind = &input_config_binds[i][j]; + if (keybind) + configuration_set_uint(settings, + settings->uints.input_remap_ids[i][j], keybind->id); + configuration_set_uint(settings, + settings->uints.input_keymapper_ids[i][j], RETROK_UNKNOWN); + } + + /* Analog stick remaps */ + for (j = RARCH_FIRST_CUSTOM_BIND; j < (RARCH_FIRST_CUSTOM_BIND + 8); j++) + configuration_set_uint(settings, + settings->uints.input_remap_ids[i][j], j); + + /* Controller port remaps */ + configuration_set_uint(settings, + settings->uints.input_remap_ports[i], i); + } + + /* Need to call 'input_remapping_update_port_map()' + * whenever 'settings->uints.input_remap_ports' + * is modified */ + input_remapping_update_port_map(); + + /* Restore 'global' settings that were cached on + * the last core init + * > Prevents remap changes from 'bleeding through' + * into the main config file */ + input_remapping_restore_global_config(); +} + static bool input_driver_grab_mouse(struct rarch_state *p_rarch) { if (!p_rarch->current_input || !p_rarch->current_input->grab_mouse) @@ -13810,7 +13927,6 @@ bool command_event(enum event_command cmd, void *data) video_driver_restore_cached(p_rarch, settings); -#ifdef HAVE_CONFIGFILE if ( runloop_state.remaps_core_active || runloop_state.remaps_content_dir_active || runloop_state.remaps_game_active @@ -13819,7 +13935,8 @@ bool command_event(enum event_command cmd, void *data) input_remapping_deinit(); input_remapping_set_defaults(); } -#endif + else + input_remapping_restore_global_config(); if (is_inited) { @@ -15120,9 +15237,8 @@ bool command_event(enum event_command cmd, void *data) { rarch_system_info_t *info = &runloop_state.system; if (info) - command_event_init_controllers(info, - p_rarch->input_driver_max_users - ); + command_event_init_controllers(info, settings, + p_rarch->input_driver_max_users); } break; case CMD_EVENT_NONE: @@ -22313,7 +22429,7 @@ bool input_driver_set_rumble_state(unsigned port, const input_device_driver_t *sec_joypad = NULL; #endif bool rumble_state = false; - unsigned joy_idx = settings->uints.input_joypad_map[port]; + unsigned joy_idx = settings->uints.input_joypad_index[port]; if (joy_idx >= MAX_USERS) return false; @@ -22455,8 +22571,9 @@ static void input_driver_poll(void) for (i = 0; i < max_users; i++) { joypad_info[i].axis_threshold = p_rarch->input_driver_axis_threshold; - joypad_info[i].joy_idx = settings->uints.input_joypad_map[i]; + joypad_info[i].joy_idx = settings->uints.input_joypad_index[i]; joypad_info[i].auto_binds = input_autoconf_binds[joypad_info[i].joy_idx]; + p_rarch->input_driver_turbo_btns.frame_enable[i] = p_rarch->libretro_input_binds[i][RARCH_TURBO_ENABLE].valid ? input_state_wrap( p_rarch->current_input, @@ -22478,7 +22595,8 @@ static void input_driver_poll(void) settings, p_rarch->overlay_ptr, input_overlay_opacity, - settings->uints.input_analog_dpad_mode[0], + settings->uints.input_analog_dpad_mode[ + settings->uints.input_remap_ports[0]], p_rarch->input_driver_axis_threshold); #endif @@ -22500,13 +22618,11 @@ static void input_driver_poll(void) for (i = 0; i < max_users; i++) { input_bits_t current_inputs; - unsigned device - = settings->uints.input_libretro_device[i] - & RETRO_DEVICE_MASK; - input_bits_t *p_new_state - = (input_bits_t*)¤t_inputs; - unsigned input_analog_dpad_mode = - settings->uints.input_analog_dpad_mode[i]; + unsigned mapped_port = settings->uints.input_remap_ports[i]; + unsigned device = settings->uints.input_libretro_device[mapped_port] + & RETRO_DEVICE_MASK; + input_bits_t *p_new_state = (input_bits_t*)¤t_inputs; + unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[mapped_port]; switch (device) { @@ -22591,8 +22707,8 @@ static void input_driver_poll(void) for (j = 0; j < RARCH_CUSTOM_BIND_LIST_END; j++) { unsigned current_button_value; - unsigned remap_key = - settings->uints.input_keymapper_ids[i][j]; + unsigned remap_key = + settings->uints.input_keymapper_ids[mapped_port][j]; if (remap_key == RETROK_UNKNOWN) continue; @@ -22665,9 +22781,9 @@ static void input_driver_poll(void) { bool remap_valid; unsigned remap_button = - settings->uints.input_remap_ids[i][j]; + settings->uints.input_remap_ids[mapped_port][j]; unsigned current_button_value = - BIT256_GET_PTR(p_new_state, j); + BIT256_GET_PTR(p_new_state, j); #ifdef HAVE_OVERLAY if (poll_overlay && i == 0) @@ -22722,7 +22838,7 @@ static void input_driver_poll(void) unsigned k = (unsigned)j + RARCH_FIRST_CUSTOM_BIND; int16_t current_axis_value = p_new_state->analogs[j]; unsigned remap_axis = - settings->uints.input_remap_ids[i][k]; + settings->uints.input_remap_ids[mapped_port][k]; if ( (abs(current_axis_value) > 0 && @@ -22831,7 +22947,8 @@ static int16_t input_state_device( unsigned idx, unsigned id, bool button_mask) { - int16_t res = 0; + unsigned mapped_port = settings->uints.input_remap_ports[port]; + int16_t res = 0; switch (device) { @@ -22849,7 +22966,7 @@ static int16_t input_state_device( { bool bind_valid = p_rarch->libretro_input_binds[port] && p_rarch->libretro_input_binds[port][id].valid; - unsigned remap_button = settings->uints.input_remap_ids[port][id]; + unsigned remap_button = settings->uints.input_remap_ids[mapped_port][id]; /* TODO/FIXME: What on earth is this code doing...? */ if (! @@ -23071,10 +23188,10 @@ static int16_t input_state_device( (idx * 4) + (id * 2); if (settings->uints.input_remap_ids - [port][offset] != offset) + [mapped_port][offset] != offset) reset_state = true; else if (settings->uints.input_remap_ids - [port][offset+1] != (offset+1)) + [mapped_port][offset+1] != (offset+1)) reset_state = true; } @@ -23156,26 +23273,32 @@ static int16_t input_state(unsigned port, unsigned device, unsigned idx, unsigned id) { rarch_joypad_info_t joypad_info; - struct rarch_state *p_rarch = &rarch_st; - settings_t *settings = p_rarch->configuration_settings; - float input_analog_deadzone = settings->floats.input_analog_deadzone; - float input_analog_sensitivity = settings->floats.input_analog_sensitivity; - unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[port]; - int16_t result = 0; - int16_t ret = 0; + unsigned mapped_port; + struct rarch_state *p_rarch = &rarch_st; + settings_t *settings = p_rarch->configuration_settings; + float input_analog_deadzone = settings->floats.input_analog_deadzone; + float input_analog_sensitivity = settings->floats.input_analog_sensitivity; + unsigned input_analog_dpad_mode = settings->uints.input_analog_dpad_mode[port]; + unsigned *input_remap_port_map = settings->uints.input_remap_port_map[port]; + const input_device_driver_t *joypad = p_rarch->joypad; #ifdef HAVE_MFI - const input_device_driver_t - *sec_joypad = p_rarch->sec_joypad; + const input_device_driver_t *sec_joypad = p_rarch->sec_joypad; #else - const input_device_driver_t - *sec_joypad = NULL; + const input_device_driver_t *sec_joypad = NULL; #endif + bool input_blocked = (p_rarch->input_driver_flushing_input > 0) || + p_rarch->input_driver_block_libretro_input; + bool bitmask_enabled = false; + unsigned max_users = p_rarch->input_driver_max_users; + int16_t result = 0; - joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold; - joypad_info.joy_idx = settings->uints.input_joypad_map[port]; - joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; + device &= RETRO_DEVICE_MASK; + bitmask_enabled = (device == RETRO_DEVICE_JOYPAD) && + (id == RETRO_DEVICE_ID_JOYPAD_MASK); + joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold; #ifdef HAVE_BSV_MOVIE + /* Load input from BSV record, if enabled */ if (BSV_MOVIE_IS_PLAYBACK_ON()) { int16_t bsv_result; @@ -23191,97 +23314,136 @@ static int16_t input_state(unsigned port, unsigned device, } #endif - device &= RETRO_DEVICE_MASK; - ret = input_state_wrap( - p_rarch->current_input, - p_rarch->current_input_data, - p_rarch->joypad, - sec_joypad, - &joypad_info, - p_rarch->libretro_input_binds, - p_rarch->keyboard_mapping_blocked, - port, device, idx, id); - - if ( (device == RETRO_DEVICE_ANALOG) && - (ret == 0)) + /* Loop over all 'physical' ports mapped to specified + * 'virtual' port index */ + while ((mapped_port = *(input_remap_port_map++)) < MAX_USERS) { - const input_device_driver_t *joypad = p_rarch->joypad; -#ifdef HAVE_MFI - const input_device_driver_t *sec_joypad = p_rarch->sec_joypad; -#else - const input_device_driver_t *sec_joypad = NULL; -#endif - if (p_rarch->libretro_input_binds[port]) + int16_t ret = 0; + int16_t port_result = 0; + joypad_info.joy_idx = settings->uints.input_joypad_index[mapped_port]; + joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; + + /* Skip disabled input devices */ + if (mapped_port >= max_users) + continue; + + /* TODO/FIXME: This code is gibberish - a mess of nested + * refactors that make no sense whatsoever. The entire + * thing needs to be rewritten from scratch... */ + + ret = input_state_wrap( + p_rarch->current_input, + p_rarch->current_input_data, + joypad, + sec_joypad, + &joypad_info, + p_rarch->libretro_input_binds, + p_rarch->keyboard_mapping_blocked, + mapped_port, device, idx, id); + + if ((device == RETRO_DEVICE_ANALOG) && + (ret == 0)) { - if (idx == RETRO_DEVICE_INDEX_ANALOG_BUTTON) + if (p_rarch->libretro_input_binds[mapped_port]) { - if (id < RARCH_FIRST_CUSTOM_BIND) + if (idx == RETRO_DEVICE_INDEX_ANALOG_BUTTON) { - bool valid_bind = - p_rarch->libretro_input_binds[port][id].valid; - if (valid_bind) + if (id < RARCH_FIRST_CUSTOM_BIND) { - if (sec_joypad) - ret = - input_joypad_analog_button( + bool valid_bind = p_rarch->libretro_input_binds[mapped_port][id].valid; + + if (valid_bind) + { + if (sec_joypad) + ret = input_joypad_analog_button( input_analog_deadzone, input_analog_sensitivity, sec_joypad, &joypad_info, id, - &p_rarch->libretro_input_binds[port][id]); - if (joypad && (ret == 0)) - ret = input_joypad_analog_button( - input_analog_deadzone, - input_analog_sensitivity, - joypad, &joypad_info, - id, - &p_rarch->libretro_input_binds[port][id]); + &p_rarch->libretro_input_binds[mapped_port][id]); + + if (joypad && (ret == 0)) + ret = input_joypad_analog_button( + input_analog_deadzone, + input_analog_sensitivity, + joypad, &joypad_info, + id, + &p_rarch->libretro_input_binds[mapped_port][id]); + } } } + else + { + if (sec_joypad) + ret = input_joypad_analog_axis( + input_analog_dpad_mode, + input_analog_deadzone, + input_analog_sensitivity, + sec_joypad, + &joypad_info, + idx, + id, + p_rarch->libretro_input_binds[mapped_port]); + + if (joypad && (ret == 0)) + ret = input_joypad_analog_axis( + input_analog_dpad_mode, + input_analog_deadzone, + input_analog_sensitivity, + joypad, + &joypad_info, + idx, + id, + p_rarch->libretro_input_binds[mapped_port]); + } } - else + } + + if (!input_blocked) + { + input_mapper_t *handle = &p_rarch->input_driver_mapper; + + if (bitmask_enabled) { - if (sec_joypad) - ret = input_joypad_analog_axis( - input_analog_dpad_mode, - input_analog_deadzone, - input_analog_sensitivity, - sec_joypad, - &joypad_info, - idx, - id, - p_rarch->libretro_input_binds[port]); - if (joypad && (ret == 0)) - ret = input_joypad_analog_axis( - input_analog_dpad_mode, - input_analog_deadzone, - input_analog_sensitivity, - joypad, - &joypad_info, - idx, - id, - p_rarch->libretro_input_binds[port]); - } - } - } - - if ( (p_rarch->input_driver_flushing_input == 0) - && !p_rarch->input_driver_block_libretro_input) - { - input_mapper_t *handle = &p_rarch->input_driver_mapper; - if ( (device == RETRO_DEVICE_JOYPAD) && - (id == RETRO_DEVICE_ID_JOYPAD_MASK)) + unsigned i; + for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++) + if (input_state_device(p_rarch, settings, handle, + ret, mapped_port, device, idx, i, true)) + port_result |= (1 << i); + } + else + port_result = input_state_device(p_rarch, settings, handle, + ret, mapped_port, device, idx, id, false); + } + + /* Digital values are represented by a bitmap; + * we can just perform the logical OR of + * successive samples. + * Analog values are an integer corresponding + * to the extent of the analog motion; these + * cannot be OR'd together, we must instead + * keep the value with the largest magnitude */ + if (device == RETRO_DEVICE_ANALOG) { - unsigned i; - for (i = 0; i < RARCH_FIRST_CUSTOM_BIND; i++) - if (input_state_device(p_rarch, settings, handle, ret, port, device, idx, i, true)) - result |= (1 << i); + if (result == 0) + result = port_result; + else + { + int16_t port_result_abs = (port_result >= 0) ? + port_result : -port_result; + int16_t result_abs = (result >= 0) ? + result : -result; + + result = (port_result_abs > result_abs) ? + port_result : result; + } } else - result = input_state_device(p_rarch, settings, handle, ret, port, device, idx, id, false); + result |= port_result; } #ifdef HAVE_BSV_MOVIE + /* Save input to BSV record, if enabled */ if (BSV_MOVIE_IS_PLAYBACK_OFF()) { result = swap_if_big16(result); @@ -27013,7 +27175,7 @@ const struct retro_keybind *input_config_get_bind_auto( { struct rarch_state *p_rarch = &rarch_st; settings_t *settings = p_rarch->configuration_settings; - unsigned joy_idx = settings->uints.input_joypad_map[port]; + unsigned joy_idx = settings->uints.input_joypad_index[port]; if (joy_idx < MAX_USERS) return &input_autoconf_binds[joy_idx][id]; @@ -37086,7 +37248,6 @@ bool retroarch_main_quit(void) p_rarch->runtime_shader_preset[0] = '\0'; #endif -#ifdef HAVE_CONFIGFILE if ( runloop_state.remaps_core_active || runloop_state.remaps_content_dir_active || runloop_state.remaps_game_active @@ -37095,7 +37256,8 @@ bool retroarch_main_quit(void) input_remapping_deinit(); input_remapping_set_defaults(); } -#endif + else + input_remapping_restore_global_config(); } runloop_state.shutdown_initiated = true; @@ -37437,7 +37599,7 @@ static enum runloop_state runloop_check_state( *sec_joypad = NULL; #endif - joypad_info.joy_idx = settings->uints.input_joypad_map[port]; + joypad_info.joy_idx = settings->uints.input_joypad_index[port]; joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; joypad_info.axis_threshold = p_rarch->input_driver_axis_threshold; @@ -38693,13 +38855,16 @@ int runloop_iterate(void) /* Update binds for analog dpad modes. */ for (i = 0; i < max_users; i++) { - enum analog_dpad_mode dpad_mode = (enum analog_dpad_mode)settings->uints.input_analog_dpad_mode[i]; + unsigned mapped_port = settings->uints.input_remap_ports[i]; + enum analog_dpad_mode dpad_mode = (enum analog_dpad_mode) + settings->uints.input_analog_dpad_mode[mapped_port]; if (dpad_mode != ANALOG_DPAD_NONE) { unsigned k; - struct retro_keybind *general_binds = input_config_binds[i]; - struct retro_keybind *auto_binds = input_autoconf_binds[i]; + unsigned joy_idx = settings->uints.input_joypad_index[i]; + struct retro_keybind *general_binds = input_config_binds[joy_idx]; + struct retro_keybind *auto_binds = input_autoconf_binds[joy_idx]; unsigned x_plus = RARCH_ANALOG_RIGHT_X_PLUS; unsigned y_plus = RARCH_ANALOG_RIGHT_Y_PLUS; unsigned x_minus = RARCH_ANALOG_RIGHT_X_MINUS; @@ -38786,15 +38951,18 @@ int runloop_iterate(void) for (i = 0; i < max_users; i++) { - unsigned j; - enum analog_dpad_mode dpad_mode = (enum analog_dpad_mode)settings->uints.input_analog_dpad_mode[i]; + unsigned mapped_port = settings->uints.input_remap_ports[i]; + enum analog_dpad_mode dpad_mode = (enum analog_dpad_mode) + settings->uints.input_analog_dpad_mode[mapped_port]; /* Restores analog D-pad binds temporarily overridden. */ if (dpad_mode != ANALOG_DPAD_NONE) { - struct retro_keybind *general_binds = input_config_binds[i]; - struct retro_keybind *auto_binds = input_autoconf_binds[i]; + unsigned j; + unsigned joy_idx = settings->uints.input_joypad_index[i]; + struct retro_keybind *general_binds = input_config_binds[joy_idx]; + struct retro_keybind *auto_binds = input_autoconf_binds[joy_idx]; for (j = RETRO_DEVICE_ID_JOYPAD_UP; j <= RETRO_DEVICE_ID_JOYPAD_RIGHT; j++) { diff --git a/retroarch.h b/retroarch.h index 682fc115eb86..11bde8e8f814 100644 --- a/retroarch.h +++ b/retroarch.h @@ -287,6 +287,8 @@ typedef struct global } console; unsigned old_analog_dpad_mode[MAX_USERS]; unsigned old_libretro_device[MAX_USERS]; + bool old_analog_dpad_mode_set[MAX_USERS]; + bool old_libretro_device_set[MAX_USERS]; /* Settings and/or global states specific to menus */ #ifdef HAVE_MENU enum menu_action menu_prev_action; diff --git a/retroarch_data.h b/retroarch_data.h index 9e4ab8a71c4b..387c1fdf30ed 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -1702,10 +1702,10 @@ struct runloop bool autosave; #ifdef HAVE_CONFIGFILE bool overrides_active; +#endif bool remaps_core_active; bool remaps_game_active; bool remaps_content_dir_active; -#endif #ifdef HAVE_SCREENSHOTS bool max_frames_screenshot; char max_frames_screenshot_path[PATH_MAX_LENGTH];