diff --git a/.gitignore b/.gitignore
index 996bbf24375..edf85f05ed0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,7 +57,6 @@ xcuserdata
profile
*.moved-aside
DerivedData
-.idea/
*.hmap
apple/tmp
apple/*.mobileprovision
@@ -249,3 +248,4 @@ param.sfo
# Visual Studio Code
.vscode/
+/.gdbinit
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 00000000000..13566b81b01
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/fileColors.xml b/.idea/fileColors.xml
new file mode 100644
index 00000000000..42fef831cf9
--- /dev/null
+++ b/.idea/fileColors.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000000..8d66637cb9f
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000000..2e8a9ca1aa4
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/scopes/Dependencies.xml b/.idea/scopes/Dependencies.xml
new file mode 100644
index 00000000000..b457b64c18e
--- /dev/null
+++ b/.idea/scopes/Dependencies.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 00000000000..35eb1ddfbbc
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config.def.keybinds.h b/config.def.keybinds.h
index d86c8b6413e..0ed94fde2f3 100644
--- a/config.def.keybinds.h
+++ b/config.def.keybinds.h
@@ -18,6 +18,36 @@
#ifndef __CONFIG_DEF_KEYBINDS_H
#define __CONFIG_DEF_KEYBINDS_H
+#define JOYPAD_LOGICAL_ENTRY(index) {\
+ NULL, NULL,\
+ AXIS_NONE, AXIS_NONE, AXIS_NONE,\
+ MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LOGICAL, RETROK_UNKNOWN,\
+ RARCH_EXTRA_CORE_COMMAND_START + (index), NO_BTN, NO_BTN, 0,\
+ true\
+ }
+#define JOYPAD_LOGICAL_ENTRY_TEN(base) \
+ JOYPAD_LOGICAL_ENTRY(base), \
+ JOYPAD_LOGICAL_ENTRY(base + 1), \
+ JOYPAD_LOGICAL_ENTRY(base + 2), \
+ JOYPAD_LOGICAL_ENTRY(base + 3), \
+ JOYPAD_LOGICAL_ENTRY(base + 4), \
+ JOYPAD_LOGICAL_ENTRY(base + 5), \
+ JOYPAD_LOGICAL_ENTRY(base + 6), \
+ JOYPAD_LOGICAL_ENTRY(base + 7), \
+ JOYPAD_LOGICAL_ENTRY(base + 8), \
+ JOYPAD_LOGICAL_ENTRY(base + 9)
+#define JOYPAD_LOGICAL_ENTRY_HUNDRED(base) \
+ JOYPAD_LOGICAL_ENTRY_TEN(base), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 10), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 20), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 30), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 40), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 50), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 60), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 70), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 80), \
+ JOYPAD_LOGICAL_ENTRY_TEN(base + 90)
+
#ifndef IS_SALAMANDER
/* User 1 */
@@ -1927,6 +1957,20 @@ static const struct retro_keybind retro_keybinds_1[] = {
RARCH_OSK, NO_BTN, NO_BTN, 0,
true
},
+
+ /* 128 Logical extra joypad buttons. */
+ JOYPAD_LOGICAL_ENTRY_HUNDRED(0),
+ JOYPAD_LOGICAL_ENTRY_TEN(100),
+ JOYPAD_LOGICAL_ENTRY_TEN(110),
+ JOYPAD_LOGICAL_ENTRY(120),
+ JOYPAD_LOGICAL_ENTRY(121),
+ JOYPAD_LOGICAL_ENTRY(122),
+ JOYPAD_LOGICAL_ENTRY(123),
+ JOYPAD_LOGICAL_ENTRY(124),
+ JOYPAD_LOGICAL_ENTRY(125),
+ JOYPAD_LOGICAL_ENTRY(126),
+ JOYPAD_LOGICAL_ENTRY(127),
+
#if 0
/* Deprecated */
{
@@ -2194,6 +2238,27 @@ static const struct retro_keybind retro_keybinds_rest[] = {
RARCH_TURBO_ENABLE, NO_BTN, NO_BTN, 0,
true
},
+
+ {
+ NULL, NULL,
+ AXIS_NONE, AXIS_NONE, AXIS_NONE,
+ MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LOGICAL, RETROK_UNKNOWN,
+ RARCH_EXTRA_CORE_COMMAND_START, NO_BTN, NO_BTN, 0,
+ true
+ },
+
+ /* 128 Logical extra joypad buttons. */
+ JOYPAD_LOGICAL_ENTRY_HUNDRED(0),
+ JOYPAD_LOGICAL_ENTRY_TEN(100),
+ JOYPAD_LOGICAL_ENTRY_TEN(110),
+ JOYPAD_LOGICAL_ENTRY(120),
+ JOYPAD_LOGICAL_ENTRY(121),
+ JOYPAD_LOGICAL_ENTRY(122),
+ JOYPAD_LOGICAL_ENTRY(123),
+ JOYPAD_LOGICAL_ENTRY(124),
+ JOYPAD_LOGICAL_ENTRY(125),
+ JOYPAD_LOGICAL_ENTRY(126),
+ JOYPAD_LOGICAL_ENTRY(127),
};
#endif
diff --git a/configuration.c b/configuration.c
index 4bdaa69509f..d1bc1c6e318 100644
--- a/configuration.c
+++ b/configuration.c
@@ -282,6 +282,26 @@ enum midi_driver_enum
#define DECLARE_BIND(base, bind, desc) { #base, desc, 0, bind, true }
#define DECLARE_META_BIND(level, base, bind, desc) { #base, desc, level, bind, true }
+#define DECLARE_EXTRA_BIND_PASTE2(a, b) a##b
+#define DECLARE_EXTRA_BIND_PASTE(a, b) DECLARE_EXTRA_BIND_PASTE2(a, b)
+#define DECLARE_EXTRA_BIND_STRINGY2(a) #a
+#define DECLARE_EXTRA_BIND_STRINGY(a) DECLARE_EXTRA_BIND_STRINGY2(a)
+
+/** Declare an extra logical bind, the label used depends on the core. */
+#define DECLARE_EXTRA_BIND(id) {DECLARE_EXTRA_BIND_STRINGY(DECLARE_EXTRA_BIND_PASTE(log, id)), MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LOGICAL, 0, id, true }
+
+/** Declare ten binds. */
+#define DECLARE_EXTRA_BIND_10(dig) \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 0)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 1)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 2)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 3)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 4)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 5)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 6)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 7)), \
+ DECLARE_EXTRA_BIND(DECLARE_EXTRA_BIND_PASTE(dig, 9))
+
const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
DECLARE_BIND(b, RETRO_DEVICE_ID_JOYPAD_B, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B),
DECLARE_BIND(y, RETRO_DEVICE_ID_JOYPAD_Y, MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y),
@@ -394,12 +414,50 @@ const struct input_bind_map input_config_bind_map[RARCH_BIND_LIST_END_NULL] = {
DECLARE_META_BIND(2, overlay_next, RARCH_OVERLAY_NEXT, MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT),
DECLARE_META_BIND(2, osk_toggle, RARCH_OSK, MENU_ENUM_LABEL_VALUE_INPUT_META_OSK),
+
+ /* Extra keys, all of them. */
+ DECLARE_EXTRA_BIND(0),
+ DECLARE_EXTRA_BIND(1),
+ DECLARE_EXTRA_BIND(2),
+ DECLARE_EXTRA_BIND(3),
+ DECLARE_EXTRA_BIND(4),
+ DECLARE_EXTRA_BIND(5),
+ DECLARE_EXTRA_BIND(6),
+ DECLARE_EXTRA_BIND(7),
+ DECLARE_EXTRA_BIND(8),
+ DECLARE_EXTRA_BIND(9),
+ DECLARE_EXTRA_BIND_10(1),
+ DECLARE_EXTRA_BIND_10(2),
+ DECLARE_EXTRA_BIND_10(3),
+ DECLARE_EXTRA_BIND_10(4),
+ DECLARE_EXTRA_BIND_10(5),
+ DECLARE_EXTRA_BIND_10(6),
+ DECLARE_EXTRA_BIND_10(7),
+ DECLARE_EXTRA_BIND_10(8),
+ DECLARE_EXTRA_BIND_10(9),
+ DECLARE_EXTRA_BIND_10(10),
+ DECLARE_EXTRA_BIND_10(11),
+ DECLARE_EXTRA_BIND(120),
+ DECLARE_EXTRA_BIND(121),
+ DECLARE_EXTRA_BIND(122),
+ DECLARE_EXTRA_BIND(123),
+ DECLARE_EXTRA_BIND(124),
+ DECLARE_EXTRA_BIND(125),
+ DECLARE_EXTRA_BIND(126),
+ DECLARE_EXTRA_BIND(127),
+
#if 0
/* Deprecated */
DECLARE_META_BIND(2, send_debug_info, RARCH_SEND_DEBUG_INFO, MENU_ENUM_LABEL_VALUE_INPUT_META_SEND_DEBUG_INFO),
#endif
};
+#undef DECLARE_EXTRA_BIND_PASTE2
+#undef DECLARE_EXTRA_BIND_PASTE
+#undef DECLARE_EXTRA_BIND_STRINGY2
+#undef DECLARE_EXTRA_BIND_STRINGY
+#undef DECLARE_EXTRA_BIND_10
+
#if defined(HAVE_METAL)
#if defined(HAVE_VULKAN)
/* Default to Vulkan/MoltenVK when available */
@@ -5669,6 +5727,61 @@ bool config_replace(bool config_replace_save_on_exit, char *path)
return task_push_start_dummy_core(&content_info);
}
+/**
+ * Returns the key string for a given logical game controller button.
+ *
+ * @param logical The input logical button.
+ * @return The character string for the given key.
+ * @since 2023/12/24
+ */
+static const char* rarch_input_get_key_string(rarch_logical_bind_id logical)
+{
+#define BUF_SIZE 8
+ static char key_strings[rarch_num_bind_game_controller()][BUF_SIZE] =
+ {
+ "b", "y", "select", "start",
+ "up", "down", "left", "right",
+ "a", "x", "l", "r",
+ "l2", "r2", "l3", "r3",
+ "l_x+", "l_x-", "l_y+", "l_y-",
+ "r_x+", "r_x-", "r_y+", "r_y-",
+
+ /* Light gun is only here because of the mixing between defines,
+ * This creates a difficult situation where we do not want to
+ * include it, but we must. */
+ "loggtr",
+ "loggrl",
+ "loggaa",
+ "loggab",
+ "loggac",
+ "loggst",
+ "loggsl",
+ "loggdu",
+ "loggdd",
+ "loggdl",
+ "loggdr",
+
+ /* Turbo as well. */
+ "logtrb"
+ };
+
+ /* Not valid at all. */
+ if (logical < 0 || logical >= rarch_num_bind_game_controller())
+ return NULL;
+
+ /* Is the key already filled in? */
+ if (key_strings[logical][0] != 0)
+ return key_strings[logical];
+
+ /* Just use a generic logical name for the key. */
+ snprintf(key_strings[logical], BUF_SIZE - 1, "log%d", logical);
+ key_strings[logical][BUF_SIZE - 1] = 0;
+
+ /* It can now be used. */
+ return key_strings[logical];
+#undef BUF_SIZE
+}
+
/**
* input_remapping_load_file:
* @data : Path to config file.
@@ -5679,15 +5792,10 @@ bool config_replace(bool config_replace_save_on_exit, char *path)
**/
bool input_remapping_load_file(void *data, const char *path)
{
- unsigned i, j;
+ unsigned usernum, logical;
config_file_t *conf = (config_file_t*)data;
settings_t *settings = config_st;
runloop_state_t *runloop_st = runloop_state_get_ptr();
- char key_strings[RARCH_FIRST_CUSTOM_BIND + 8][8] = {
- "b", "y", "select", "start",
- "up", "down", "left", "right",
- "a", "x", "l", "r", "l2", "r2",
- "l3", "r3", "l_x+", "l_x-", "l_y+", "l_y-", "r_x+", "r_x-", "r_y+", "r_y-" };
if ( !conf
|| string_is_empty(path))
@@ -5699,14 +5807,14 @@ bool input_remapping_load_file(void *data, const char *path)
input_remapping_set_defaults(false);
runloop_st->name.remapfile = strdup(path);
- for (i = 0; i < MAX_USERS; i++)
+ for (usernum = 0; usernum < MAX_USERS; usernum++)
{
size_t _len;
char prefix[16];
char s1[32], s2[32], s3[32];
char formatted_number[4];
formatted_number[0] = '\0';
- snprintf(formatted_number, sizeof(formatted_number), "%u", i + 1);
+ snprintf(formatted_number, sizeof(formatted_number), "%u", usernum + 1);
_len = strlcpy(prefix, "input_player", sizeof(prefix));
strlcpy(prefix + _len, formatted_number, sizeof(prefix) - _len);
_len = strlcpy(s1, prefix, sizeof(s1));
@@ -5716,11 +5824,11 @@ bool input_remapping_load_file(void *data, const char *path)
_len = strlcpy(s3, prefix, sizeof(s3));
strlcpy(s3 + _len, "_stk", sizeof(s3) - _len);
- for (j = 0; j < RARCH_FIRST_CUSTOM_BIND + 8; j++)
+ for (logical = 0; logical < rarch_num_bind_game_controller(); logical++)
{
- const char *key_string = key_strings[j];
+ const char *key_string = rarch_input_get_key_string(logical);
- if (j < RARCH_FIRST_CUSTOM_BIND)
+ if (rarch_logical_bind_is_basic(logical))
{
int btn_remap = -1;
int key_remap = -1;
@@ -5738,14 +5846,14 @@ bool input_remapping_load_file(void *data, const char *path)
btn_remap = RARCH_UNMAPPED;
configuration_set_uint(settings,
- settings->uints.input_remap_ids[i][j], btn_remap);
+ settings->uints.input_remap_ids[usernum][logical], btn_remap);
}
if (!config_get_int(conf, key_ident, &key_remap))
key_remap = RETROK_UNKNOWN;
configuration_set_uint(settings,
- settings->uints.input_keymapper_ids[i][j], key_remap);
+ settings->uints.input_keymapper_ids[usernum][logical], key_remap);
}
else
{
@@ -5763,7 +5871,7 @@ bool input_remapping_load_file(void *data, const char *path)
stk_remap = RARCH_UNMAPPED;
configuration_set_uint(settings,
- settings->uints.input_remap_ids[i][j], stk_remap);
+ settings->uints.input_remap_ids[usernum][logical], stk_remap);
}
fill_pathname_join_delim(key_ident, s2,
@@ -5773,21 +5881,21 @@ bool input_remapping_load_file(void *data, const char *path)
key_remap = RETROK_UNKNOWN;
configuration_set_uint(settings,
- settings->uints.input_keymapper_ids[i][j], key_remap);
+ settings->uints.input_keymapper_ids[usernum][logical], key_remap);
}
}
_len = strlcpy(s1, prefix, sizeof(s1));
strlcpy(s1 + _len, "_analog_dpad_mode", sizeof(s1) - _len);
- CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], s1);
+ CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[usernum], s1);
_len = strlcpy(s1, "input_libretro_device_p", sizeof(s1));
strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len);
- CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], s1);
+ CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[usernum], s1);
_len = strlcpy(s1, "input_remap_port_p", sizeof(s1));
strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len);
- CONFIG_GET_INT_BASE(conf, settings, uints.input_remap_ports[i], s1);
+ CONFIG_GET_INT_BASE(conf, settings, uints.input_remap_ports[usernum], s1);
}
input_remapping_update_port_map();
@@ -5812,17 +5920,8 @@ bool input_remapping_save_file(const char *path)
{
size_t _len;
bool ret;
- unsigned i, j;
+ unsigned usernum, logical;
char remap_file_dir[PATH_MAX_LENGTH];
- char key_strings[RARCH_FIRST_CUSTOM_BIND + 8][8] =
- {
- "b", "y", "select", "start",
- "up", "down", "left", "right",
- "a", "x", "l", "r",
- "l2", "r2", "l3", "r3",
- "l_x+", "l_x-", "l_y+", "l_y-",
- "r_x+", "r_x-", "r_y+", "r_y-"
- };
config_file_t *conf = NULL;
runloop_state_t *runloop_st = runloop_state_get_ptr();
settings_t *settings = config_st;
@@ -5844,7 +5943,7 @@ bool input_remapping_save_file(const char *path)
if (!(conf = config_file_new_alloc()))
return false;
- for (i = 0; i < MAX_USERS; i++)
+ for (usernum = 0; usernum < MAX_USERS; usernum++)
{
size_t _len;
bool skip_port = true;
@@ -5858,15 +5957,15 @@ bool input_remapping_save_file(const char *path)
/* We must include all mapped ports + all those
* with an index less than max_users */
- if (i < max_users)
+ if (usernum < max_users)
skip_port = false;
else
{
/* Check whether current port is mapped
* to an input device */
- for (j = 0; j < max_users; j++)
+ for (logical = 0; logical < max_users; logical++)
{
- if (i == settings->uints.input_remap_ports[j])
+ if (usernum == settings->uints.input_remap_ports[logical])
{
skip_port = false;
break;
@@ -5877,7 +5976,7 @@ bool input_remapping_save_file(const char *path)
if (skip_port)
continue;
- snprintf(formatted_number, sizeof(formatted_number), "%u", i + 1);
+ snprintf(formatted_number, sizeof(formatted_number), "%u", usernum + 1);
_len = strlcpy(prefix, "input_player", sizeof(prefix));
strlcpy(prefix + _len, formatted_number, sizeof(prefix) - _len);
_len = strlcpy(s1, prefix, sizeof(s1));
@@ -5887,13 +5986,17 @@ bool input_remapping_save_file(const char *path)
_len = strlcpy(s3, prefix, sizeof(s3));
strlcpy(s3 + _len, "_stk", sizeof(s3) - _len);
- for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++)
+ for (logical = 0; logical < rarch_num_bind_game_controller(); logical++)
{
+ /* Ignore the analog/gun binds. */
+ if (!rarch_logical_bind_is_basic(logical))
+ continue;
+
char btn_ident[128];
char key_ident[128];
- const char *key_string = key_strings[j];
- unsigned remap_id = settings->uints.input_remap_ids[i][j];
- unsigned keymap_id = settings->uints.input_keymapper_ids[i][j];
+ const char *key_string = rarch_input_get_key_string(logical);
+ unsigned remap_id = settings->uints.input_remap_ids[usernum][logical];
+ unsigned keymap_id = settings->uints.input_keymapper_ids[usernum][logical];
fill_pathname_join_delim(btn_ident, s1,
key_string, '_', sizeof(btn_ident));
@@ -5901,7 +6004,7 @@ bool input_remapping_save_file(const char *path)
key_string, '_', sizeof(key_ident));
/* Only save modified button values */
- if (remap_id == j)
+ if (remap_id == logical)
config_unset(conf, btn_ident);
else
{
@@ -5909,7 +6012,7 @@ bool input_remapping_save_file(const char *path)
config_set_int(conf, btn_ident, -1);
else
config_set_int(conf, btn_ident,
- settings->uints.input_remap_ids[i][j]);
+ settings->uints.input_remap_ids[usernum][logical]);
}
/* Only save non-empty keymapper values */
@@ -5917,16 +6020,17 @@ bool input_remapping_save_file(const char *path)
config_unset(conf, key_ident);
else
config_set_int(conf, key_ident,
- settings->uints.input_keymapper_ids[i][j]);
+ settings->uints.input_keymapper_ids[usernum][logical]);
}
- for (j = RARCH_FIRST_CUSTOM_BIND; j < (RARCH_FIRST_CUSTOM_BIND + 8); j++)
+ /* This goes through axis and otherwise, so should keep the + 8 here. */
+ for (logical = RARCH_FIRST_CUSTOM_BIND; logical < (RARCH_FIRST_CUSTOM_BIND + 8); logical++)
{
char stk_ident[128];
char key_ident[128];
- const char *key_string = key_strings[j];
- unsigned remap_id = settings->uints.input_remap_ids[i][j];
- unsigned keymap_id = settings->uints.input_keymapper_ids[i][j];
+ const char *key_string = rarch_input_get_key_string(logical);
+ unsigned remap_id = settings->uints.input_remap_ids[usernum][logical];
+ unsigned keymap_id = settings->uints.input_keymapper_ids[usernum][logical];
fill_pathname_join_delim(stk_ident, s3,
key_string, '_', sizeof(stk_ident));
@@ -5934,7 +6038,7 @@ bool input_remapping_save_file(const char *path)
key_string, '_', sizeof(key_ident));
/* Only save modified button values */
- if (remap_id == j)
+ if (remap_id == logical)
config_unset(conf, stk_ident);
else
{
@@ -5942,7 +6046,7 @@ bool input_remapping_save_file(const char *path)
config_set_int(conf, stk_ident, -1);
else
config_set_int(conf, stk_ident,
- settings->uints.input_remap_ids[i][j]);
+ settings->uints.input_remap_ids[usernum][logical]);
}
/* Only save non-empty keymapper values */
@@ -5950,20 +6054,20 @@ bool input_remapping_save_file(const char *path)
config_unset(conf, key_ident);
else
config_set_int(conf, key_ident,
- settings->uints.input_keymapper_ids[i][j]);
+ settings->uints.input_keymapper_ids[usernum][logical]);
}
_len = strlcpy(s1, "input_libretro_device_p", sizeof(s1));
strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len);
- config_set_int(conf, s1, input_config_get_device(i));
+ config_set_int(conf, s1, input_config_get_device(usernum));
_len = strlcpy(s1, prefix, sizeof(s1));
strlcpy(s1 + _len, "_analog_dpad_mode", sizeof(s1) - _len);
- config_set_int(conf, s1, settings->uints.input_analog_dpad_mode[i]);
+ config_set_int(conf, s1, settings->uints.input_analog_dpad_mode[usernum]);
_len = strlcpy(s1, "input_remap_port_p", sizeof(s1));
strlcpy(s1 + _len, formatted_number, sizeof(s1) - _len);
- config_set_int(conf, s1, settings->uints.input_remap_ports[i]);
+ config_set_int(conf, s1, settings->uints.input_remap_ports[usernum]);
}
ret = config_file_write(conf, path, true);
diff --git a/configuration.h b/configuration.h
index 786f1f439c8..b51b8534ab8 100644
--- a/configuration.h
+++ b/configuration.h
@@ -150,8 +150,8 @@ typedef struct settings
unsigned input_analog_dpad_mode[MAX_USERS];
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_ids[MAX_USERS][rarch_num_bind_game_controller()];
+ unsigned input_keymapper_ids[MAX_USERS][rarch_num_bind_game_controller()];
unsigned input_remap_port_map[MAX_USERS][MAX_USERS + 1];
unsigned led_map[MAX_LEDS];
diff --git a/cores/libretro-net-retropad/net_retropad_core.c b/cores/libretro-net-retropad/net_retropad_core.c
index bedf072ad00..e69a264e704 100644
--- a/cores/libretro-net-retropad/net_retropad_core.c
+++ b/cores/libretro-net-retropad/net_retropad_core.c
@@ -92,7 +92,7 @@ static struct descriptor joypad = {
.index_min = 0,
.index_max = 0,
.id_min = RETRO_DEVICE_ID_JOYPAD_B,
- .id_max = RETRO_DEVICE_ID_JOYPAD_R3
+ .id_max = RETRO_DEVICE_ID_JOYPAD_MAX_BUTTONS
};
static struct descriptor analog = {
diff --git a/dynamic.h b/dynamic.h
index 79ed70ab16d..76ac7a534e7 100644
--- a/dynamic.h
+++ b/dynamic.h
@@ -33,7 +33,8 @@ enum retro_core_flags
RETRO_CORE_FLAG_GAME_LOADED = (1 << 2),
RETRO_CORE_FLAG_INPUT_POLLED = (1 << 3),
RETRO_CORE_FLAG_HAS_SET_SUBSYSTEMS = (1 << 4),
- RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS = (1 << 5)
+ RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS = (1 << 5),
+ RETRO_CORE_FLAG_HAS_SET_EXTENDED_INPUT = (1 << 6),
};
struct retro_core_t
diff --git a/input/input_defines.h b/input/input_defines.h
index bdd36fc37a1..2d343a7224f 100644
--- a/input/input_defines.h
+++ b/input/input_defines.h
@@ -21,6 +21,7 @@
#include
#include
+#include
#define MAX_USERS 16
@@ -28,7 +29,18 @@
#define RARCH_MAX_KEYS 137
+/**
+ * When using this to check if a bind is part of a game controller use
+ * instead @c rarch_bind_is_game_controller() .
+ *
+ * Instead of using @code RARCH_FIRST_CUSTOM_BIND + 8 @endcode use
+ * instead @c rarch_num_bind_game_controller() .
+ *
+ * Instead of using this to check if a bind is just a plain button
+ * with no axis, instead use @c rarch_logical_bind_is_basic() .
+ */
#define RARCH_FIRST_CUSTOM_BIND 16
+
#define RARCH_FIRST_LIGHTGUN_BIND RARCH_ANALOG_BIND_LIST_END
#define RARCH_FIRST_MISC_CUSTOM_BIND RARCH_LIGHTGUN_BIND_LIST_END
#define RARCH_FIRST_META_KEY RARCH_CUSTOM_BIND_LIST_END
@@ -83,6 +95,9 @@
#endif
+/** The number of extra core commands available, used with @c RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD . */
+#define RARCH_EXTRA_CORE_COMMAND_COUNT 128
+
RETRO_BEGIN_DECLS
/* RetroArch specific bind IDs. */
@@ -118,6 +133,16 @@ enum
/* Turbo */
RARCH_TURBO_ENABLE = RARCH_FIRST_MISC_CUSTOM_BIND,
+ /**
+ * End of the custom bind list.
+ *
+ * Instead of using this to check whether a button is part of
+ * a game controller, use @c rarch_bind_is_game_controller() or
+ * instead @c rarch_num_bind_game_controller() .
+ *
+ * To get the starting ID for logical buttons use
+ * instead @c rarch_first_logical_bind_game_controller() .
+ */
RARCH_CUSTOM_BIND_LIST_END,
/* Command binds. Not related to game input,
@@ -187,6 +212,12 @@ enum
RARCH_OVERLAY_NEXT,
RARCH_OSK,
+ /** Custom core command start, used with @c RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD. */
+ RARCH_EXTRA_CORE_COMMAND_START,
+
+ /** Custom core command end, used with @c RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD. */
+ RARCH_EXTRA_CORE_COMMAND_END = RARCH_EXTRA_CORE_COMMAND_START + RARCH_EXTRA_CORE_COMMAND_COUNT,
+
RARCH_BIND_LIST_END,
/* Deprecated */
@@ -246,4 +277,132 @@ enum input_turbo_default_button
RETRO_END_DECLS
+/**
+ * Represents an actual bind id.
+ *
+ * @since 2023/12/24
+ */
+typedef unsigned rarch_bind_id;
+
+/**
+ * Represents a logical bind id.
+ *
+ * @since 2023/12/24
+ */
+typedef unsigned rarch_logical_bind_id;
+
+/**
+ * The first logical bind index.
+ *
+ * @since 2023/12/24
+ */
+#define rarch_first_logical_bind_game_controller() RARCH_CUSTOM_BIND_LIST_END
+
+/**
+ * Is the given logical bind a basic button, one with no axis or otherwise?
+ *
+ * @param bind The logical bind to check.
+ * @return If the bind is simple.
+ * @since 2023/12/24
+ */
+static INLINE bool rarch_logical_bind_is_basic(rarch_logical_bind_id bind)
+{
+ return (bind < RARCH_FIRST_CUSTOM_BIND) || (bind >= RARCH_CUSTOM_BIND_LIST_END);
+}
+
+/**
+ * Is the given logical bind an extended basic button, one with no axis or otherwise?
+ *
+ * @param bind The logical bind to check.
+ * @return If the bind is simple and an extended button.
+ * @since 2023/12/24
+ */
+static INLINE bool rarch_logical_bind_is_extended_basic(rarch_logical_bind_id bind)
+{
+ return (bind >= RARCH_CUSTOM_BIND_LIST_END);
+}
+
+/**
+ * Returns the extended index of a given key.
+ *
+ * @param bind The bind to get the extended index of.
+ * @return The index of then given key or @c -1 if not valid.
+ * @since 2023/12/24
+ */
+static INLINE int rarch_logical_bind_get_extended_index(rarch_logical_bind_id bind)
+{
+ if (bind < RARCH_CUSTOM_BIND_LIST_END)
+ return -1;
+ return bind - RARCH_CUSTOM_BIND_LIST_END;
+}
+
+/**
+ * Translates a real bind id to a logical bind id.
+ *
+ * @param bind The input bind.
+ * @return The resultant logical index.
+ * @since 2023/12/24
+ */
+static INLINE rarch_logical_bind_id rarch_bind_to_logical_game_controller(rarch_bind_id bind)
+{
+ if (bind < RARCH_CUSTOM_BIND_LIST_END)
+ return bind;
+
+ if (bind >= RARCH_EXTRA_CORE_COMMAND_START && bind < RARCH_EXTRA_CORE_COMMAND_END)
+ return RARCH_CUSTOM_BIND_LIST_END + (bind - RARCH_EXTRA_CORE_COMMAND_START);
+
+ return RARCH_BIND_LIST_END_NULL;
+}
+
+/**
+ * Translates a logical bind id to an actual one.
+ *
+ * @param bind The logical game controller bind.
+ * @return The resultant bind id.
+ * @since 2023/12/24
+ */
+static INLINE rarch_bind_id rarch_logical_to_bind_game_controller(rarch_logical_bind_id bind)
+{
+ if (bind >= RARCH_CUSTOM_BIND_LIST_END)
+ return (RARCH_EXTRA_CORE_COMMAND_START + bind);
+
+ return bind;
+}
+
+/**
+ * Returns the number of binds that are part of game controllers.
+ *
+ * Use this instead of @c RARCH_FIRST_CUSTOM_BIND;
+ * Use this instead of @code RARCH_FIRST_CUSTOM_BIND + 8 @endcode.
+ *
+ * @return The number of binds that are part of game controllers.
+ * @since 2023/12/24
+ */
+#define rarch_num_bind_game_controller() (RARCH_CUSTOM_BIND_LIST_END + RARCH_EXTRA_CORE_COMMAND_COUNT)
+
+/**
+ * Checks whether the given bind is considered to be part of a controller.
+ *
+ * @param bind The bind id to check.
+ * @return If it is a game controller bind.
+ * @since 2023/12/24
+ */
+static INLINE bool rarch_bind_is_game_controller(rarch_bind_id bind)
+{
+ return (bind < RARCH_CUSTOM_BIND_LIST_END) ||
+ (bind >= RARCH_EXTRA_CORE_COMMAND_START && bind < RARCH_EXTRA_CORE_COMMAND_END);
+}
+
+/**
+ * Checks whether the given bind is valid for a logical bind.
+ *
+ * @param bind The logical bind to check.
+ * @return If it is a valid logical bind.
+ * @since 2023/12/24
+ */
+static INLINE bool rarch_logical_bind_is_game_controller(rarch_logical_bind_id bind)
+{
+ return bind < rarch_num_bind_game_controller();
+}
+
#endif
diff --git a/input/input_driver.c b/input/input_driver.c
index 177d5df2b86..baa3a92fe29 100644
--- a/input/input_driver.c
+++ b/input/input_driver.c
@@ -91,8 +91,32 @@
|| ((autoconf_bind)->joyaxis != AXIS_NONE)) \
)
+#define INPUT_CONFIG_MASS_BIND_ORDER(x) (36 + x)
+#define INPUT_CONFIG_MASS_BIND_ORDER_TEN(base) \
+ INPUT_CONFIG_MASS_BIND_ORDER(base), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 1), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 2), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 3), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 4), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 5), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 6), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 7), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 8), \
+ INPUT_CONFIG_MASS_BIND_ORDER(base + 9)
+#define INPUT_CONFIG_MASS_BIND_ORDER_HUNDRED(base) \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 1), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 2), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 3), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 4), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 5), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 6), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 7), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 8), \
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(base + 9)
+
/* Human readable order of input binds */
-const unsigned input_config_bind_order[24] = {
+const unsigned input_config_bind_order[rarch_num_bind_game_controller()] = {
RETRO_DEVICE_ID_JOYPAD_UP,
RETRO_DEVICE_ID_JOYPAD_DOWN,
RETRO_DEVICE_ID_JOYPAD_LEFT,
@@ -109,16 +133,49 @@ const unsigned input_config_bind_order[24] = {
RETRO_DEVICE_ID_JOYPAD_R2,
RETRO_DEVICE_ID_JOYPAD_L3,
RETRO_DEVICE_ID_JOYPAD_R3,
- 19, /* Left Analog Up */
- 18, /* Left Analog Down */
- 17, /* Left Analog Left */
- 16, /* Left Analog Right */
- 23, /* Right Analog Up */
- 22, /* Right Analog Down */
- 21, /* Right Analog Left */
- 20, /* Right Analog Right */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_L_UP, /* Left Analog Up */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_L_DOWN, /* Left Analog Down */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_L_LEFT, /* Left Analog Left */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_L_RIGHT, /* Left Analog Right */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_R_UP, /* Right Analog Up */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_R_DOWN, /* Right Analog Down */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_R_LEFT, /* Right Analog Left */
+ RETRO_DEVICE_ID_JOYPAD_ANALOG_R_RIGHT, /* Right Analog Right */
+
+ /* The remaining 36 + 128 = 164 entries, just 1:1 mapped... starts at 36. */
+ INPUT_CONFIG_MASS_BIND_ORDER_HUNDRED(0),
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(100),
+ INPUT_CONFIG_MASS_BIND_ORDER_TEN(110),
+ INPUT_CONFIG_MASS_BIND_ORDER(120),
+ INPUT_CONFIG_MASS_BIND_ORDER(121),
+ INPUT_CONFIG_MASS_BIND_ORDER(122),
+ INPUT_CONFIG_MASS_BIND_ORDER(123),
+ INPUT_CONFIG_MASS_BIND_ORDER(124),
+ INPUT_CONFIG_MASS_BIND_ORDER(125),
+ INPUT_CONFIG_MASS_BIND_ORDER(126),
+ INPUT_CONFIG_MASS_BIND_ORDER(127),
+
+ /* Light gun order, this is here because there has been mix and match
+ * between buttons, analogs, etc. */
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+ RARCH_UNMAPPED,
+
+ /* Same goes for turbo. */
+ RARCH_UNMAPPED,
};
+#undef INPUT_CONFIG_MASS_BIND_ORDER
+#undef INPUT_CONFIG_MASS_BIND_ORDER_TEN
+
/**************************************/
/* TODO/FIXME - turn these into static global variable */
retro_keybind_set input_config_binds[MAX_USERS];
@@ -6116,32 +6173,46 @@ void input_remapping_deinit(bool save_remap)
void input_remapping_set_defaults(bool clear_cache)
{
- unsigned i, j;
+ unsigned usernum, logical;
settings_t *settings = config_get_ptr();
+ const struct retro_keybind *keybind;
+ bool is_ext;
- for (i = 0; i < MAX_USERS; i++)
+ for (usernum = 0; usernum < MAX_USERS; usernum++)
{
/* Button/keyboard remaps */
- for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++)
+ for (logical = 0; logical < rarch_num_bind_game_controller(); logical++)
{
- const struct retro_keybind *keybind = &input_config_binds[i][j];
+ /* Ignore the analog/gun binds. */
+ if (!rarch_logical_bind_is_basic(logical))
+ continue;
+
+ is_ext = rarch_logical_bind_is_extended_basic(logical);
+
+ keybind = &input_config_binds[usernum][logical];
+
+ /* Debug. */
+ RARCH_LOG("Keybind user %d log %d -> %p %d\n",
+ usernum, logical, keybind, (keybind != NULL ? keybind->id : -1));
+ /* Force defaults for extended keys to be unmapped by default. */
configuration_set_uint(settings,
- settings->uints.input_remap_ids[i][j],
- keybind ? keybind->id : RARCH_UNMAPPED);
+ settings->uints.input_remap_ids[usernum][logical],
+ (/*!rarch_logical_bind_is_extended_basic(logical) &&*/ keybind) ?
+ keybind->id : RARCH_UNMAPPED);
configuration_set_uint(settings,
- settings->uints.input_keymapper_ids[i][j], RETROK_UNKNOWN);
+ settings->uints.input_keymapper_ids[usernum][logical], RETROK_UNKNOWN);
}
- /* Analog stick remaps */
- for (j = RARCH_FIRST_CUSTOM_BIND; j < (RARCH_FIRST_CUSTOM_BIND + 8); j++)
+ /* Analog stick remaps, use +8 still here for compatibility purposes. */
+ for (logical = RARCH_FIRST_CUSTOM_BIND; logical < (RARCH_FIRST_CUSTOM_BIND + 8); logical++)
configuration_set_uint(settings,
- settings->uints.input_remap_ids[i][j], j);
+ settings->uints.input_remap_ids[usernum][logical], logical);
/* Controller port remaps */
configuration_set_uint(settings,
- settings->uints.input_remap_ports[i], i);
+ settings->uints.input_remap_ports[usernum], usernum);
}
/* Need to call 'input_remapping_update_port_map()'
diff --git a/input/input_driver.h b/input/input_driver.h
index 6fa75a3b353..7a39b985228 100644
--- a/input/input_driver.h
+++ b/input/input_driver.h
@@ -1058,7 +1058,7 @@ void input_driver_collect_system_input(input_driver_state_t *input_st,
void input_keyboard_event(bool down, unsigned code,
uint32_t character, uint16_t mod, unsigned device);
-extern const unsigned input_config_bind_order[24];
+extern const unsigned input_config_bind_order[rarch_num_bind_game_controller()];
extern input_device_driver_t *joypad_drivers[];
extern input_driver_t *input_drivers[];
diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h
index 999390dab45..9c0360414f8 100644
--- a/intl/msg_hash_us.h
+++ b/intl/msg_hash_us.h
@@ -15970,3 +15970,9 @@ MSG_HASH(
MSG_IOS_TOUCH_MOUSE_DISABLED,
"Touch mouse is disabled"
)
+
+/* Extra logical buttons. */
+MSG_HASH(
+ MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LOGICAL,
+ "Logical Button %d"
+ )
\ No newline at end of file
diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h
index b16228b272d..72ecf9b6177 100644
--- a/libretro-common/include/libretro.h
+++ b/libretro-common/include/libretro.h
@@ -202,6 +202,18 @@ extern "C" {
#define RETRO_DEVICE_ID_JOYPAD_L3 14
#define RETRO_DEVICE_ID_JOYPAD_R3 15
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_L_RIGHT 16
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_L_LEFT 17
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_L_DOWN 18
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_L_UP 19
+
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_R_RIGHT 20
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_R_LEFT 21
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_R_DOWN 22
+#define RETRO_DEVICE_ID_JOYPAD_ANALOG_R_UP 23
+
+#define RETRO_DEVICE_ID_JOYPAD_MAX_BUTTONS 24
+
#define RETRO_DEVICE_ID_JOYPAD_MASK 256
/* Index / Id values for ANALOG device. */
@@ -1852,6 +1864,12 @@ enum retro_mod
* multiplayer, where a deterministic core supporting multiple
* input devices does not need to take any action on its own.
*/
+#define RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD (79 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+ /* const struct retro_core_extended_retropad* --
+ * Similar to the setting of controls, this allows for
+ * the addition of additional button inputs which are not
+ * bound to anything.
+ */
/* VFS functionality */
@@ -3360,6 +3378,50 @@ struct retro_input_descriptor
const char *description;
};
+/** Used with @c retro_core_extended_retropad , similar to @c retro_input_descriptor. */
+struct retro_core_extended_retropad_button
+{
+ /** The controller port or player this is attached to. */
+ unsigned port;
+
+ /** The device that this is associated with, either @c RETRO_DEVICE_JOYPAD or @c RETRO_DEVICE_ANALOG. */
+ unsigned device;
+
+ /** The index of the device. */
+ unsigned index;
+
+ /**
+ * The logical bind ID number of the specific command.
+ * The value will be between @c 0 and @c out_num_extra .
+ */
+ unsigned logical_id;
+
+ /** The description of the command, @c NULL terminates the list.
+ * Must remain allocated until retro_unload_game() is called. */
+ const char* description;
+
+ /** The glyph to use for this command, it is up to the front end to provide a picture.
+ * Must remain allocated until retro_unload_game() is called.*/
+ const char* glyph;
+};
+
+/** Used with @c RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD to set extra core buttons. */
+struct retro_core_extended_retropad_info
+{
+ /** Output: The number of extra buttons which are available. */
+ unsigned out_num_extra;
+};
+
+/** Used with @c RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD to set extra core buttons. */
+struct retro_core_extended_retropad
+{
+ /** The core commands that exist, NULL description ends. */
+ const struct retro_core_extended_retropad_button* actions;
+
+ /** Extended RetroPad information output. */
+ struct retro_core_extended_retropad_info* out_info;
+};
+
struct retro_system_info
{
/* All pointers are owned by libretro implementation, and pointers must
diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c
index 1fa79fdf566..9e0eb0f9f5b 100644
--- a/menu/cbs/menu_cbs_get_value.c
+++ b/menu/cbs/menu_cbs_get_value.c
@@ -828,8 +828,8 @@ static void menu_action_setting_disp_set_label_input_desc(
{
unsigned remap_idx;
settings_t *settings = config_get_ptr();
- unsigned user_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (RARCH_FIRST_CUSTOM_BIND + 8);
- unsigned btn_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (RARCH_FIRST_CUSTOM_BIND + 8) * user_idx;
+ unsigned user_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (rarch_num_bind_game_controller());
+ unsigned btn_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (rarch_num_bind_game_controller()) * user_idx;
if (!settings)
return;
@@ -845,7 +845,7 @@ static void menu_action_setting_disp_set_label_input_desc(
if (!string_is_empty(descriptor))
{
size_t _len = strlcpy(s, descriptor, len);
- if (remap_idx < RARCH_FIRST_CUSTOM_BIND) { }
+ if (rarch_logical_bind_is_basic(remap_idx)) { }
else if (remap_idx % 2 == 0)
{
s[ _len] = ' ';
diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c
index d5858a3c816..c0e8b51e1c5 100644
--- a/menu/cbs/menu_cbs_ok.c
+++ b/menu/cbs/menu_cbs_ok.c
@@ -7137,17 +7137,17 @@ static int action_ok_push_dropdown_item_input_description(const char *path,
if ( !settings
|| (entry_type < MENU_SETTINGS_INPUT_DESC_BEGIN)
- || ((remap_idx >= RARCH_CUSTOM_BIND_LIST_END)
+ || ((remap_idx >= rarch_num_bind_game_controller())
&& (remap_idx != RARCH_UNMAPPED)))
return -1;
/* Determine user/button indices */
user_idx = (entry_type - MENU_SETTINGS_INPUT_DESC_BEGIN)
- / (RARCH_FIRST_CUSTOM_BIND + 8);
+ / (rarch_num_bind_game_controller());
btn_idx = (entry_type - MENU_SETTINGS_INPUT_DESC_BEGIN)
- - (RARCH_FIRST_CUSTOM_BIND + 8) * user_idx;
+ - (rarch_num_bind_game_controller()) * user_idx;
- if ((user_idx >= MAX_USERS) || (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
+ if ((user_idx >= MAX_USERS) || (btn_idx >= rarch_num_bind_game_controller()))
return -1;
/* Assign new mapping */
diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c
index 828ea697d0e..d2a67b8721b 100644
--- a/menu/cbs/menu_cbs_start.c
+++ b/menu/cbs/menu_cbs_start.c
@@ -245,13 +245,13 @@ static int action_start_input_desc(
if (settings && sys_info)
{
- unsigned user_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (RARCH_FIRST_CUSTOM_BIND + 8);
- unsigned btn_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (RARCH_FIRST_CUSTOM_BIND + 8) * user_idx;
+ unsigned user_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (rarch_num_bind_game_controller());
+ unsigned btn_idx = (type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (rarch_num_bind_game_controller()) * user_idx;
unsigned mapped_port = settings->uints.input_remap_ports[user_idx];
if ( (user_idx >= MAX_USERS)
|| (mapped_port >= MAX_USERS)
- || (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
+ || !rarch_logical_bind_is_game_controller(btn_idx))
return 0;
/* Check whether core has defined this input */
diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c
index 530d73d95ca..e56cd4780dc 100644
--- a/menu/cbs/menu_cbs_sublabel.c
+++ b/menu/cbs/menu_cbs_sublabel.c
@@ -1579,7 +1579,7 @@ static int action_bind_sublabel_remap_sublabel(
{
settings_t *settings = config_get_ptr();
unsigned port = (type - MENU_SETTINGS_INPUT_DESC_BEGIN)
- / (RARCH_FIRST_CUSTOM_BIND + 8);
+ / (rarch_num_bind_game_controller());
if (settings && (port < MAX_USERS))
{
diff --git a/menu/cbs/menu_cbs_title.c b/menu/cbs/menu_cbs_title.c
index ac4d526cdb6..d3d13c4c65f 100644
--- a/menu/cbs/menu_cbs_title.c
+++ b/menu/cbs/menu_cbs_title.c
@@ -549,7 +549,7 @@ 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);
+ (rarch_num_bind_game_controller());
return action_get_title_dropdown_input_description_common(
path, port, s, len);
diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c
index ee71e2dc8e1..0536532a9cd 100644
--- a/menu/menu_displaylist.c
+++ b/menu/menu_displaylist.c
@@ -5466,11 +5466,11 @@ static int menu_displaylist_parse_input_description_list(
return 0;
/* Determine user/button indices */
- user_idx = (info->type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (RARCH_FIRST_CUSTOM_BIND + 8);
- btn_idx = (info->type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (RARCH_FIRST_CUSTOM_BIND + 8) * user_idx;
+ user_idx = (info->type - MENU_SETTINGS_INPUT_DESC_BEGIN) / (rarch_num_bind_game_controller());
+ btn_idx = (info->type - MENU_SETTINGS_INPUT_DESC_BEGIN) - (rarch_num_bind_game_controller()) * user_idx;
if ( (user_idx >= MAX_USERS)
- || (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
+ || (btn_idx >= rarch_num_bind_game_controller()))
return 0;
mapped_port = settings->uints.input_remap_ports[user_idx];
@@ -5481,7 +5481,7 @@ static int menu_displaylist_parse_input_description_list(
/* Get current mapping for selected button */
current_remap_idx = settings->uints.input_remap_ids[user_idx][btn_idx];
- if (current_remap_idx >= RARCH_CUSTOM_BIND_LIST_END)
+ if (current_remap_idx < 0 || current_remap_idx >= rarch_num_bind_game_controller())
current_remap_idx = RARCH_UNMAPPED;
/* An annoyance: Menu entries do not have
@@ -5494,11 +5494,11 @@ static int menu_displaylist_parse_input_description_list(
snprintf(entry_label, sizeof(entry_label), "%u", info->type);
/* Loop over core input definitions */
- for (j = 0; j < RARCH_CUSTOM_BIND_LIST_END; j++)
+ for (j = 0; j < rarch_num_bind_game_controller(); j++)
{
const char *input_desc_btn;
- i = (j < RARCH_ANALOG_BIND_LIST_END) ? input_config_bind_order[j] : j;
+ i = (rarch_logical_bind_is_basic(j) ? input_config_bind_order[j] : j);
input_desc_btn = sys_info->input_desc_btn[mapped_port][i];
/* Check whether an input is defined for
@@ -5514,7 +5514,7 @@ static int menu_displaylist_parse_input_description_list(
* indicators */
size_t _len = strlcpy(input_description, input_desc_btn,
sizeof(input_description));
- if (i >= RARCH_FIRST_CUSTOM_BIND)
+ if (!rarch_logical_bind_is_basic(i))
{
input_description [ _len] = ' ';
if ((i % 2) == 0)
@@ -11687,7 +11687,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
if (menu_entries_append(list, descriptor, info->path,
MSG_UNKNOWN,
MENU_SETTINGS_INPUT_DESC_BEGIN +
- (port * (RARCH_FIRST_CUSTOM_BIND + 8)) + retro_id, 0, 0, NULL))
+ (port * rarch_num_bind_game_controller()) + retro_id, 0, 0, NULL))
count++;
}
}
diff --git a/menu/menu_driver.h b/menu/menu_driver.h
index e56be9fdd75..69622ad8708 100644
--- a/menu/menu_driver.h
+++ b/menu/menu_driver.h
@@ -217,9 +217,11 @@ enum menu_settings_type
MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_END = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN + MENU_SETTINGS_AUDIO_MIXER_MAX_STREAMS,
MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN,
MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_END = MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN + MENU_SETTINGS_AUDIO_MIXER_MAX_STREAMS,
+
+ /* Binds in the menu, note that every single bind needs to fit! */
MENU_SETTINGS_BIND_BEGIN,
- MENU_SETTINGS_BIND_LAST = MENU_SETTINGS_BIND_BEGIN + RARCH_ANALOG_RIGHT_Y_MINUS,
- MENU_SETTINGS_BIND_ALL_LAST = MENU_SETTINGS_BIND_BEGIN + RARCH_MENU_TOGGLE,
+ MENU_SETTINGS_BIND_LAST = MENU_SETTINGS_BIND_BEGIN + rarch_num_bind_game_controller(),
+ MENU_SETTINGS_BIND_ALL_LAST = MENU_SETTINGS_BIND_BEGIN + RARCH_EXTRA_CORE_COMMAND_COUNT + RARCH_MENU_TOGGLE,
MENU_SETTINGS_CUSTOM_BIND,
MENU_SETTINGS_CUSTOM_BIND_KEYBOARD,
@@ -232,13 +234,14 @@ enum menu_settings_type
MENU_SETTINGS_CHEAT_BEGIN,
MENU_SETTINGS_CHEAT_END = MENU_SETTINGS_CHEAT_BEGIN + (MAX_CHEAT_COUNTERS - 1),
+ /* Within @c MENU_SETTINGS_INPUT_END , the + 6 are these following keys. */
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_END = MENU_SETTINGS_INPUT_BEGIN + rarch_num_bind_game_controller() + 6,
MENU_SETTINGS_INPUT_DESC_BEGIN,
- MENU_SETTINGS_INPUT_DESC_END = MENU_SETTINGS_INPUT_DESC_BEGIN + ((RARCH_FIRST_CUSTOM_BIND + 8) * MAX_USERS),
+ MENU_SETTINGS_INPUT_DESC_END = MENU_SETTINGS_INPUT_DESC_BEGIN + (rarch_num_bind_game_controller() * MAX_USERS),
MENU_SETTINGS_INPUT_DESC_KBD_BEGIN,
MENU_SETTINGS_INPUT_DESC_KBD_END = MENU_SETTINGS_INPUT_DESC_KBD_BEGIN + (RARCH_MAX_KEYS * MAX_USERS),
MENU_SETTINGS_REMAPPING_PORT_BEGIN,
diff --git a/menu/menu_setting.c b/menu/menu_setting.c
index 80a43f75c76..5ec3c643e5b 100644
--- a/menu/menu_setting.c
+++ b/menu/menu_setting.c
@@ -224,9 +224,9 @@
if (SETTINGS_LIST_APPEND(a, b)) \
config_hex(a, b, c, d, e, f, g, h, i, j, k, l)
-#define CONFIG_BIND_ALT(a, b, c, d, e, f, g, h, i, j, k) \
- if (SETTINGS_LIST_APPEND(a, b)) \
- config_bind_alt(a, b, c, d, e, f, g, h, i, j, k)
+#define CONFIG_BIND_ALT(list, list_info, target, player, player_offset, name, SHORT, default_value, group_info, subgroup_info, parent_group) \
+ if (SETTINGS_LIST_APPEND(list, list_info)) \
+ config_bind_alt(list, list_info, target, player, player_offset, name, SHORT, default_value, group_info, subgroup_info, parent_group)
#define CONFIG_BIND(a, b, c, d, e, f, g, h, i, j, k, l) \
if (SETTINGS_LIST_APPEND(a, b)) \
@@ -9021,7 +9021,7 @@ static bool setting_append_list_input_player_options(
*/
static char buffer[MAX_USERS][13+2+1];
static char group_label[MAX_USERS][255];
- unsigned i, j;
+ unsigned bindish, bindid;
rarch_setting_group_info_t group_info;
rarch_setting_group_info_t subgroup_info;
settings_t *settings = config_get_ptr();
@@ -9254,16 +9254,41 @@ static bool setting_append_list_input_player_options(
{
const char *value_na =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE);
- for (j = 0; j < RARCH_BIND_LIST_END; j++)
+
+ RARCH_LOG("Filling in bind menu for user %d.\n", user);
+
+ for (bindid = 0; bindid < RARCH_BIND_LIST_END; bindid++)
{
char label[NAME_MAX_LENGTH];
char name[NAME_MAX_LENGTH];
+ bool is_game;
+ rarch_logical_bind_id logical_bind;
size_t _len = 0;
- i = (j < RARCH_ANALOG_BIND_LIST_END)
- ? input_config_bind_order[j]
- : j;
- if (input_config_bind_map_get_meta(i))
+ /* Is this a game button or similar? */
+ is_game = rarch_bind_is_game_controller(bindid);
+
+ /* Which button does this belong to? */
+ if (is_game)
+ {
+ logical_bind = rarch_bind_to_logical_game_controller(bindid);
+
+ /* For extended basic buttons we go really deep into the actual bind
+ * map as it is not at the start which @c input_config_bind_order
+ * assumes, so effectively use the real bind id for its position. */
+ if (rarch_logical_bind_is_extended_basic(logical_bind))
+ bindish = bindid;
+ else
+ bindish = input_config_bind_order[logical_bind];
+ }
+ else
+ {
+ logical_bind = (rarch_logical_bind_id)-1;
+ bindish = bindid;
+ }
+
+ /* Checks keybind->meta, where 0 is for game controllers. */
+ if (0 != input_config_bind_map_get_meta(bindish))
continue;
name[0] = '\0';
@@ -9279,20 +9304,35 @@ static bool setting_append_list_input_player_options(
if (
settings->bools.input_descriptor_label_show
- && (i < RARCH_FIRST_META_KEY)
- && core_has_set_input_descriptor()
- && (i != RARCH_TURBO_ENABLE)
+ && is_game
+ && (core_has_set_input_descriptor())
+ && (bindish != RARCH_TURBO_ENABLE)
)
{
- if (sys_info->input_desc_btn[user][i])
+ /* For core defined keys, we use the label provided by the core... if any. */
+ if (sys_info->input_desc_btn[user][logical_bind])
+ {
strlcpy(label + _len,
- sys_info->input_desc_btn[user][i],
+ sys_info->input_desc_btn[user][logical_bind],
sizeof(label) - _len);
+ }
+
+ /* Otherwise we just label it with the description of the key. */
else
{
- snprintf(label, sizeof(label), "%s (%s)",
- input_config_bind_map_get_desc(i),
- value_na);
+ /* For logical keys they have no true label, so use a generic name for them. */
+ if (rarch_logical_bind_is_extended_basic(logical_bind))
+ {
+ snprintf(label, sizeof(label), "Logical %d (%s)",
+ rarch_logical_bind_get_extended_index(logical_bind),
+ value_na);
+ }
+ else
+ {
+ snprintf(label, sizeof(label), "%s (%s)",
+ input_config_bind_map_get_desc(bindish),
+ value_na);
+ }
if (settings->bools.input_descriptor_hide_unbound)
continue;
@@ -9300,23 +9340,25 @@ static bool setting_append_list_input_player_options(
}
else
strlcpy(label + _len,
- input_config_bind_map_get_desc(i),
+ input_config_bind_map_get_desc(bindish),
sizeof(label) - _len);
- snprintf(name, sizeof(name), "p%u_%s", user + 1, input_config_bind_map_get_base(i));
+ /* Essentially p1_y. */
+ snprintf(name, sizeof(name), "p%u_%s",
+ user + 1, input_config_bind_map_get_base(bindish));
CONFIG_BIND_ALT(
list, list_info,
- &input_config_binds[user][i],
+ &input_config_binds[user][bindish],
user + 1,
user,
strdup(name),
strdup(label),
- &defaults[i],
+ &defaults[bindish],
&group_info,
&subgroup_info,
parent_group);
- (*list)[list_info->index - 1].bind_type = i + MENU_SETTINGS_BIND_BEGIN;
+ (*list)[list_info->index - 1].bind_type = bindish + MENU_SETTINGS_BIND_BEGIN;
}
}
diff --git a/msg_hash.h b/msg_hash.h
index c3ccb278372..eb1e5cc9aa9 100644
--- a/msg_hash.h
+++ b/msg_hash.h
@@ -4121,6 +4121,9 @@ enum msg_hash_enums
MSG_3DS_BOTTOM_MENU_SAVE_STATE,
MSG_3DS_BOTTOM_MENU_LOAD_STATE,
+ /* Logical menu input. */
+ MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LOGICAL,
+
MSG_LAST,
/* Ensure sizeof(enum) == sizeof(int) */
diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c
index c53b81f4e7e..f8f30caed8c 100644
--- a/network/netplay/netplay_frontend.c
+++ b/network/netplay/netplay_frontend.c
@@ -7744,7 +7744,7 @@ static bool get_self_input_state(
/* no break */
case RETRO_DEVICE_JOYPAD:
- for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_R3; i++)
+ for (i = 0; i <= RETRO_DEVICE_ID_JOYPAD_MAX_BUTTONS; i++)
{
int16_t tmp = cb(local_device,
RETRO_DEVICE_JOYPAD, 0, (unsigned)i);
diff --git a/network/netplay/netplay_protocol.h b/network/netplay/netplay_protocol.h
index 7583a2e2561..608fca18b77 100644
--- a/network/netplay/netplay_protocol.h
+++ b/network/netplay/netplay_protocol.h
@@ -19,7 +19,7 @@
#define __RARCH_NETPLAY_PROTOCOL_H
#define LOW_NETPLAY_PROTOCOL_VERSION 5
-#define HIGH_NETPLAY_PROTOCOL_VERSION 6
+#define HIGH_NETPLAY_PROTOCOL_VERSION 7
#define NETPLAY_PROTOCOL_VERSION HIGH_NETPLAY_PROTOCOL_VERSION
diff --git a/retroarch.c b/retroarch.c
index 896598c9902..99c0e163709 100644
--- a/retroarch.c
+++ b/retroarch.c
@@ -5535,6 +5535,7 @@ static void global_free(struct rarch_state *p_rarch)
#endif
runloop_st->current_core.flags &= ~(RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS
+ | RETRO_CORE_FLAG_HAS_SET_EXTENDED_INPUT
| RETRO_CORE_FLAG_HAS_SET_SUBSYSTEMS);
global = global_get_ptr();
@@ -6734,6 +6735,7 @@ static bool retroarch_parse_input_and_config(
/* Flush out some states that could have been set
* by core environment variables. */
runloop_st->current_core.flags &= ~(RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS
+ | RETRO_CORE_FLAG_HAS_SET_EXTENDED_INPUT
| RETRO_CORE_FLAG_HAS_SET_SUBSYSTEMS);
/* Load the config file now that we know what it is */
diff --git a/retroarch_types.h b/retroarch_types.h
index 37e6492d150..e6d068bc985 100644
--- a/retroarch_types.h
+++ b/retroarch_types.h
@@ -169,7 +169,7 @@ typedef struct rarch_system_info
disk_control_interface_t disk_control; /* ptr alignment */
struct retro_system_info info; /* ptr alignment */
rarch_memory_map_t mmaps; /* ptr alignment */
- const char *input_desc_btn[MAX_USERS][RARCH_FIRST_META_KEY];
+ const char *input_desc_btn[MAX_USERS][rarch_num_bind_game_controller()];
struct
{
struct retro_subsystem_info *data;
diff --git a/runloop.c b/runloop.c
index 43bed44704c..b785bdeafea 100644
--- a/runloop.c
+++ b/runloop.c
@@ -1401,6 +1401,253 @@ static void core_performance_counter_stop(struct retro_perf_counter *perf)
perf->total += cpu_features_get_perf_counter() - perf->start;
}
+/**
+ * Erases input descriptor buttons.
+ *
+ * @param sys_info The current state of the front end.
+ * @param from The starting index, inclusive.
+ * @param to The ending index, exclusive.
+ */
+static void rarch_erase_input_desc_btn(rarch_system_info_t *sys_info, unsigned from, unsigned to)
+{
+ unsigned usernum, at;
+ const char** user_inputs;
+
+ /* Erase all the previous extended binds for all users. */
+ for (usernum = 0; usernum < MAX_USERS; usernum++)
+ {
+ /* For simpler access. */
+ user_inputs = sys_info->input_desc_btn[usernum];
+
+ /* Invalidate all entries. */
+ for (at = rarch_first_logical_bind_game_controller();
+ at < rarch_num_bind_game_controller();
+ at++)
+ user_inputs[at] = NULL;
+ }
+}
+
+static void rarch_set_core_extended_retropad(rarch_system_info_t *sys_info,
+ runloop_state_t *runloop_st,
+ const struct retro_core_extended_retropad *input) {
+ const struct retro_core_extended_retropad_button* action;
+ unsigned at, bind, usernum;
+ const char** user_inputs;
+ bool did_standard;
+
+ /* Debug. */
+ RARCH_LOG("[Environ]: Setting extended retropad buttons.\n");
+
+ /* Check if standard inputs were set. */
+ did_standard = (runloop_st->current_core.flags & RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS) != 0;
+ if (!did_standard)
+ RARCH_LOG("[Environ]: Standard was not previously set.\n");
+
+ /* Erase all the previous extended binds for all users. */
+ if (did_standard)
+ rarch_erase_input_desc_btn(sys_info,
+ rarch_first_logical_bind_game_controller(),
+ rarch_num_bind_game_controller());
+
+ /* Otherwise erase everything as it has never been set before. */
+ else
+ rarch_erase_input_desc_btn(sys_info, 0, rarch_num_bind_game_controller());
+
+ /* Set output details, if requested. */
+ if (input->out_info != NULL) {
+ input->out_info->out_num_extra = RARCH_EXTRA_CORE_COMMAND_COUNT;
+ }
+
+ /* Go through the commands and process them. */
+ if (input->actions != NULL)
+ {
+ for (at = 0; input->actions[at].description != NULL; at++)
+ {
+ /* Get base action. */
+ action = &input->actions[at];
+
+ /* Debug. */
+ RARCH_LOG("[Environ]: Wanting extra button %d %d %d %d %d %s %s.\n",
+ at, action->port, action->device, action->port, action->logical_id,
+ action->description, action->glyph);
+
+ /* Map player. */
+ usernum = action->port;
+ if (usernum < 0 || usernum >= MAX_USERS)
+ continue;
+
+ /* We only care about gamepads and their analog equivalents. */
+ if (action->device != RETRO_DEVICE_JOYPAD &&
+ action->device != RETRO_DEVICE_ANALOG)
+ continue;
+
+ /* Ignore logical binds which are out of bounds. */
+ bind = action->logical_id;
+ if (bind < 0 || bind >= RARCH_EXTRA_CORE_COMMAND_COUNT)
+ continue;
+
+ /* Map to logical button internally. */
+ bind = rarch_first_logical_bind_game_controller() + bind;
+
+ /* Set description. */
+ sys_info->input_desc_btn[usernum][bind] = action->description;
+
+ /* Debug. */
+ RARCH_LOG("[Environ]: Bound %d to %s.\n",
+ bind, action->description);
+ }
+
+ /* Debug. */
+ RARCH_LOG("[Environ]: Set %d extended buttons.\n", at);
+ }
+
+ /* Indicate that the input descriptors changed. */
+ runloop_st->current_core.flags |=
+ RETRO_CORE_FLAG_HAS_SET_EXTENDED_INPUT;
+}
+
+static void rarch_set_input_descriptors(const void *data,
+ runloop_state_t *runloop_st, const settings_t *settings,
+ rarch_system_info_t *sys_info) {
+ unsigned retro_id;
+ const struct retro_input_descriptor *desc = NULL;
+ unsigned int p;
+ bool did_extra;
+
+ /* Check if extended inputs were set. */
+ did_extra = (runloop_st->current_core.flags & RETRO_CORE_FLAG_HAS_SET_EXTENDED_INPUT) != 0;
+ if (!did_extra)
+ RARCH_LOG("[Environ]: SET_INPUT_DESCRIPTORS: Extra was not previously set.\n");
+
+ /* If extended descriptors were set, only erase the standard ones. */
+ if (did_extra)
+ rarch_erase_input_desc_btn(sys_info, 0, rarch_first_logical_bind_game_controller());
+
+ /* Otherwise, erase everything to keep legacy behavior. */
+ else
+ rarch_erase_input_desc_btn(sys_info, 0, rarch_num_bind_game_controller());
+
+ desc = (const struct retro_input_descriptor*)data;
+
+ for (; desc->description; desc++)
+ {
+ unsigned retro_port = desc->port;
+
+ retro_id = desc->id;
+
+ if (desc->port >= MAX_USERS)
+ continue;
+
+ /* Ignore extended custom binds. */
+ if (desc->id >= RARCH_FIRST_CUSTOM_BIND)
+ continue;
+
+ switch (desc->device)
+ {
+ case RETRO_DEVICE_JOYPAD:
+ sys_info->input_desc_btn[retro_port]
+ [retro_id] = desc->description;
+ break;
+ case RETRO_DEVICE_ANALOG:
+ switch (retro_id)
+ {
+ case RETRO_DEVICE_ID_ANALOG_X:
+ switch (desc->index)
+ {
+ case RETRO_DEVICE_INDEX_ANALOG_LEFT:
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_LEFT_X_PLUS] = desc->description;
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_LEFT_X_MINUS] = desc->description;
+ break;
+ case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description;
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description;
+ break;
+ }
+ break;
+ case RETRO_DEVICE_ID_ANALOG_Y:
+ switch (desc->index)
+ {
+ case RETRO_DEVICE_INDEX_ANALOG_LEFT:
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description;
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description;
+ break;
+ case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description;
+ sys_info->input_desc_btn[retro_port]
+ [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description;
+ break;
+ }
+ break;
+ case RETRO_DEVICE_ID_JOYPAD_R2:
+ switch (desc->index)
+ {
+ case RETRO_DEVICE_INDEX_ANALOG_BUTTON:
+ sys_info->input_desc_btn[retro_port]
+ [retro_id] = desc->description;
+ break;
+ }
+ break;
+ case RETRO_DEVICE_ID_JOYPAD_L2:
+ switch (desc->index)
+ {
+ case RETRO_DEVICE_INDEX_ANALOG_BUTTON:
+ sys_info->input_desc_btn[retro_port]
+ [retro_id] = desc->description;
+ break;
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ RARCH_LOG("[Environ]: SET_INPUT_DESCRIPTORS:\n");
+
+ {
+ unsigned log_level = settings->uints.libretro_log_level;
+
+ if (log_level == RETRO_LOG_DEBUG)
+ {
+ unsigned input_driver_max_users = settings->uints.input_max_users;
+ unsigned bind_index;
+ const char *description;
+
+ for (p = 0; p < input_driver_max_users; p++)
+ {
+ unsigned mapped_port = settings->uints.input_remap_ports[p];
+
+ RARCH_DBG(" %s %u:\n", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT), p + 1);
+
+ for (retro_id = 0; retro_id < RETRO_DEVICE_ID_JOYPAD_MAX_BUTTONS; retro_id++)
+ {
+ bind_index = input_config_bind_order[retro_id];
+
+ if (bind_index == RARCH_UNMAPPED)
+ continue;
+
+ description = sys_info->input_desc_btn[mapped_port][bind_index];
+
+ if (!description)
+ continue;
+
+ RARCH_DBG(" \"%s\" => \"%s\"\n",
+ msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B + bind_index),
+ description);
+ }
+ }
+ }
+ }
+
+ runloop_st->current_core.flags |=
+ RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS;
+}
bool runloop_environment_cb(unsigned cmd, void *data)
{
@@ -2049,124 +2296,7 @@ bool runloop_environment_cb(unsigned cmd, void *data)
{
if (sys_info)
{
- unsigned retro_id;
- const struct retro_input_descriptor *desc = NULL;
- memset((void*)&sys_info->input_desc_btn, 0,
- sizeof(sys_info->input_desc_btn));
-
- desc = (const struct retro_input_descriptor*)data;
-
- for (; desc->description; desc++)
- {
- unsigned retro_port = desc->port;
-
- retro_id = desc->id;
-
- if (desc->port >= MAX_USERS)
- continue;
-
- if (desc->id >= RARCH_FIRST_CUSTOM_BIND)
- continue;
-
- switch (desc->device)
- {
- case RETRO_DEVICE_JOYPAD:
- sys_info->input_desc_btn[retro_port]
- [retro_id] = desc->description;
- break;
- case RETRO_DEVICE_ANALOG:
- switch (retro_id)
- {
- case RETRO_DEVICE_ID_ANALOG_X:
- switch (desc->index)
- {
- case RETRO_DEVICE_INDEX_ANALOG_LEFT:
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_LEFT_X_PLUS] = desc->description;
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_LEFT_X_MINUS] = desc->description;
- break;
- case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_RIGHT_X_PLUS] = desc->description;
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_RIGHT_X_MINUS] = desc->description;
- break;
- }
- break;
- case RETRO_DEVICE_ID_ANALOG_Y:
- switch (desc->index)
- {
- case RETRO_DEVICE_INDEX_ANALOG_LEFT:
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_LEFT_Y_PLUS] = desc->description;
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_LEFT_Y_MINUS] = desc->description;
- break;
- case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description;
- sys_info->input_desc_btn[retro_port]
- [RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description;
- break;
- }
- break;
- case RETRO_DEVICE_ID_JOYPAD_R2:
- switch (desc->index)
- {
- case RETRO_DEVICE_INDEX_ANALOG_BUTTON:
- sys_info->input_desc_btn[retro_port]
- [retro_id] = desc->description;
- break;
- }
- break;
- case RETRO_DEVICE_ID_JOYPAD_L2:
- switch (desc->index)
- {
- case RETRO_DEVICE_INDEX_ANALOG_BUTTON:
- sys_info->input_desc_btn[retro_port]
- [retro_id] = desc->description;
- break;
- }
- break;
- }
- break;
- }
- }
-
- RARCH_LOG("[Environ]: SET_INPUT_DESCRIPTORS:\n");
-
- {
- unsigned log_level = settings->uints.libretro_log_level;
-
- if (log_level == RETRO_LOG_DEBUG)
- {
- unsigned input_driver_max_users = settings->uints.input_max_users;
-
- for (p = 0; p < input_driver_max_users; p++)
- {
- unsigned mapped_port = settings->uints.input_remap_ports[p];
-
- RARCH_DBG(" %s %u:\n", msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT), p + 1);
-
- for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++)
- {
- unsigned bind_index = input_config_bind_order[retro_id];
- const char *description = sys_info->input_desc_btn[mapped_port][bind_index];
-
- if (!description)
- continue;
-
- RARCH_DBG(" \"%s\" => \"%s\"\n",
- msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B + bind_index),
- description);
- }
- }
- }
- }
-
- runloop_st->current_core.flags |=
- RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS;
+ rarch_set_input_descriptors(data, runloop_st, settings, sys_info);
}
break;
}
@@ -3551,6 +3681,12 @@ bool runloop_environment_cb(unsigned cmd, void *data)
}
}
break;
+
+ case RETRO_ENVIRONMENT_SET_EXTENDED_RETROPAD:
+ rarch_set_core_extended_retropad(sys_info, runloop_st,
+ (struct retro_core_extended_retropad*)data);
+ break;
+
default:
RARCH_LOG("[Environ]: UNSUPPORTED (#%u).\n", cmd);
return false;
@@ -7793,7 +7929,8 @@ bool core_has_set_input_descriptor(void)
{
runloop_state_t *runloop_st = &runloop_state;
return ((runloop_st->current_core.flags &
- RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS) > 0);
+ (RETRO_CORE_FLAG_HAS_SET_INPUT_DESCRIPTORS |
+ RETRO_CORE_FLAG_HAS_SET_EXTENDED_INPUT)) != 0);
}
void runloop_path_set_basename(const char *path)