diff --git a/docs/README-migration.md b/docs/README-migration.md index 5095f98d88..52e4b0b93b 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -374,8 +374,6 @@ The SDL_EVENT_GAMEPAD_ADDED event now provides the joystick instance ID in the w The functions SDL_GetGamepads(), SDL_GetGamepadInstanceName(), SDL_GetGamepadInstancePath(), SDL_GetGamepadInstancePlayerIndex(), SDL_GetGamepadInstanceGUID(), SDL_GetGamepadInstanceVendor(), SDL_GetGamepadInstanceProduct(), SDL_GetGamepadInstanceProductVersion(), and SDL_GetGamepadInstanceType() have been added to directly query the list of available gamepads. -The gamepad binding structure has been removed in favor of exchanging bindings in text format. - SDL_GameControllerGetSensorDataWithTimestamp() has been removed. If you want timestamps for the sensor data, you should use the sensor_timestamp member of SDL_EVENT_GAMEPAD_SENSOR_UPDATE events. SDL_CONTROLLER_TYPE_VIRTUAL has been removed, so virtual controllers can emulate other gamepad types. If you need to know whether a controller is virtual, you can use SDL_IsJoystickVirtual(). @@ -471,8 +469,6 @@ The following functions have been renamed: The following functions have been removed: * SDL_GameControllerEventState() - replaced with SDL_SetGamepadEventsEnabled() and SDL_GamepadEventsEnabled() -* SDL_GameControllerGetBindForAxis() -* SDL_GameControllerGetBindForButton() * SDL_GameControllerMappingForDeviceIndex() - replaced with SDL_GetGamepadInstanceMapping() * SDL_GameControllerNameForIndex() - replaced with SDL_GetGamepadInstanceName() * SDL_GameControllerPathForIndex() - replaced with SDL_GetGamepadInstancePath() diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h index 484aee49fc..a804ed6504 100644 --- a/include/SDL3/SDL_gamepad.h +++ b/include/SDL3/SDL_gamepad.h @@ -125,6 +125,33 @@ typedef enum SDL_GAMEPAD_AXIS_MAX } SDL_GamepadAxis; +typedef enum +{ + SDL_GAMEPAD_BINDTYPE_NONE = 0, + SDL_GAMEPAD_BINDTYPE_BUTTON, + SDL_GAMEPAD_BINDTYPE_AXIS, + SDL_GAMEPAD_BINDTYPE_HAT +} SDL_GamepadBindingType; + +/** + * Get the SDL joystick layer binding for this gamepad button/axis mapping + */ +typedef struct SDL_GamepadBinding +{ + SDL_GamepadBindingType bindType; + union + { + int button; + int axis; + struct { + int hat; + int hat_mask; + } hat; + } value; + +} SDL_GamepadBinding; + + /** * Add support for gamepads that SDL is unaware of or change the binding of an * existing gamepad. @@ -819,6 +846,21 @@ extern DECLSPEC SDL_GamepadAxis SDLCALL SDL_GetGamepadAxisFromString(const char */ extern DECLSPEC const char* SDLCALL SDL_GetGamepadStringForAxis(SDL_GamepadAxis axis); +/** + * Get the SDL joystick layer binding for a gamepad axis mapping. + * + * \param gamepad a gamepad + * \param axis an axis enum value (one of the SDL_GamepadAxis values) + * \returns a SDL_GamepadBinding describing the bind. On failure (like the + * given Controller axis doesn't exist on the device), its + * `.bindType` will be `SDL_GAMEPAD_BINDTYPE_NONE`. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadBindForButton + */ +extern DECLSPEC SDL_GamepadBinding SDLCALL SDL_GetGamepadBindForAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis); + /** * Query whether a gamepad has a given axis. * @@ -884,6 +926,21 @@ extern DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadButtonFromString(const c */ extern DECLSPEC const char* SDLCALL SDL_GetGamepadStringForButton(SDL_GamepadButton button); +/** + * Get the SDL joystick layer binding for a gamepad button mapping. + * + * \param gamepad a gamepad + * \param button an button enum value (an SDL_GamepadButton value) + * \returns a SDL_GamepadBinding describing the bind. On failure (like the + * given Controller button doesn't exist on the device), its + * `.bindType` will be `SDL_GAMEPAD_BINDTYPE_NONE`. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadBindForAxis + */ +extern DECLSPEC SDL_GamepadBinding SDLCALL SDL_GetGamepadBindForButton(SDL_Gamepad *gamepad, SDL_GamepadButton button); + /** * Query whether a gamepad has a given button. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 60366b0500..ac044bf10d 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -172,6 +172,8 @@ SDL3_0.0.0 { SDL_GetGamepadAppleSFSymbolsNameForButton; SDL_GetGamepadAxis; SDL_GetGamepadAxisFromString; + SDL_GetGamepadBindForAxis; + SDL_GetGamepadBindForButton; SDL_GetGamepadButton; SDL_GetGamepadButtonFromString; SDL_GetGamepadFirmwareVersion; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index bd97d523d2..d5237abe22 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -196,6 +196,8 @@ #define SDL_GetGamepadAppleSFSymbolsNameForButton SDL_GetGamepadAppleSFSymbolsNameForButton_REAL #define SDL_GetGamepadAxis SDL_GetGamepadAxis_REAL #define SDL_GetGamepadAxisFromString SDL_GetGamepadAxisFromString_REAL +#define SDL_GetGamepadBindForAxis SDL_GetGamepadBindForAxis_REAL +#define SDL_GetGamepadBindForButton SDL_GetGamepadBindForButton_REAL #define SDL_GetGamepadButton SDL_GetGamepadButton_REAL #define SDL_GetGamepadButtonFromString SDL_GetGamepadButtonFromString_REAL #define SDL_GetGamepadFirmwareVersion SDL_GetGamepadFirmwareVersion_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 71eba0275e..4f2212bcf3 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -271,6 +271,8 @@ SDL_DYNAPI_PROC(const char*,SDL_GetGamepadAppleSFSymbolsNameForAxis,(SDL_Gamepad SDL_DYNAPI_PROC(const char*,SDL_GetGamepadAppleSFSymbolsNameForButton,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return) SDL_DYNAPI_PROC(Sint16,SDL_GetGamepadAxis,(SDL_Gamepad *a, SDL_GamepadAxis b),(a,b),return) SDL_DYNAPI_PROC(SDL_GamepadAxis,SDL_GetGamepadAxisFromString,(const char *a),(a),return) +SDL_DYNAPI_PROC(SDL_GamepadBinding,SDL_GetGamepadBindForAxis,(SDL_Gamepad *a, SDL_GamepadAxis b),(a,b),return) +SDL_DYNAPI_PROC(SDL_GamepadBinding,SDL_GetGamepadBindForButton,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return) SDL_DYNAPI_PROC(Uint8,SDL_GetGamepadButton,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return) SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadButtonFromString,(const char *a),(a),return) SDL_DYNAPI_PROC(Uint16,SDL_GetGamepadFirmwareVersion,(SDL_Gamepad *a),(a),return) diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 00b6e92873..2dfbcdea20 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -57,14 +57,6 @@ static SDL_bool SDL_gamepads_initialized; static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL; -typedef enum -{ - SDL_GAMEPAD_BINDTYPE_NONE = 0, - SDL_GAMEPAD_BINDTYPE_BUTTON, - SDL_GAMEPAD_BINDTYPE_AXIS, - SDL_GAMEPAD_BINDTYPE_HAT -} SDL_GamepadBindingType; - typedef struct { SDL_GamepadBindingType inputType; @@ -101,7 +93,7 @@ typedef struct } output; -} SDL_GamepadBinding; +} SDL_ExtendedGamepadBind; /* our hard coded list of mapping support */ typedef enum @@ -155,8 +147,8 @@ struct SDL_Gamepad const char *name _guarded; GamepadMapping_t *mapping _guarded; int num_bindings _guarded; - SDL_GamepadBinding *bindings _guarded; - SDL_GamepadBinding **last_match_axis _guarded; + SDL_ExtendedGamepadBind *bindings _guarded; + SDL_ExtendedGamepadBind **last_match_axis _guarded; Uint8 *last_hat_mask _guarded; Uint64 guide_button_down _guarded; @@ -192,7 +184,7 @@ static GamepadMapping_t *SDL_PrivateGetGamepadMapping(SDL_JoystickID instance_id static int SDL_SendGamepadAxis(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_GamepadAxis axis, Sint16 value); static int SDL_SendGamepadButton(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_GamepadButton button, Uint8 state); -static SDL_bool HasSameOutput(SDL_GamepadBinding *a, SDL_GamepadBinding *b) +static SDL_bool HasSameOutput(SDL_ExtendedGamepadBind *a, SDL_ExtendedGamepadBind *b) { if (a->outputType != b->outputType) { return SDL_FALSE; @@ -205,7 +197,7 @@ static SDL_bool HasSameOutput(SDL_GamepadBinding *a, SDL_GamepadBinding *b) } } -static void ResetOutput(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_GamepadBinding *bind) +static void ResetOutput(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_ExtendedGamepadBind *bind) { if (bind->outputType == SDL_GAMEPAD_BINDTYPE_AXIS) { SDL_SendGamepadAxis(timestamp, gamepad, bind->output.axis.axis, 0); @@ -217,14 +209,14 @@ static void ResetOutput(Uint64 timestamp, SDL_Gamepad *gamepad, SDL_GamepadBindi static void HandleJoystickAxis(Uint64 timestamp, SDL_Gamepad *gamepad, int axis, int value) { int i; - SDL_GamepadBinding *last_match; - SDL_GamepadBinding *match = NULL; + SDL_ExtendedGamepadBind *last_match; + SDL_ExtendedGamepadBind *match = NULL; SDL_AssertJoysticksLocked(); last_match = gamepad->last_match_axis[axis]; for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; if (binding->inputType == SDL_GAMEPAD_BINDTYPE_AXIS && axis == binding->input.axis.axis) { if (binding->input.axis.axis_min < binding->input.axis.axis_max) { @@ -276,7 +268,7 @@ static void HandleJoystickButton(Uint64 timestamp, SDL_Gamepad *gamepad, int but SDL_AssertJoysticksLocked(); for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; if (binding->inputType == SDL_GAMEPAD_BINDTYPE_BUTTON && button == binding->input.button) { if (binding->outputType == SDL_GAMEPAD_BINDTYPE_AXIS) { @@ -300,7 +292,7 @@ static void HandleJoystickHat(Uint64 timestamp, SDL_Gamepad *gamepad, int hat, U last_mask = gamepad->last_hat_mask[hat]; changed_mask = (last_mask ^ value); for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; if (binding->inputType == SDL_GAMEPAD_BINDTYPE_HAT && hat == binding->input.hat.hat) { if ((changed_mask & binding->input.hat.hat_mask) != 0) { if (value & binding->input.hat.hat_mask) { @@ -1164,7 +1156,7 @@ const char *SDL_GetGamepadStringForButton(SDL_GamepadButton button) */ static int SDL_PrivateParseGamepadElement(SDL_Gamepad *gamepad, const char *szGameButton, const char *szJoystickButton) { - SDL_GamepadBinding bind; + SDL_ExtendedGamepadBind bind; SDL_GamepadButton button; SDL_GamepadAxis axis; SDL_bool invert_input = SDL_FALSE; @@ -1244,7 +1236,7 @@ static int SDL_PrivateParseGamepadElement(SDL_Gamepad *gamepad, const char *szGa } ++gamepad->num_bindings; - gamepad->bindings = (SDL_GamepadBinding *)SDL_realloc(gamepad->bindings, gamepad->num_bindings * sizeof(*gamepad->bindings)); + gamepad->bindings = (SDL_ExtendedGamepadBind *)SDL_realloc(gamepad->bindings, gamepad->num_bindings * sizeof(*gamepad->bindings)); if (!gamepad->bindings) { gamepad->num_bindings = 0; return SDL_OutOfMemory(); @@ -1323,7 +1315,7 @@ static void SDL_PrivateLoadButtonMapping(SDL_Gamepad *gamepad, GamepadMapping_t /* Set the zero point for triggers */ for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; if (binding->inputType == SDL_GAMEPAD_BINDTYPE_AXIS && binding->outputType == SDL_GAMEPAD_BINDTYPE_AXIS && (binding->output.axis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || @@ -2486,7 +2478,7 @@ SDL_Gamepad *SDL_OpenGamepad(SDL_JoystickID instance_id) } if (gamepad->joystick->naxes) { - gamepad->last_match_axis = (SDL_GamepadBinding **)SDL_calloc(gamepad->joystick->naxes, sizeof(*gamepad->last_match_axis)); + gamepad->last_match_axis = (SDL_ExtendedGamepadBind **)SDL_calloc(gamepad->joystick->naxes, sizeof(*gamepad->last_match_axis)); if (!gamepad->last_match_axis) { SDL_OutOfMemory(); SDL_CloseJoystick(gamepad->joystick); @@ -2534,25 +2526,17 @@ void SDL_UpdateGamepads(void) */ SDL_bool SDL_GamepadHasAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis) { - SDL_bool retval = SDL_FALSE; + SDL_GamepadBinding bind; SDL_LockJoysticks(); { - int i; - CHECK_GAMEPAD_MAGIC(gamepad, SDL_FALSE); - for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; - if (binding->outputType == SDL_GAMEPAD_BINDTYPE_AXIS && binding->output.axis.axis == axis) { - retval = SDL_TRUE; - break; - } - } + bind = SDL_GetGamepadBindForAxis(gamepad, axis); } SDL_UnlockJoysticks(); - return retval; + return (bind.bindType != SDL_GAMEPAD_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE; } /* @@ -2569,7 +2553,7 @@ Sint16 SDL_GetGamepadAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis) CHECK_GAMEPAD_MAGIC(gamepad, 0); for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; if (binding->outputType == SDL_GAMEPAD_BINDTYPE_AXIS && binding->output.axis.axis == axis) { int value = 0; SDL_bool valid_input_range; @@ -2625,25 +2609,17 @@ Sint16 SDL_GetGamepadAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis) */ SDL_bool SDL_GamepadHasButton(SDL_Gamepad *gamepad, SDL_GamepadButton button) { - SDL_bool retval = SDL_FALSE; + SDL_GamepadBinding bind; SDL_LockJoysticks(); { - int i; - CHECK_GAMEPAD_MAGIC(gamepad, SDL_FALSE); - for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; - if (binding->outputType == SDL_GAMEPAD_BINDTYPE_BUTTON && binding->output.button == button) { - retval = SDL_TRUE; - break; - } - } + bind = SDL_GetGamepadBindForButton(gamepad, button); } SDL_UnlockJoysticks(); - return retval; + return (bind.bindType != SDL_GAMEPAD_BINDTYPE_NONE) ? SDL_TRUE : SDL_FALSE; } /* @@ -2660,7 +2636,7 @@ Uint8 SDL_GetGamepadButton(SDL_Gamepad *gamepad, SDL_GamepadButton button) CHECK_GAMEPAD_MAGIC(gamepad, 0); for (i = 0; i < gamepad->num_bindings; ++i) { - SDL_GamepadBinding *binding = &gamepad->bindings[i]; + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; if (binding->outputType == SDL_GAMEPAD_BINDTYPE_BUTTON && binding->output.button == button) { if (binding->inputType == SDL_GAMEPAD_BINDTYPE_AXIS) { SDL_bool valid_input_range; @@ -3180,6 +3156,81 @@ SDL_Gamepad *SDL_GetGamepadFromPlayerIndex(int player_index) return retval; } +/* + * Get the SDL joystick layer binding for this gamepad axis mapping + */ +SDL_GamepadBinding SDL_GetGamepadBindForAxis(SDL_Gamepad *gamepad, SDL_GamepadAxis axis) +{ + SDL_GamepadBinding bind; + + SDL_zero(bind); + + SDL_LockJoysticks(); + { + CHECK_GAMEPAD_MAGIC(gamepad, bind); + + if (axis != SDL_GAMEPAD_AXIS_INVALID) { + int i; + for (i = 0; i < gamepad->num_bindings; ++i) { + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; + if (binding->outputType == SDL_GAMEPAD_BINDTYPE_AXIS && binding->output.axis.axis == axis) { + bind.bindType = binding->inputType; + if (binding->inputType == SDL_GAMEPAD_BINDTYPE_AXIS) { + /* FIXME: There might be multiple axes bound now that we have axis ranges... */ + bind.value.axis = binding->input.axis.axis; + } else if (binding->inputType == SDL_GAMEPAD_BINDTYPE_BUTTON) { + bind.value.button = binding->input.button; + } else if (binding->inputType == SDL_GAMEPAD_BINDTYPE_HAT) { + bind.value.hat.hat = binding->input.hat.hat; + bind.value.hat.hat_mask = binding->input.hat.hat_mask; + } + break; + } + } + } + } + SDL_UnlockJoysticks(); + + return bind; +} + +/* + * Get the SDL joystick layer binding for this gamepad button mapping + */ +SDL_GamepadBinding SDL_GetGamepadBindForButton(SDL_Gamepad *gamepad, SDL_GamepadButton button) +{ + SDL_GamepadBinding bind; + + SDL_zero(bind); + + SDL_LockJoysticks(); + { + CHECK_GAMEPAD_MAGIC(gamepad, bind); + + if (button != SDL_GAMEPAD_BUTTON_INVALID) { + int i; + for (i = 0; i < gamepad->num_bindings; ++i) { + SDL_ExtendedGamepadBind *binding = &gamepad->bindings[i]; + if (binding->outputType == SDL_GAMEPAD_BINDTYPE_BUTTON && binding->output.button == button) { + bind.bindType = binding->inputType; + if (binding->inputType == SDL_GAMEPAD_BINDTYPE_AXIS) { + bind.value.axis = binding->input.axis.axis; + } else if (binding->inputType == SDL_GAMEPAD_BINDTYPE_BUTTON) { + bind.value.button = binding->input.button; + } else if (binding->inputType == SDL_GAMEPAD_BINDTYPE_HAT) { + bind.value.hat.hat = binding->input.hat.hat; + bind.value.hat.hat_mask = binding->input.hat.hat_mask; + } + break; + } + } + } + } + SDL_UnlockJoysticks(); + + return bind; +} + int SDL_RumbleGamepad(SDL_Gamepad *gamepad, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) { SDL_Joystick *joystick = SDL_GetGamepadJoystick(gamepad);