diff --git a/config.def.h b/config.def.h index d4da7e7a85..e5ffdffac5 100644 --- a/config.def.h +++ b/config.def.h @@ -329,6 +329,15 @@ static const struct snes_keybind snes_keybinds_1[] = { { true, RETRO_DEVICE_ID_JOYPAD_L3, SK_UNKNOWN, NO_BTN, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_R3, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_X_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_X_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_Y_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_Y_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_X_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_X_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_Y_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_Y_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_FAST_FORWARD_KEY, SK_SPACE, NO_BTN, AXIS_NONE }, { true, RARCH_FAST_FORWARD_HOLD_KEY, SK_l, NO_BTN, AXIS_NONE }, { true, RARCH_LOAD_STATE_KEY, SK_F4, NO_BTN, AXIS_NONE }, @@ -374,6 +383,15 @@ static const struct snes_keybind snes_keybinds_rest[] = { { true, RETRO_DEVICE_ID_JOYPAD_R2, SK_UNKNOWN, NO_BTN, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_L3, SK_UNKNOWN, NO_BTN, AXIS_NONE }, { true, RETRO_DEVICE_ID_JOYPAD_R3, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + + { true, RARCH_ANALOG_LEFT_X_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_X_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_Y_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_LEFT_Y_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_X_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_X_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_Y_PLUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, + { true, RARCH_ANALOG_RIGHT_Y_MINUS, SK_UNKNOWN, NO_BTN, AXIS_NONE }, }; #endif diff --git a/driver.h b/driver.h index 5908e71fbf..13391494d8 100644 --- a/driver.h +++ b/driver.h @@ -37,10 +37,27 @@ #define AUDIO_MAX_RATIO 16 // libretro has 16 buttons from 0-15 (libretro.h) -#define RARCH_FIRST_META_KEY 16 -enum +// Analog binds use RETRO_DEVICE_ANALOG, but we follow the same scheme internally +// in RetroArch for simplicity, +// so they are mapped into [16, 23]. +#define RARCH_FIRST_ANALOG_BIND 16 +#define RARCH_FIRST_META_KEY RARCH_ANALOG_BIND_LIST_END +enum // RetroArch specific bind IDs. { - RARCH_FAST_FORWARD_KEY = RARCH_FIRST_META_KEY, + // Analogs (RETRO_DEVICE_ANALOG) + RARCH_ANALOG_LEFT_X_PLUS = RARCH_FIRST_ANALOG_BIND, + RARCH_ANALOG_LEFT_X_MINUS, + RARCH_ANALOG_LEFT_Y_PLUS, + RARCH_ANALOG_LEFT_Y_MINUS, + RARCH_ANALOG_RIGHT_X_PLUS, + RARCH_ANALOG_RIGHT_X_MINUS, + RARCH_ANALOG_RIGHT_Y_PLUS, + RARCH_ANALOG_RIGHT_Y_MINUS, + + RARCH_ANALOG_BIND_LIST_END, + + // Command binds. + RARCH_FAST_FORWARD_KEY = RARCH_ANALOG_BIND_LIST_END, RARCH_FAST_FORWARD_HOLD_KEY, RARCH_LOAD_STATE_KEY, RARCH_SAVE_STATE_KEY, diff --git a/input/dinput.c b/input/dinput.c index 2bdb09e7c1..1dcf42078f 100644 --- a/input/dinput.c +++ b/input/dinput.c @@ -190,47 +190,60 @@ static bool dinput_joykey_pressed(sdl_dinput_t *di, unsigned port_num, uint16_t return false; } -static bool dinput_joyaxis_pressed(sdl_dinput_t *di, unsigned port_num, uint32_t joyaxis) +int16_t sdl_dinput_axis(sdl_dinput_t *di, unsigned port_num, const struct snes_keybind *key) { + uint32_t joyaxis = key->joyaxis; + if (joyaxis == AXIS_NONE) + return 0; + + int val = 0; + + int axis = -1; + bool is_neg = false; + bool is_pos = false; + + if (AXIS_NEG_GET(joyaxis) <= 5) + { + axis = AXIS_NEG_GET(joyaxis); + is_neg = true; + } + else if (AXIS_POS_GET(joyaxis) <= 5) + { + axis = AXIS_POS_GET(joyaxis); + is_pos = true; + } + + switch (axis) + { + case 0: val = di->joy_state[port_num].lX; break; + case 1: val = di->joy_state[port_num].lY; break; + case 2: val = di->joy_state[port_num].lZ; break; + case 3: val = di->joy_state[port_num].lRx; break; + case 4: val = di->joy_state[port_num].lRy; break; + case 5: val = di->joy_state[port_num].lRz; break; + } + + if (val < -0x7fff) // So abs() of -0x8000 can't mess us up. + val = -0x7fff; + + if (is_neg && val > 0) + val = 0; + else if (is_pos && val < 0) + val = 0; + + return val; +} + +static bool dinput_joyaxis_pressed(sdl_dinput_t *di, unsigned port_num, const struct snes_keybind *key) +{ + if (key->joyaxis == AXIS_NONE) return false; - int min = -32678 * g_settings.input.axis_threshold; - int max = 32677 * g_settings.input.axis_threshold; + int min = 0x7fff * g_settings.input.axis_threshold; - switch (AXIS_NEG_GET(joyaxis)) - { - case 0: - return di->joy_state[port_num].lX <= min; - case 1: - return di->joy_state[port_num].lY <= min; - case 2: - return di->joy_state[port_num].lZ <= min; - case 3: - return di->joy_state[port_num].lRx <= min; - case 4: - return di->joy_state[port_num].lRy <= min; - case 5: - return di->joy_state[port_num].lRz <= min; - } - - switch (AXIS_POS_GET(joyaxis)) - { - case 0: - return di->joy_state[port_num].lX >= max; - case 1: - return di->joy_state[port_num].lY >= max; - case 2: - return di->joy_state[port_num].lZ >= max; - case 3: - return di->joy_state[port_num].lRx >= max; - case 4: - return di->joy_state[port_num].lRy >= max; - case 5: - return di->joy_state[port_num].lRz >= max; - } - - return false; + int16_t val = sdl_dinput_axis(di, port_num, key); + return abs(val) > min; } bool sdl_dinput_pressed(sdl_dinput_t *di, unsigned port_num, const struct snes_keybind *key) @@ -239,7 +252,7 @@ bool sdl_dinput_pressed(sdl_dinput_t *di, unsigned port_num, const struct snes_k return false; if (dinput_joykey_pressed(di, port_num, key->joykey)) return true; - if (dinput_joyaxis_pressed(di, port_num, key->joyaxis)) + if (dinput_joyaxis_pressed(di, port_num, key)) return true; return false; diff --git a/input/rarch_dinput.h b/input/rarch_dinput.h index c35403a8ac..9bfc8be479 100644 --- a/input/rarch_dinput.h +++ b/input/rarch_dinput.h @@ -40,6 +40,9 @@ void sdl_dinput_free(sdl_dinput_t *di); bool sdl_dinput_pressed(sdl_dinput_t *di, unsigned port_num, const struct snes_keybind *key); +int16_t sdl_dinput_axis(sdl_dinput_t *di, unsigned port_num, + const struct snes_keybind *key); + void sdl_dinput_poll(sdl_dinput_t *di); diff --git a/input/sdl_input.c b/input/sdl_input.c index a0bc134269..6260ebbf8d 100644 --- a/input/sdl_input.c +++ b/input/sdl_input.c @@ -223,27 +223,38 @@ static bool sdl_joykey_pressed(sdl_input_t *sdl, int port_num, uint16_t joykey) } } -static bool sdl_axis_pressed(sdl_input_t *sdl, int port_num, uint32_t joyaxis) +static int16_t sdl_axis_analog(sdl_input_t *sdl, unsigned port_num, uint32_t joyaxis) { if (joyaxis == AXIS_NONE) - return false; + return 0; + Sint16 val = 0; if (AXIS_NEG_GET(joyaxis) < sdl->num_axes[port_num]) { - Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_NEG_GET(joyaxis)); - float scaled = (float)val / 0x8000; - if (scaled < -g_settings.input.axis_threshold) - return true; + val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_NEG_GET(joyaxis)); + + if (val > 0) + val = 0; + else if (val < -0x8000) // -0x8000 can cause trouble if we later abs() it. + val = -0x7fff; } - if (AXIS_POS_GET(joyaxis) < sdl->num_axes[port_num]) + else if (AXIS_POS_GET(joyaxis) < sdl->num_axes[port_num]) { - Sint16 val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_POS_GET(joyaxis)); - float scaled = (float)val / 0x8000; - if (scaled > g_settings.input.axis_threshold) - return true; + val = SDL_JoystickGetAxis(sdl->joysticks[port_num], AXIS_POS_GET(joyaxis)); + + if (val < 0) + val = 0; } - return false; + return val; +} + +static bool sdl_axis_pressed(sdl_input_t *sdl, unsigned port_num, uint32_t joyaxis) +{ + int16_t val = sdl_axis_analog(sdl, port_num, joyaxis); + + float scaled = (float)abs(val) / 0x8000; + return scaled > g_settings.input.axis_threshold; } #endif @@ -291,6 +302,69 @@ static int16_t sdl_joypad_device_state(sdl_input_t *sdl, const struct snes_keybi return 0; } +static void conv_analog_id_to_bind_id(unsigned index, unsigned id, + unsigned *id_minus, unsigned *id_plus) +{ + switch ((index << 1) | id) + { + case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_X: + *id_minus = RARCH_ANALOG_LEFT_X_MINUS; + *id_plus = RARCH_ANALOG_LEFT_X_PLUS; + break; + + case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_Y: + *id_minus = RARCH_ANALOG_LEFT_Y_MINUS; + *id_plus = RARCH_ANALOG_LEFT_Y_PLUS; + break; + + case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_X: + *id_minus = RARCH_ANALOG_RIGHT_X_MINUS; + *id_plus = RARCH_ANALOG_RIGHT_X_PLUS; + break; + + case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_Y: + *id_minus = RARCH_ANALOG_RIGHT_Y_MINUS; + *id_plus = RARCH_ANALOG_RIGHT_Y_PLUS; + break; + } +} + +static int16_t sdl_analog_device_state(sdl_input_t *sdl, const struct snes_keybind **binds_, + unsigned port_num, unsigned index, unsigned id) +{ + const struct snes_keybind *binds = binds_[port_num]; + if (id >= RARCH_BIND_LIST_END) + return 0; + + unsigned id_minus = 0; + unsigned id_plus = 0; + conv_analog_id_to_bind_id(index, id, &id_minus, &id_plus); + + const struct snes_keybind *bind_minus = &binds[id_minus]; + const struct snes_keybind *bind_plus = &binds[id_plus]; + if (!bind_minus->valid || !bind_plus->valid) + return 0; + + // A user might have bound minus axis to positive axis in SDL. +#ifdef HAVE_DINPUT + int16_t pressed_minus = abs(sdl_dinput_axis(sdl->di, port_num, bind_minus)); + int16_t pressed_plus = abs(sdl_dinput_axis(sdl->di, port_num, bind_plus)); +#else + int16_t pressed_minus = abs(sdl_axis_analog(sdl, port_num, bind_minus->joyaxis)); + int16_t pressed_plus = abs(sdl_axis_analog(sdl, port_num, bind_plus->joyaxis)); +#endif + + int16_t res = pressed_plus - pressed_minus; + + // TODO: Does it make sense to use axis thresholding here? + if (res != 0) + return res; + + int16_t digital_left = sdl_is_pressed(sdl, port_num, bind_minus) ? -0x7fff : 0; + int16_t digital_right = sdl_is_pressed(sdl, port_num, bind_plus) ? 0x7fff : 0; + return digital_right + digital_left; +} + static int16_t sdl_mouse_device_state(sdl_input_t *sdl, unsigned id) { switch (id) @@ -338,6 +412,8 @@ static int16_t sdl_input_state(void *data_, const struct snes_keybind **binds, u { case RETRO_DEVICE_JOYPAD: return sdl_joypad_device_state(data, binds, port, id); + case RETRO_DEVICE_ANALOG: + return sdl_analog_device_state(data, binds, port, index, id); case RETRO_DEVICE_MOUSE: return sdl_mouse_device_state(data, id); case RETRO_DEVICE_LIGHTGUN: diff --git a/input/x11_input.c b/input/x11_input.c index 58e4623f1d..2bdf173335 100644 --- a/input/x11_input.c +++ b/input/x11_input.c @@ -197,6 +197,9 @@ static int16_t x_input_state(void *data, const struct snes_keybind **binds, unsi return x_is_pressed(x11, binds[port], id) || input_sdl.input_state(x11->sdl, binds, port, device, index, id); + case RETRO_DEVICE_ANALOG: + return input_sdl.input_state(x11->sdl, binds, port, device, index, id); + default: return 0; } diff --git a/libretro-test/libretro-test.c b/libretro-test/libretro-test.c index 8d2080e3f3..c4f92179f9 100644 --- a/libretro-test/libretro-test.c +++ b/libretro-test/libretro-test.c @@ -115,6 +115,11 @@ static void update_input(void) if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT)) dir_x++; + dir_x += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / 2000; + dir_y += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / 2000; + //dir_x += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 2000; + //dir_y += input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / 2000; + x_coord = (x_coord + dir_x) & 31; y_coord = (y_coord + dir_y) & 31; } diff --git a/retroarch.cfg b/retroarch.cfg index 8781bfddef..4d7730b41c 100644 --- a/retroarch.cfg +++ b/retroarch.cfg @@ -203,6 +203,19 @@ # input_player1_l3 = # input_player1_r3 = +# Two analog sticks (DualShock-esque). +# Bound as usual, however, if a real analog axis is bound, +# it can be read as a true analog. +# Positive X axis is right, Positive Y axis is down. +# input_player1_l_x_plus = +# input_player1_l_x_minus = +# input_player1_l_y_plus = +# input_player1_l_y_minus = +# input_player1_r_x_plus = +# input_player1_r_x_minus = +# input_player1_r_y_plus = +# input_player1_r_y_minus = + # If desired, it is possible to override which joypads are being used for player 1 through 5. First joypad available is 0. # input_player1_joypad_index = 0 # input_player2_joypad_index = 1 diff --git a/settings.c b/settings.c index 01b45da816..eacc1a7f7a 100644 --- a/settings.c +++ b/settings.c @@ -527,44 +527,35 @@ struct bind_map #define DECLARE_BIND(x, bind) { true, "input_" #x, "input_" #x "_btn", "input_" #x "_axis", bind } #define DECL_PLAYER(P) \ - { \ - DECLARE_BIND(player##P##_b, RETRO_DEVICE_ID_JOYPAD_B), \ - DECLARE_BIND(player##P##_y, RETRO_DEVICE_ID_JOYPAD_Y), \ - DECLARE_BIND(player##P##_select, RETRO_DEVICE_ID_JOYPAD_SELECT), \ - DECLARE_BIND(player##P##_start, RETRO_DEVICE_ID_JOYPAD_START), \ - DECLARE_BIND(player##P##_up, RETRO_DEVICE_ID_JOYPAD_UP), \ - DECLARE_BIND(player##P##_down, RETRO_DEVICE_ID_JOYPAD_DOWN), \ - DECLARE_BIND(player##P##_left, RETRO_DEVICE_ID_JOYPAD_LEFT), \ - DECLARE_BIND(player##P##_right, RETRO_DEVICE_ID_JOYPAD_RIGHT), \ - DECLARE_BIND(player##P##_a, RETRO_DEVICE_ID_JOYPAD_A), \ - DECLARE_BIND(player##P##_x, RETRO_DEVICE_ID_JOYPAD_X), \ - DECLARE_BIND(player##P##_l, RETRO_DEVICE_ID_JOYPAD_L), \ - DECLARE_BIND(player##P##_r, RETRO_DEVICE_ID_JOYPAD_R), \ - DECLARE_BIND(player##P##_l2, RETRO_DEVICE_ID_JOYPAD_L2), \ - DECLARE_BIND(player##P##_r2, RETRO_DEVICE_ID_JOYPAD_R2), \ - DECLARE_BIND(player##P##_l3, RETRO_DEVICE_ID_JOYPAD_L3), \ - DECLARE_BIND(player##P##_r3, RETRO_DEVICE_ID_JOYPAD_R3), \ - } + DECLARE_BIND(player##P##_b, RETRO_DEVICE_ID_JOYPAD_B), \ + DECLARE_BIND(player##P##_y, RETRO_DEVICE_ID_JOYPAD_Y), \ + DECLARE_BIND(player##P##_select, RETRO_DEVICE_ID_JOYPAD_SELECT), \ + DECLARE_BIND(player##P##_start, RETRO_DEVICE_ID_JOYPAD_START), \ + DECLARE_BIND(player##P##_up, RETRO_DEVICE_ID_JOYPAD_UP), \ + DECLARE_BIND(player##P##_down, RETRO_DEVICE_ID_JOYPAD_DOWN), \ + DECLARE_BIND(player##P##_left, RETRO_DEVICE_ID_JOYPAD_LEFT), \ + DECLARE_BIND(player##P##_right, RETRO_DEVICE_ID_JOYPAD_RIGHT), \ + DECLARE_BIND(player##P##_a, RETRO_DEVICE_ID_JOYPAD_A), \ + DECLARE_BIND(player##P##_x, RETRO_DEVICE_ID_JOYPAD_X), \ + DECLARE_BIND(player##P##_l, RETRO_DEVICE_ID_JOYPAD_L), \ + DECLARE_BIND(player##P##_r, RETRO_DEVICE_ID_JOYPAD_R), \ + DECLARE_BIND(player##P##_l2, RETRO_DEVICE_ID_JOYPAD_L2), \ + DECLARE_BIND(player##P##_r2, RETRO_DEVICE_ID_JOYPAD_R2), \ + DECLARE_BIND(player##P##_l3, RETRO_DEVICE_ID_JOYPAD_L3), \ + DECLARE_BIND(player##P##_r3, RETRO_DEVICE_ID_JOYPAD_R3), \ + DECLARE_BIND(player##P##_l_x_plus, RARCH_ANALOG_LEFT_X_PLUS), \ + DECLARE_BIND(player##P##_l_x_minus, RARCH_ANALOG_LEFT_X_MINUS), \ + DECLARE_BIND(player##P##_l_y_plus, RARCH_ANALOG_LEFT_Y_PLUS), \ + DECLARE_BIND(player##P##_l_y_minus, RARCH_ANALOG_LEFT_Y_MINUS), \ + DECLARE_BIND(player##P##_r_x_plus, RARCH_ANALOG_RIGHT_X_PLUS), \ + DECLARE_BIND(player##P##_r_x_minus, RARCH_ANALOG_RIGHT_X_MINUS), \ + DECLARE_BIND(player##P##_r_y_plus, RARCH_ANALOG_RIGHT_Y_PLUS), \ + DECLARE_BIND(player##P##_r_y_minus, RARCH_ANALOG_RIGHT_Y_MINUS) // Big and nasty bind map... :) static const struct bind_map bind_maps[MAX_PLAYERS][RARCH_BIND_LIST_END_NULL] = { { - DECLARE_BIND(player1_b, RETRO_DEVICE_ID_JOYPAD_B), - DECLARE_BIND(player1_y, RETRO_DEVICE_ID_JOYPAD_Y), - DECLARE_BIND(player1_select, RETRO_DEVICE_ID_JOYPAD_SELECT), - DECLARE_BIND(player1_start, RETRO_DEVICE_ID_JOYPAD_START), - DECLARE_BIND(player1_up, RETRO_DEVICE_ID_JOYPAD_UP), - DECLARE_BIND(player1_down, RETRO_DEVICE_ID_JOYPAD_DOWN), - DECLARE_BIND(player1_left, RETRO_DEVICE_ID_JOYPAD_LEFT), - DECLARE_BIND(player1_right, RETRO_DEVICE_ID_JOYPAD_RIGHT), - DECLARE_BIND(player1_a, RETRO_DEVICE_ID_JOYPAD_A), - DECLARE_BIND(player1_x, RETRO_DEVICE_ID_JOYPAD_X), - DECLARE_BIND(player1_l, RETRO_DEVICE_ID_JOYPAD_L), - DECLARE_BIND(player1_r, RETRO_DEVICE_ID_JOYPAD_R), - DECLARE_BIND(player1_l2, RETRO_DEVICE_ID_JOYPAD_L2), - DECLARE_BIND(player1_r2, RETRO_DEVICE_ID_JOYPAD_R2), - DECLARE_BIND(player1_l3, RETRO_DEVICE_ID_JOYPAD_L3), - DECLARE_BIND(player1_r3, RETRO_DEVICE_ID_JOYPAD_R3), + DECL_PLAYER(1), DECLARE_BIND(toggle_fast_forward, RARCH_FAST_FORWARD_KEY), DECLARE_BIND(hold_fast_forward, RARCH_FAST_FORWARD_HOLD_KEY), @@ -593,13 +584,13 @@ static const struct bind_map bind_maps[MAX_PLAYERS][RARCH_BIND_LIST_END_NULL] = DECLARE_BIND(slowmotion, RARCH_SLOWMOTION), }, - DECL_PLAYER(2), - DECL_PLAYER(3), - DECL_PLAYER(4), - DECL_PLAYER(5), - DECL_PLAYER(6), - DECL_PLAYER(7), - DECL_PLAYER(8), + { DECL_PLAYER(2) }, + { DECL_PLAYER(3) }, + { DECL_PLAYER(4) }, + { DECL_PLAYER(5) }, + { DECL_PLAYER(6) }, + { DECL_PLAYER(7) }, + { DECL_PLAYER(8) }, }; struct key_map diff --git a/tools/retroarch-joyconfig.c b/tools/retroarch-joyconfig.c index 417e0d5f73..0754933dc3 100644 --- a/tools/retroarch-joyconfig.c +++ b/tools/retroarch-joyconfig.c @@ -60,53 +60,62 @@ struct bind bool is_misc; }; -#define BIND(x, k) { x, { "input_player1_" #k "_btn", "input_player2_" #k "_btn", "input_player3_" #k "_btn", "input_player4_" #k "_btn", "input_player5_" #k "_btn" }, {"input_player1_" #k "_axis", "input_player2_" #k "_axis", "input_player3_" #k "_axis", "input_player4_" #k "_axis", "input_player5_" #k "_axis"}, false}, +#define BIND(x, k) { x, { "input_player1_" #k "_btn", "input_player2_" #k "_btn", "input_player3_" #k "_btn", "input_player4_" #k "_btn", "input_player5_" #k "_btn" }, {"input_player1_" #k "_axis", "input_player2_" #k "_axis", "input_player3_" #k "_axis", "input_player4_" #k "_axis", "input_player5_" #k "_axis"}, false} -#define MISC_BIND(x, k) { x, { "input_" #k "_btn" }, { "input_" #k "_axis" }, true}, +#define MISC_BIND(x, k) { x, { "input_" #k "_btn" }, { "input_" #k "_axis" }, true} static struct bind binds[] = { - BIND("A button (right)", a) - BIND("B button (down)", b) - BIND("X button (top)", x) - BIND("Y button (left)", y) - BIND("L button (left shoulder)", l) - BIND("R button (right shoulder)", r) - BIND("L2 button (left shoulder #2)", l2) - BIND("R2 button (right shoulder #2)", r2) - BIND("L3 button (left analog button)", l3) - BIND("R3 button (right analog button)", r3) - BIND("Start button", start) - BIND("Select button", select) - BIND("Left D-pad", left) - BIND("Up D-pad", up) - BIND("Right D-pad", right) - BIND("Down D-pad", down) + BIND("A button (right)", a), + BIND("B button (down)", b), + BIND("X button (top)", x), + BIND("Y button (left)", y), + BIND("L button (left shoulder)", l), + BIND("R button (right shoulder)", r), + BIND("L2 button (left shoulder #2)", l2), + BIND("R2 button (right shoulder #2)", r2), + BIND("L3 button (left analog button)", l3), + BIND("R3 button (right analog button)", r3), + BIND("Start button", start), + BIND("Select button", select), + BIND("Left D-pad", left), + BIND("Up D-pad", up), + BIND("Right D-pad", right), + BIND("Down D-pad", down), - MISC_BIND("Save state", save_state) - MISC_BIND("Load state", load_state) - MISC_BIND("Exit emulator", exit_emulator) - MISC_BIND("Toggle fullscreen", toggle_fullscreen) - MISC_BIND("Save state slot increase", state_slot_increase) - MISC_BIND("Save state slot decrease", state_slot_decrease) - MISC_BIND("Toggle fast forward", toggle_fast_forward) - MISC_BIND("Hold fast forward", hold_fast_forward) - MISC_BIND("Audio input rate step up", rate_step_up) - MISC_BIND("Audio input rate step down", rate_step_down) - MISC_BIND("Rewind", rewind) - MISC_BIND("Movie recording toggle", movie_record_toggle) - MISC_BIND("Pause", pause_toggle) - MISC_BIND("Frame advance", frame_advance) - MISC_BIND("Reset", reset) - MISC_BIND("Next shader", shader_next) - MISC_BIND("Previous shader", shader_prev) - MISC_BIND("Toggle cheat on/off", cheat_toggle) - MISC_BIND("Cheat index plus", cheat_index_plus) - MISC_BIND("Cheat index minus", cheat_index_minus) - MISC_BIND("Screenshot", screenshot) - MISC_BIND("DSP config", dsp_config) - MISC_BIND("Audio mute/unmute", audio_mute) - MISC_BIND("Netplay player flip", netplay_flip_players) - MISC_BIND("Slow motion", slowmotion) + BIND("Left analog X+ (right)", l_x_plus), + BIND("Left analog Y+ (down)", l_y_plus), + BIND("Left analog X- (left)", l_x_minus), + BIND("Left analog Y- (up)", l_y_minus), + BIND("Right analog X+ (right)", r_x_plus), + BIND("Right analog Y+ (down)", r_y_plus), + BIND("Right analog X- (left)", r_x_minus), + BIND("Right analog Y- (up)", r_y_minus), + + MISC_BIND("Save state", save_state), + MISC_BIND("Load state", load_state), + MISC_BIND("Exit emulator", exit_emulator), + MISC_BIND("Toggle fullscreen", toggle_fullscreen), + MISC_BIND("Save state slot increase", state_slot_increase), + MISC_BIND("Save state slot decrease", state_slot_decrease), + MISC_BIND("Toggle fast forward", toggle_fast_forward), + MISC_BIND("Hold fast forward", hold_fast_forward), + MISC_BIND("Audio input rate step up", rate_step_up), + MISC_BIND("Audio input rate step down", rate_step_down), + MISC_BIND("Rewind", rewind), + MISC_BIND("Movie recording toggle", movie_record_toggle), + MISC_BIND("Pause", pause_toggle), + MISC_BIND("Frame advance", frame_advance), + MISC_BIND("Reset", reset), + MISC_BIND("Next shader", shader_next), + MISC_BIND("Previous shader", shader_prev), + MISC_BIND("Toggle cheat on/off", cheat_toggle), + MISC_BIND("Cheat index plus", cheat_index_plus), + MISC_BIND("Cheat index minus", cheat_index_minus), + MISC_BIND("Screenshot", screenshot), + MISC_BIND("DSP config", dsp_config), + MISC_BIND("Audio mute/unmute", audio_mute), + MISC_BIND("Netplay player flip", netplay_flip_players), + MISC_BIND("Slow motion", slowmotion), }; static void get_binds(config_file_t *conf, int player, int joypad) @@ -116,6 +125,7 @@ static void get_binds(config_file_t *conf, int player, int joypad) fprintf(stderr, "Failed to init joystick subsystem.\n"); exit(1); } + SDL_Joystick *joystick; int num = SDL_NumJoysticks(); if (joypad >= num) @@ -131,8 +141,9 @@ static void get_binds(config_file_t *conf, int player, int joypad) exit(1); } - int last_axis = 0xFF; - int last_pos = 0; + int last_axis = -1; + bool block_axis = false; + int num_axes = SDL_JoystickNumAxes(joystick); int *initial_axes = (int*)calloc(num_axes, sizeof(int)); assert(initial_axes); @@ -140,7 +151,20 @@ static void get_binds(config_file_t *conf, int player, int joypad) SDL_PumpEvents(); SDL_JoystickUpdate(); for (int i = 0; i < num_axes; i++) - initial_axes[i] = SDL_JoystickGetAxis(joystick, i); + { + Sint16 initial = SDL_JoystickGetAxis(joystick, i); + if (abs(initial) < 20000) + initial = 0; + + // Certain joypads (such as XBox360 controller on Linux) has a default negative axis for shoulder triggers, + // which makes configuration very awkward. + // If default negative, we can't trigger on the negative axis, and similar with defaulted positive axes. + + if (initial) + fprintf(stderr, "Axis %d is defaulted to %s axis value of %d\n", i, initial > 0 ? "positive" : "negative", (int)initial); + + initial_axes[i] = initial; + } fprintf(stderr, "Configuring binds for player #%d on joypad #%d (%s)\n", player + 1, joypad, SDL_JoystickName(joypad)); @@ -168,27 +192,44 @@ static void get_binds(config_file_t *conf, int player, int joypad) break; case SDL_JOYAXISMOTION: - if ( // This is starting to look like Lisp. :D - (abs((int)event.jaxis.value - initial_axes[event.jaxis.axis]) > 20000) && - ( - (event.jaxis.axis != last_axis) || - ( - (abs(event.jaxis.value) > 20000) && - (abs((int)event.jaxis.value - last_pos) > 20000) - ) - ) - ) + { + bool same_axis = last_axis == event.jaxis.axis; + bool require_negative = initial_axes[event.jaxis.axis] > 0; + bool require_positive = initial_axes[event.jaxis.axis] < 0; + + // Block the axis config until we're sure axes have returned to their neutral state. + if (same_axis) + { + if (abs(event.jaxis.value) < 10000 || + (require_positive && event.jaxis.value < 0) || + (require_negative && event.jaxis.value > 0)) + block_axis = false; + } + + // If axes are in their neutral state, we can't allow it. + if (require_negative && event.jaxis.value >= 0) + break; + if (require_positive && event.jaxis.value <= 0) + break; + + if (block_axis) + break; + + if (abs(event.jaxis.value) > 20000) { last_axis = event.jaxis.axis; - last_pos = event.jaxis.value; fprintf(stderr, "\tJoyaxis moved: Axis %d, Value %d\n", (int)event.jaxis.axis, (int)event.jaxis.value); - done = true; + + done = true; + block_axis = true; char buf[8]; snprintf(buf, sizeof(buf), event.jaxis.value > 0 ? "+%d" : "-%d", event.jaxis.axis); config_set_string(conf, binds[i].confaxis[player_index], buf); } + break; + } case SDL_KEYDOWN: fprintf(stderr, ":V\n");