From cb8dc86c9158ebf7220bc649d7a2b2c9d8536540 Mon Sep 17 00:00:00 2001 From: Taylor Richards Date: Sat, 9 Mar 2019 10:50:26 -0500 Subject: [PATCH] first pass at proper gamepad support --- include/joy.h | 9 +- src/io/joy.cpp | 260 +++++++++++++++++++++++++------------------- src/io/joy_ff.cpp | 11 +- src/osapi/osapi.cpp | 52 +++++++++ 4 files changed, 212 insertions(+), 120 deletions(-) diff --git a/include/joy.h b/include/joy.h index 2c6948c..37aa406 100644 --- a/include/joy.h +++ b/include/joy.h @@ -92,14 +92,6 @@ #define JOY_AXIS_UNDEFINED -10000 -typedef struct Joy_info { - int num_axes; - int axis_min[JOY_NUM_AXES]; - int axis_center[JOY_NUM_AXES]; - int axis_max[JOY_NUM_AXES]; - int axis_current[JOY_NUM_AXES]; -} Joy_info; - extern int Joy_sensitivity; extern int Dead_zone_size; // percentage of range that is dead zone @@ -125,6 +117,7 @@ int joy_get_unscaled_reading(int axn); bool joy_axis_valid(int axis); void joy_mark_button(int btn, int state); int joystick_get_id(); +bool joystick_is_controller(); void joystick_update_axis(int axis, int value); #endif /* __JOY_H__ */ diff --git a/src/io/joy.cpp b/src/io/joy.cpp index fea096d..493e47b 100644 --- a/src/io/joy.cpp +++ b/src/io/joy.cpp @@ -23,6 +23,17 @@ int Joy_sensitivity = 9; static int Joy_last_x_reading = 0; static int Joy_last_y_reading = 0; +typedef struct Joy_info { + int num_axes; + int is_controller; + int axis_min[JOY_NUM_AXES]; + int axis_center[JOY_NUM_AXES]; + int axis_max[JOY_NUM_AXES]; + int axis_current[JOY_NUM_AXES]; +} Joy_info; + +static Joy_info joystick; + typedef struct joy_button_info { int actual_state; // Set if the button is physically down int state; // Set when the button goes from up to down, cleared on down to up. Different than actual_state after a flush. @@ -32,17 +43,20 @@ typedef struct joy_button_info { uint last_down_check; // timestamp in milliseconds of last } joy_button_info; -static Joy_info joystick; +joy_button_info joy_buttons[JOY_TOTAL_BUTTONS]; -SDL_Joystick *sdljoy; -static SDL_JoystickID joy_id = -1; +static SDL_JoystickID JoystickID = -1; -joy_button_info joy_buttons[JOY_TOTAL_BUTTONS]; int joystick_get_id() { - return joy_id; + return JoystickID; +} + +bool joystick_is_controller() +{ + return (joystick.is_controller == 1); } void joy_close() @@ -53,13 +67,22 @@ void joy_close() joy_ff_shutdown(); Joy_inited = 0; - joy_id = -1; - if (SDL_JoystickGetAttached(sdljoy)) { - SDL_JoystickClose(sdljoy); + if ( joystick_is_controller() ) { + SDL_GameController *sdlcon = SDL_GameControllerFromInstanceID(JoystickID); + + if ( SDL_GameControllerGetAttached(sdlcon) ) { + SDL_GameControllerClose(sdlcon); + } + } else { + SDL_Joystick *sdljoy = SDL_JoystickFromInstanceID(JoystickID); + + if ( SDL_JoystickGetAttached(sdljoy) ) { + SDL_JoystickClose(sdljoy); + } } - sdljoy = NULL; + JoystickID = -1; SDL_QuitSubSystem(SDL_INIT_JOYSTICK); } @@ -336,22 +359,17 @@ int joy_get_pos(int *x, int *y, int *z, int *rx) return 1; } -int joy_init() +static int joy_init_internal(int with_index) { int i, num_sticks; - const char *ptr = NULL; + const char *ptr = nullptr; int Cur_joystick; + SDL_Joystick *sdljoy = nullptr; + const char *joy_name = nullptr; + SDL_JoystickGUID guid; + char guid_str[40]; - if (Joy_inited) { - return 0; - } - - mprintf(("Initializing Joystick...\n")); - - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) { - mprintf((" Could not initialize joystick subsystem\n\n")); - return 0; - } + SDL_zero(joystick); num_sticks = SDL_NumJoysticks(); @@ -360,29 +378,67 @@ int joy_init() return 0; } - Cur_joystick = 0; + if ( (with_index >= 0) && (with_index < num_sticks) ) { + Cur_joystick = with_index; + } else { + Cur_joystick = 0; - ptr = os_config_read_string("Controls", "CurrentJoystick", NULL); + ptr = os_config_read_string("Controls", "CurrentJoystick", nullptr); - if ( ptr && SDL_strlen(ptr) ) { - for (i = 0; i < num_sticks; i++) { - const char *jname = SDL_JoystickNameForIndex(i); + if ( ptr && SDL_strlen(ptr) ) { + for (i = 0; i < num_sticks; i++) { + const char *jname = nullptr; + + if ( SDL_IsGameController(i) ) { + jname = SDL_GameControllerNameForIndex(i); + } else { + jname = SDL_JoystickNameForIndex(i); + } - if ( jname && !SDL_strcasecmp(ptr, jname) ) { - Cur_joystick = i; - break; + if ( jname && !SDL_strcasecmp(ptr, jname) ) { + Cur_joystick = i; + break; + } } } } - sdljoy = SDL_JoystickOpen(Cur_joystick); + if ( SDL_IsGameController(Cur_joystick) ) { + joystick.is_controller = 1; - if (sdljoy == NULL) { - mprintf((" Unable to init joystick %d (%s)\n\n", Cur_joystick, SDL_JoystickNameForIndex(Cur_joystick))); - return 0; + SDL_GameController *sdlcon = SDL_GameControllerOpen(Cur_joystick); + + if (sdlcon == nullptr) { + mprintf((" Unable to init game controller %d (%s)\n\n", Cur_joystick, SDL_GameControllerNameForIndex(Cur_joystick))); + return 0; + } + + joy_name = SDL_GameControllerName(sdlcon); + + sdljoy = SDL_GameControllerGetJoystick(sdlcon); + } else { + joystick.is_controller = 0; + + sdljoy = SDL_JoystickOpen(Cur_joystick); + + if (sdljoy == nullptr) { + mprintf((" Unable to init joystick %d (%s)\n\n", Cur_joystick, SDL_JoystickNameForIndex(Cur_joystick))); + return 0; + } + + joy_name = SDL_JoystickName(sdljoy); } - mprintf((" Name : %s\n", SDL_JoystickName(sdljoy))); + JoystickID = SDL_JoystickInstanceID(sdljoy); + + guid = SDL_JoystickGetGUID(sdljoy); + + SDL_zero(guid_str); + SDL_JoystickGetGUIDString(guid, guid_str, SDL_arraysize(guid_str)); + + mprintf((" Name : %s\n", joy_name ? joy_name : "")); + mprintf((" GUID : %s\n", guid_str)); + mprintf((" Controller : %s\n", SDL_IsGameController(Cur_joystick) ? "Yes" : "No")); mprintf((" Axes : %d\n", SDL_JoystickNumAxes(sdljoy))); mprintf((" Buttons : %d\n", SDL_JoystickNumButtons(sdljoy))); mprintf((" Hats : %d\n", SDL_JoystickNumHats(sdljoy))); @@ -392,123 +448,107 @@ int joy_init() mprintf(("\n")); - Joy_inited = 1; - - joy_id = SDL_JoystickInstanceID(sdljoy); - joystick.num_axes = SDL_JoystickNumAxes(sdljoy); joy_flush(); - // Fake a calibration - joy_set_cen(); - for (i = 0; i < JOY_NUM_AXES; i++) { - joystick.axis_min[i] = 0; - joystick.axis_max[i] = 65536; - joystick.axis_current[i] = joystick.axis_center[i]; + joystick.axis_min[i] = SDL_JOYSTICK_AXIS_MIN; + joystick.axis_max[i] = SDL_JOYSTICK_AXIS_MAX; + } + + if (joystick.is_controller == 1) { + // the last two axes should be triggers, so set values manually + for (i = JOY_NUM_AXES-2; i < JOY_NUM_AXES; i++) { + joystick.axis_min[i] = 0; + joystick.axis_max[i] = SDL_JOYSTICK_AXIS_MAX; + } } return num_sticks; } -void joy_reinit(int with_index) +int joy_init() { - int i, num_sticks; - const char *ptr = NULL; - int Cur_joystick; - - if ( !Joy_inited ) { - joy_init(); - return; + if (Joy_inited) { + return 0; } - // close out what we have already opened... - joy_ff_shutdown(); - - joy_id = -1; + mprintf(("Initializing Joystick...\n")); - if (SDL_JoystickGetAttached(sdljoy)) { - SDL_JoystickClose(sdljoy); + if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0) { + mprintf((" Could not initialize joystick subsystem\n\n")); + return 0; } - sdljoy = NULL; + int num_sticks = joy_init_internal(-1); - // attempt to get a new joystick to use... - mprintf(("Re-Initializing Joystick...\n")); + if (num_sticks > 0) { + Joy_inited = 1; + } - num_sticks = SDL_NumJoysticks(); + return num_sticks; +} - if (num_sticks < 1) { - mprintf((" No joysticks found\n\n")); +void joy_reinit(int with_index) +{ + if ( !Joy_inited ) { + joy_init(); return; } - if ( (with_index >= 0) && (with_index < num_sticks) ) { - Cur_joystick = with_index; - } else { - Cur_joystick = 0; + // close out what we have already opened... + joy_ff_shutdown(); - ptr = os_config_read_string("Controls", "CurrentJoystick", NULL); + if (joystick.is_controller == 1) { + SDL_GameController *sdlcon = SDL_GameControllerFromInstanceID(JoystickID); - if ( ptr && SDL_strlen(ptr) ) { - for (i = 0; i < num_sticks; i++) { - const char *jname = SDL_JoystickNameForIndex(i); - - if ( jname && !SDL_strcasecmp(ptr, jname) ) { - Cur_joystick = i; - break; - } - } + if ( SDL_GameControllerGetAttached(sdlcon) ) { + SDL_GameControllerClose(sdlcon); } - } - - sdljoy = SDL_JoystickOpen(Cur_joystick); + } else { + SDL_Joystick *sdljoy = SDL_JoystickFromInstanceID(JoystickID); - if (sdljoy == NULL) { - mprintf((" Unable to init joystick %d (%s)\n\n", Cur_joystick, SDL_JoystickNameForIndex(Cur_joystick))); - return; + if ( SDL_JoystickGetAttached(sdljoy) ) { + SDL_JoystickClose(sdljoy); + } } - mprintf((" Name : %s\n", SDL_JoystickName(sdljoy))); - mprintf((" Axes : %d\n", SDL_JoystickNumAxes(sdljoy))); - mprintf((" Buttons : %d\n", SDL_JoystickNumButtons(sdljoy))); - mprintf((" Hats : %d\n", SDL_JoystickNumHats(sdljoy))); - mprintf((" Haptic : %s\n", SDL_JoystickIsHaptic(sdljoy) ? "Yes" : "No")); - - joy_ff_init(); - - mprintf(("\n")); + JoystickID = -1; - joy_id = SDL_JoystickInstanceID(sdljoy); - - joystick.num_axes = SDL_JoystickNumAxes(sdljoy); - - joy_flush(); - - // Fake a calibration - joy_set_cen(); + // attempt to get a new joystick to use... + mprintf(("Re-Initializing Joystick...\n")); - for (i = 0; i < JOY_NUM_AXES; i++) { - joystick.axis_min[i] = 0; - joystick.axis_max[i] = 65536; - joystick.axis_current[i] = joystick.axis_center[i]; - } + joy_init_internal(with_index); } void joy_set_cen() { + SDL_GameController *sdlcon = nullptr; + SDL_Joystick *sdljoy = nullptr; + if ( !Joy_inited ) { return; } + if ( joystick_is_controller() ) { + sdlcon = SDL_GameControllerFromInstanceID(JoystickID); + } else { + sdljoy = SDL_JoystickFromInstanceID(JoystickID); + } + for (int i = 0; i < JOY_NUM_AXES; i++) { if (i < joystick.num_axes) { - joystick.axis_center[i] = SDL_JoystickGetAxis(sdljoy, i) + 32768; + if ( joystick_is_controller() ) { + joystick.axis_center[i] = SDL_GameControllerGetAxis(sdlcon, (SDL_GameControllerAxis)i); + } else { + joystick.axis_center[i] = SDL_JoystickGetAxis(sdljoy, i); + } } else { - joystick.axis_center[i] = 32768; + joystick.axis_center[i] = 0; } } + } int joystick_read_raw_axis(int num_axes, int *axis) @@ -523,7 +563,7 @@ int joystick_read_raw_axis(int num_axes, int *axis) if (i < joystick.num_axes) { axis[i] = joystick.axis_current[i]; } else { - axis[i] = 32768; + axis[i] = 0;; } } @@ -538,6 +578,6 @@ bool joy_axis_valid(int axis) void joystick_update_axis(int axis, int value) { if (axis < JOY_NUM_AXES) { - joystick.axis_current[axis] = value + 32768; + joystick.axis_current[axis] = value;; } } diff --git a/src/io/joy_ff.cpp b/src/io/joy_ff.cpp index f27da1a..7f1b64f 100644 --- a/src/io/joy_ff.cpp +++ b/src/io/joy_ff.cpp @@ -14,6 +14,7 @@ #include "joy_ff.h" #include "osapi.h" #include "timer.h" +#include "joy.h" static int Joy_ff_enabled = 0; @@ -43,15 +44,21 @@ static void joy_ff_create_effects(); //static int joy_ff_effect_playing(haptic_effect_t *eff); static void joy_ff_start_effect(haptic_effect_t *eff, const char *name); -extern SDL_Joystick *sdljoy; - int joy_ff_init() { int ff_enabled = 0; + SDL_Joystick *sdljoy = nullptr; ff_enabled = os_config_read_uint("Controls", "EnableJoystickFF", 0); + if ( joystick_is_controller() ) { + SDL_GameController *sdlcon = SDL_GameControllerFromInstanceID(joystick_get_id()); + sdljoy = SDL_GameControllerGetJoystick(sdlcon); + } else { + sdljoy = SDL_JoystickFromInstanceID(joystick_get_id()); + } + if ( !ff_enabled || !SDL_JoystickIsHaptic(sdljoy) ) { return 0; } diff --git a/src/osapi/osapi.cpp b/src/osapi/osapi.cpp index 58abf01..7634dc4 100644 --- a/src/osapi/osapi.cpp +++ b/src/osapi/osapi.cpp @@ -404,7 +404,19 @@ void os_poll() break; } + case SDL_CONTROLLERAXISMOTION: { + if (e.caxis.which == joystick_get_id()) { + joystick_update_axis(e.caxis.axis, e.caxis.value); + } + + break; + } + case SDL_JOYAXISMOTION: { + if ( joystick_is_controller() ) { + break; + } + if (e.jaxis.which == joystick_get_id()) { joystick_update_axis(e.jaxis.axis, e.jaxis.value); } @@ -412,8 +424,44 @@ void os_poll() break; } + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: { + if (e.cbutton.which == joystick_get_id()) { + // convert DPAD to HAT + switch (e.cbutton.button) { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + button = JOY_HATFORWARD; + break; + + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + button = JOY_HATBACK; + break; + + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + button = JOY_HATLEFT; + break; + + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + button = JOY_HATRIGHT; + break; + + default: + button = e.cbutton.button; + } + + state = (e.cbutton.state == SDL_PRESSED) ? 1 : 0; + joy_mark_button(button, state); + } + + break; + } + case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: { + if ( joystick_is_controller() ) { + break; + } + if (e.jbutton.which == joystick_get_id()) { state = (e.jbutton.state == SDL_PRESSED) ? 1 : 0; joy_mark_button((int)e.jbutton.button, state); @@ -423,6 +471,10 @@ void os_poll() } case SDL_JOYHATMOTION: { + if ( joystick_is_controller() ) { + break; + } + if (e.jhat.which == joystick_get_id()) { // can only handle one hat if (e.jhat.hat == 0) { -- 2.39.2