From dad5e347d81e608a713eb1d9c3d4cf4d5056699b Mon Sep 17 00:00:00 2001 From: Themaister Date: Sun, 29 Sep 2013 17:58:46 +0200 Subject: [PATCH] Start adding joypad config. --- driver.h | 3 ++ frontend/menu/menu_common.c | 95 ++++++++++++++++++++++++++++++++ frontend/menu/menu_common.h | 34 ++++++++++-- frontend/menu/rgui.c | 96 +++++++++++++++++++-------------- frontend/menu/rguidisp_bitmap.c | 60 +++++++++++++++++---- input/x11_input.c | 7 +++ settings.c | 2 +- 7 files changed, 244 insertions(+), 53 deletions(-) diff --git a/driver.h b/driver.h index 764c1e4ab5..d5f3492260 100644 --- a/driver.h +++ b/driver.h @@ -323,6 +323,8 @@ enum keybind_set_id KEYBINDS_ACTION_LAST }; +typedef struct rarch_joypad_driver rarch_joypad_driver_t; + typedef struct input_driver { void *(*init)(void); @@ -336,6 +338,7 @@ typedef struct input_driver void (*grab_mouse)(void *data, bool state); bool (*set_rumble)(void *data, unsigned port, enum retro_rumble_effect effect, uint16_t state); + const rarch_joypad_driver_t *(*get_joypad_driver)(void *data); } input_driver_t; struct rarch_viewport; diff --git a/frontend/menu/menu_common.c b/frontend/menu/menu_common.c index 72541fda1a..14133f4170 100644 --- a/frontend/menu/menu_common.c +++ b/frontend/menu/menu_common.c @@ -22,8 +22,10 @@ #include "menu_common.h" #include "../../performance.h" +#include "../../driver.h" #include "../../file.h" #include "menu_context.h" +#include "../../input/input_common.h" #include "../../compat/posix_string.h" @@ -753,4 +755,97 @@ bool menu_save_new_config(void) return ret; } +void menu_poll_bind_state(struct rgui_bind_state *state) +{ + memset(state->state, 0, sizeof(state->state)); + state->skip = input_input_state_func(NULL, 0, RETRO_DEVICE_KEYBOARD, 0, RETROK_RETURN); + + const rarch_joypad_driver_t *joypad = NULL; + if (driver.input && driver.input_data && driver.input->get_joypad_driver) + joypad = driver.input->get_joypad_driver(driver.input_data); + + if (!joypad) + { + RARCH_ERR("Cannot poll raw joypad state."); + return; + } + + input_joypad_poll(joypad); + for (unsigned p = 0; p < MAX_PLAYERS; p++) + { + for (unsigned b = 0; b < RGUI_MAX_BUTTONS; b++) + state->state[p].buttons[b] = input_joypad_button_raw(joypad, p, b); + for (unsigned a = 0; a < RGUI_MAX_AXES; a++) + state->state[p].axes[a] = input_joypad_axis_raw(joypad, p, a); + for (unsigned h = 0; h < RGUI_MAX_HATS; h++) + { + state->state[p].hats[h] |= input_joypad_hat_raw(joypad, p, HAT_UP_MASK, h) ? HAT_UP_MASK : 0; + state->state[p].hats[h] |= input_joypad_hat_raw(joypad, p, HAT_DOWN_MASK, h) ? HAT_DOWN_MASK : 0; + state->state[p].hats[h] |= input_joypad_hat_raw(joypad, p, HAT_LEFT_MASK, h) ? HAT_LEFT_MASK : 0; + state->state[p].hats[h] |= input_joypad_hat_raw(joypad, p, HAT_RIGHT_MASK, h) ? HAT_RIGHT_MASK : 0; + } + } +} + +static bool menu_poll_find_trigger_pad(struct rgui_bind_state *state, const struct rgui_bind_state *new_state, unsigned p) +{ + const struct rgui_bind_state_port *n = &new_state->state[p]; + const struct rgui_bind_state_port *o = &state->state[p]; + for (unsigned b = 0; b < RGUI_MAX_BUTTONS; b++) + { + if (n->buttons[b] && !o->buttons[b]) + { + state->target->joykey = b; + state->target->joyaxis = AXIS_NONE; + return true; + } + } + + for (unsigned a = 0; a < RGUI_MAX_AXES; a++) + { + int axis_distance = abs(n->axes[a] - o->axes[a]); + if (abs(n->axes[a]) >= 20000 && axis_distance >= 20000) // Take care of case where axis rests on +/- 0x7fff (e.g. 360 controller on Linux) + { + state->target->joyaxis = n->axes[a] > 0 ? AXIS_POS(a) : AXIS_NEG(a); + state->target->joykey = NO_BTN; + return true; + } + } + + for (unsigned h = 0; h < RGUI_MAX_HATS; h++) + { + uint16_t trigged = n->hats[h] & (~o->hats[h]); + uint16_t sane_trigger = 0; + if (trigged & HAT_UP_MASK) + sane_trigger = HAT_UP_MASK; + else if (trigged & HAT_DOWN_MASK) + sane_trigger = HAT_DOWN_MASK; + else if (trigged & HAT_LEFT_MASK) + sane_trigger = HAT_LEFT_MASK; + else if (trigged & HAT_RIGHT_MASK) + sane_trigger = HAT_RIGHT_MASK; + + if (sane_trigger) + { + state->target->joykey = HAT_MAP(h, sane_trigger); + state->target->joyaxis = AXIS_NONE; + return true; + } + } + + return false; +} + +bool menu_poll_find_trigger(struct rgui_bind_state *state, const struct rgui_bind_state *new_state) +{ + for (unsigned p = 0; p < MAX_PLAYERS; p++) + { + if (menu_poll_find_trigger_pad(state, new_state, p)) + { + g_settings.input.joypad_map[state->player] = p; // Update the joypad mapping automatically. More friendly that way. + return true; + } + } + return false; +} diff --git a/frontend/menu/menu_common.h b/frontend/menu/menu_common.h index 36460a076d..0f0c26004a 100644 --- a/frontend/menu/menu_common.h +++ b/frontend/menu/menu_common.h @@ -147,22 +147,25 @@ typedef enum RGUI_SETTINGS_BIND_DEVICE, RGUI_SETTINGS_BIND_DEVICE_TYPE, RGUI_SETTINGS_BIND_DPAD_EMULATION, + + // Match up with libretro order for simplicity. + RGUI_SETTINGS_BIND_B, + RGUI_SETTINGS_BIND_Y, + RGUI_SETTINGS_BIND_SELECT, + RGUI_SETTINGS_BIND_START, RGUI_SETTINGS_BIND_UP, RGUI_SETTINGS_BIND_DOWN, RGUI_SETTINGS_BIND_LEFT, RGUI_SETTINGS_BIND_RIGHT, RGUI_SETTINGS_BIND_A, - RGUI_SETTINGS_BIND_B, RGUI_SETTINGS_BIND_X, - RGUI_SETTINGS_BIND_Y, - RGUI_SETTINGS_BIND_START, - RGUI_SETTINGS_BIND_SELECT, RGUI_SETTINGS_BIND_L, RGUI_SETTINGS_BIND_R, RGUI_SETTINGS_BIND_L2, RGUI_SETTINGS_BIND_R2, RGUI_SETTINGS_BIND_L3, RGUI_SETTINGS_BIND_R3, + RGUI_SETTINGS_CUSTOM_BIND, RGUI_SETTINGS_CORE_OPTION_NONE = 0xffff, RGUI_SETTINGS_CORE_OPTION_START = 0x10000 @@ -186,6 +189,27 @@ typedef enum RGUI_ACTION_NOOP } rgui_action_t; +#define RGUI_MAX_BUTTONS 32 +#define RGUI_MAX_AXES 32 +#define RGUI_MAX_HATS 4 +struct rgui_bind_state_port +{ + bool buttons[RGUI_MAX_BUTTONS]; + int16_t axes[RGUI_MAX_AXES]; + uint16_t hats[RGUI_MAX_HATS]; +}; + +struct rgui_bind_state +{ + struct retro_keybind *target; + unsigned player; + struct rgui_bind_state_port state[MAX_PLAYERS]; + bool skip; +}; + +void menu_poll_bind_state(struct rgui_bind_state *state); +bool menu_poll_find_trigger(struct rgui_bind_state *state, const struct rgui_bind_state *new_state); + typedef struct { uint64_t old_input_state; @@ -235,6 +259,8 @@ typedef struct rom_history_t *history; rarch_time_t last_time; // Used to throttle RGUI in case VSync is broken. + + struct rgui_bind_state binds; } rgui_handle_t; extern rgui_handle_t *rgui; diff --git a/frontend/menu/rgui.c b/frontend/menu/rgui.c index d367e8d757..d4f5baccc4 100644 --- a/frontend/menu/rgui.c +++ b/frontend/menu/rgui.c @@ -107,25 +107,6 @@ static int shader_manager_toggle_setting(rgui_handle_t *rgui, unsigned setting, #endif static int video_option_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action); -static const unsigned rgui_controller_lut[] = { - RETRO_DEVICE_ID_JOYPAD_UP, - RETRO_DEVICE_ID_JOYPAD_DOWN, - RETRO_DEVICE_ID_JOYPAD_LEFT, - RETRO_DEVICE_ID_JOYPAD_RIGHT, - RETRO_DEVICE_ID_JOYPAD_A, - RETRO_DEVICE_ID_JOYPAD_B, - RETRO_DEVICE_ID_JOYPAD_X, - RETRO_DEVICE_ID_JOYPAD_Y, - RETRO_DEVICE_ID_JOYPAD_START, - RETRO_DEVICE_ID_JOYPAD_SELECT, - RETRO_DEVICE_ID_JOYPAD_L, - RETRO_DEVICE_ID_JOYPAD_R, - RETRO_DEVICE_ID_JOYPAD_L2, - RETRO_DEVICE_ID_JOYPAD_R2, - RETRO_DEVICE_ID_JOYPAD_L3, - RETRO_DEVICE_ID_JOYPAD_R3, -}; - static void rgui_flush_menu_stack_type(rgui_handle_t *rgui, unsigned final_type) { rgui->need_refresh = true; @@ -726,10 +707,28 @@ static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, r else if (action == RGUI_ACTION_RIGHT) keybind_action = (1ULL << KEYBINDS_ACTION_INCREMENT_BIND); + // FIXME: The array indices here look totally wrong ... Fixed it so it looks sane for now. if (keybind_action != KEYBINDS_ACTION_NONE) - driver.input->set_keybinds(driver.input_data, g_settings.input.device[setting - RGUI_SETTINGS_BIND_UP], port, - rgui_controller_lut[setting - RGUI_SETTINGS_BIND_UP], keybind_action); + driver.input->set_keybinds(driver.input_data, g_settings.input.device[port], port, + setting - RGUI_SETTINGS_BIND_B, keybind_action); } + else + { + struct retro_keybind *bind = &g_settings.input.binds[port][setting - RGUI_SETTINGS_BIND_B]; + if (action == RGUI_ACTION_OK) + { + rgui->binds.target = bind; + rgui->binds.player = port; + rgui_list_push(rgui->menu_stack, "", RGUI_SETTINGS_CUSTOM_BIND, rgui->selection_ptr); + menu_poll_bind_state(&rgui->binds); + } + else if (action == RGUI_ACTION_START) + { + bind->joykey = NO_BTN; + bind->joyaxis = AXIS_NONE; + } + } + break; case RGUI_BROWSER_DIR_PATH: if (action == RGUI_ACTION_START) { @@ -1514,25 +1513,42 @@ static void rgui_settings_controller_populate_entries(rgui_handle_t *rgui) rgui_list_push(rgui->selection_buf, "Device Type", RGUI_SETTINGS_BIND_DEVICE_TYPE, 0); if (driver.input && driver.input->set_keybinds) - { rgui_list_push(rgui->selection_buf, "DPad Emulation", RGUI_SETTINGS_BIND_DPAD_EMULATION, 0); - rgui_list_push(rgui->selection_buf, "Up", RGUI_SETTINGS_BIND_UP, 0); - rgui_list_push(rgui->selection_buf, "Down", RGUI_SETTINGS_BIND_DOWN, 0); - rgui_list_push(rgui->selection_buf, "Left", RGUI_SETTINGS_BIND_LEFT, 0); - rgui_list_push(rgui->selection_buf, "Right", RGUI_SETTINGS_BIND_RIGHT, 0); - rgui_list_push(rgui->selection_buf, "A", RGUI_SETTINGS_BIND_A, 0); - rgui_list_push(rgui->selection_buf, "B", RGUI_SETTINGS_BIND_B, 0); - rgui_list_push(rgui->selection_buf, "X", RGUI_SETTINGS_BIND_X, 0); - rgui_list_push(rgui->selection_buf, "Y", RGUI_SETTINGS_BIND_Y, 0); - rgui_list_push(rgui->selection_buf, "Start", RGUI_SETTINGS_BIND_START, 0); - rgui_list_push(rgui->selection_buf, "Select", RGUI_SETTINGS_BIND_SELECT, 0); - rgui_list_push(rgui->selection_buf, "L", RGUI_SETTINGS_BIND_L, 0); - rgui_list_push(rgui->selection_buf, "R", RGUI_SETTINGS_BIND_R, 0); - rgui_list_push(rgui->selection_buf, "L2", RGUI_SETTINGS_BIND_L2, 0); - rgui_list_push(rgui->selection_buf, "R2", RGUI_SETTINGS_BIND_R2, 0); - rgui_list_push(rgui->selection_buf, "L3", RGUI_SETTINGS_BIND_L3, 0); - rgui_list_push(rgui->selection_buf, "R3", RGUI_SETTINGS_BIND_R3, 0); - } + + rgui_list_push(rgui->selection_buf, "Up", RGUI_SETTINGS_BIND_UP, 0); + rgui_list_push(rgui->selection_buf, "Down", RGUI_SETTINGS_BIND_DOWN, 0); + rgui_list_push(rgui->selection_buf, "Left", RGUI_SETTINGS_BIND_LEFT, 0); + rgui_list_push(rgui->selection_buf, "Right", RGUI_SETTINGS_BIND_RIGHT, 0); + rgui_list_push(rgui->selection_buf, "A (right)", RGUI_SETTINGS_BIND_A, 0); + rgui_list_push(rgui->selection_buf, "B (down)", RGUI_SETTINGS_BIND_B, 0); + rgui_list_push(rgui->selection_buf, "X (top)", RGUI_SETTINGS_BIND_X, 0); + rgui_list_push(rgui->selection_buf, "Y (left)", RGUI_SETTINGS_BIND_Y, 0); + rgui_list_push(rgui->selection_buf, "Start", RGUI_SETTINGS_BIND_START, 0); + rgui_list_push(rgui->selection_buf, "Select", RGUI_SETTINGS_BIND_SELECT, 0); + rgui_list_push(rgui->selection_buf, "L", RGUI_SETTINGS_BIND_L, 0); + rgui_list_push(rgui->selection_buf, "R", RGUI_SETTINGS_BIND_R, 0); + rgui_list_push(rgui->selection_buf, "L2", RGUI_SETTINGS_BIND_L2, 0); + rgui_list_push(rgui->selection_buf, "R2", RGUI_SETTINGS_BIND_R2, 0); + rgui_list_push(rgui->selection_buf, "L3", RGUI_SETTINGS_BIND_L3, 0); + rgui_list_push(rgui->selection_buf, "R3", RGUI_SETTINGS_BIND_R3, 0); +} + +// This only makes sense for PC so far. +// Consoles use set_keybind callbacks instead. +static int rgui_custom_bind_iterate(rgui_handle_t *rgui, rgui_action_t action) +{ + (void)action; // Have to ignore action here. Only bind that should work here is Quit RetroArch or something like that. + + render_text(rgui); + render_messagebox(rgui, "[key] press joypad (RETURN to skip)"); + + struct rgui_bind_state binds = rgui->binds; + menu_poll_bind_state(&binds); + + if ((binds.skip && !rgui->binds.skip) || menu_poll_find_trigger(&rgui->binds, &binds)) + rgui_list_pop(rgui->menu_stack, &rgui->selection_ptr); + rgui->binds = binds; + return 0; } static int rgui_viewport_iterate(rgui_handle_t *rgui, rgui_action_t action) @@ -2019,6 +2035,8 @@ static int rgui_iterate(void *data, unsigned action) return rgui_settings_iterate(rgui, action); else if (menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT || menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT_2) return rgui_viewport_iterate(rgui, action); + else if (menu_type == RGUI_SETTINGS_CUSTOM_BIND) + return rgui_custom_bind_iterate(rgui, action); if (rgui->need_refresh && action != RGUI_ACTION_MESSAGE) action = RGUI_ACTION_NOOP; diff --git a/frontend/menu/rguidisp_bitmap.c b/frontend/menu/rguidisp_bitmap.c index 30b994cc04..fde4167cd6 100644 --- a/frontend/menu/rguidisp_bitmap.c +++ b/frontend/menu/rguidisp_bitmap.c @@ -230,6 +230,7 @@ static void render_text(rgui_handle_t *rgui) (menu_type == RGUI_SETTINGS_PATH_OPTIONS) || (menu_type == RGUI_SETTINGS_OPTIONS) || (menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT || menu_type == RGUI_SETTINGS_CUSTOM_VIEWPORT_2) || + menu_type == RGUI_SETTINGS_CUSTOM_BIND || menu_type == RGUI_SETTINGS) snprintf(title, sizeof(title), "MENU %s", dir); else if (menu_type == RGUI_SETTINGS_OPEN_HISTORY) @@ -303,7 +304,7 @@ static void render_text(rgui_handle_t *rgui) rgui_list_get_at_offset(rgui->selection_buf, i, &path, &type); char message[256]; char type_str[256]; - unsigned w = (menu_type == RGUI_SETTINGS_INPUT_OPTIONS || menu_type == RGUI_SETTINGS_PATH_OPTIONS) ? 24 : 19; + unsigned w = (menu_type == RGUI_SETTINGS_INPUT_OPTIONS || menu_type == RGUI_SETTINGS_PATH_OPTIONS || menu_type == RGUI_SETTINGS_CUSTOM_BIND) ? 24 : 19; unsigned port = rgui->current_pad; #ifdef HAVE_SHADER_MANAGER @@ -624,18 +625,59 @@ static void render_text(rgui_handle_t *rgui) case RGUI_SETTINGS_BIND_R2: case RGUI_SETTINGS_BIND_L3: case RGUI_SETTINGS_BIND_R3: + { + unsigned id = type - RGUI_SETTINGS_BIND_B; + struct platform_bind key_label; + strlcpy(key_label.desc, "Unknown", sizeof(key_label.desc)); + key_label.joykey = g_settings.input.binds[port][id].joykey; + + if (driver.input->set_keybinds) { - unsigned id = rgui_controller_lut[type - RGUI_SETTINGS_BIND_UP]; - struct platform_bind key_label; - strlcpy(key_label.desc, "Unknown", sizeof(key_label.desc)); - key_label.joykey = g_settings.input.binds[port][id].joykey; - - if (driver.input->set_keybinds) - driver.input->set_keybinds(&key_label, 0, 0, 0, (1ULL << KEYBINDS_ACTION_GET_BIND_LABEL)); - + driver.input->set_keybinds(&key_label, 0, 0, 0, (1ULL << KEYBINDS_ACTION_GET_BIND_LABEL)); strlcpy(type_str, key_label.desc, sizeof(type_str)); } + else + { + const struct retro_keybind *bind = &g_settings.input.binds[port][type - RGUI_SETTINGS_BIND_B]; + if (bind->joykey != NO_BTN) + { + if (GET_HAT_DIR(bind->joykey)) + { + const char *dir; + switch (GET_HAT_DIR(bind->joykey)) + { + case HAT_UP_MASK: dir = "up"; break; + case HAT_DOWN_MASK: dir = "down"; break; + case HAT_LEFT_MASK: dir = "left"; break; + case HAT_RIGHT_MASK: dir = "right"; break; + default: dir = "?"; break; + } + snprintf(type_str, sizeof(type_str), "Hat #%u %s", (unsigned)GET_HAT(bind->joykey), dir); + } + else + snprintf(type_str, sizeof(type_str), "%u (btn)", (unsigned)bind->joykey); + } + else if (bind->joyaxis != AXIS_NONE) + { + unsigned axis = 0; + char dir = '\0'; + if (AXIS_NEG_GET(bind->joyaxis) != AXIS_DIR_NONE) + { + dir = '-'; + axis = AXIS_NEG_GET(bind->joyaxis); + } + else if (AXIS_POS_GET(bind->joyaxis) != AXIS_DIR_NONE) + { + dir = '+'; + axis = AXIS_POS_GET(bind->joyaxis); + } + snprintf(type_str, sizeof(type_str), "%c%u (axis)", dir, axis); + } + else + strlcpy(type_str, "", sizeof(type_str)); + } break; + } default: type_str[0] = 0; w = 0; diff --git a/input/x11_input.c b/input/x11_input.c index 1783698d42..76c9c19f34 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -275,6 +275,12 @@ static bool x_set_rumble(void *data, unsigned port, enum retro_rumble_effect eff return input_joypad_set_rumble(x11->joypad, port, effect, strength); } +static const rarch_joypad_driver_t *x_get_joypad_driver(void *data) +{ + x11_input_t *x11 = (x11_input_t*)data; + return x11->joypad; +} + const input_driver_t input_x = { x_input_init, x_input_poll, @@ -285,5 +291,6 @@ const input_driver_t input_x = { "x", x_grab_mouse, x_set_rumble, + x_get_joypad_driver, }; diff --git a/settings.c b/settings.c index 2916f04ff4..85d7a0302d 100644 --- a/settings.c +++ b/settings.c @@ -1179,7 +1179,7 @@ void settings_set(uint64_t settings) } if (settings & (1ULL << S_DEF_INPUT_OVERLAY_SCALE)) - g_settings.input.overlay_opacity = 1.0f; + g_settings.input.overlay_scale = 1.0f; #endif if (settings & (1ULL << S_REWIND_GRANULARITY_INCREMENT))