From 94d43186f2b366dd83598d863a6af6fdb68e14ee Mon Sep 17 00:00:00 2001
From: Phillip Stephens <[EMAIL REDACTED]>
Date: Tue, 22 Feb 2022 00:41:15 -0800
Subject: [PATCH] GameCubeAdapter: Add suppport for all rumble modes This adds
support for all 3 of the gamecube controller's rumble modes Rumble: 1 Stop: 0
StopHard: 2 This is useful for applications that need the full range of
support This also adds a hint to control rumble behavior, defaults 0 to
maintain compatibility
---
include/SDL_hints.h | 15 ++++++++++++
src/joystick/hidapi/SDL_hidapi_gamecube.c | 28 +++++++++++++++++++++--
2 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index fe3e2790d96..92fbb5778b2 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -625,6 +625,21 @@ extern "C" {
*/
#define SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE "SDL_JOYSTICK_HIDAPI_GAMECUBE"
+/**
+ * \brief A variable controlling whether "low_frequency_rumble" and "high_frequency_rumble" is used to implement
+ * the GameCube controller's 3 rumble modes, Stop(0), Rumble(1), and StopHard(2)
+ * this is useful for applications that need full compatibility for things like ADSR envelopes.
+ * Stop is implemented by setting "low_frequency_rumble" to "0" and "high_frequency_rumble" ">0"
+ * Rumble is both at any arbitrary value,
+ * StopHard is implemented by setting both "low_frequency_rumble" and "high_frequency_rumble" to "0"
+ *
+ * This variable can be set to the following values:
+ * "0" - Normal rumble behavior is behavior is used (default)
+ * "1" - Proper GameCube controller rumble behavior is used
+ *
+ */
+#define SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE "SDL_JOYSTICK_GAMECUBE_RUMBLE_BRAKE"
+
/**
* \brief A variable controlling whether Switch Joy-Cons should be treated the same as Switch Pro Controllers when using the HIDAPI driver.
*
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index ec1b029d5aa..694556482e8 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -53,6 +53,7 @@ typedef struct {
/* Without this variable, hid_write starts to lag a TON */
SDL_bool rumbleUpdate;
SDL_bool m_bUseButtonLabels;
+ SDL_bool useRumbleBrake;
} SDL_DriverGameCube_Context;
static SDL_bool
@@ -92,6 +93,14 @@ static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata,
ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE);
}
+static void SDLCALL SDL_JoystickGameCubeRumbleBrakeHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+ if (hint) {
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)userdata;
+ ctx->useRumbleBrake = SDL_GetStringBoolean(hint, SDL_FALSE);
+ }
+}
+
static Uint8 RemapButton(SDL_DriverGameCube_Context *ctx, Uint8 button)
{
if (!ctx->m_bUseButtonLabels) {
@@ -142,6 +151,7 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
ctx->joysticks[2] = -1;
ctx->joysticks[3] = -1;
ctx->rumble[0] = rumbleMagic;
+ ctx->useRumbleBrake = SDL_FALSE;
if (device->vendor_id != USB_VENDOR_NINTENDO) {
ctx->pc_mode = SDL_TRUE;
@@ -195,6 +205,8 @@ HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
}
}
+ SDL_AddHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE,
+ SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx);
SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
SDL_GameControllerButtonReportingHintChanged, ctx);
@@ -439,12 +451,22 @@ HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
if (joystick->instance_id == ctx->joysticks[i]) {
if (ctx->wireless[i]) {
- return SDL_SetError("Ninteno GameCube WaveBird controllers do not support rumble");
+ return SDL_SetError("Nintendo GameCube WaveBird controllers do not support rumble");
}
if (!ctx->rumbleAllowed[i]) {
return SDL_SetError("Second USB cable for WUP-028 not connected");
}
- val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
+ if (ctx->useRumbleBrake) {
+ if (low_frequency_rumble == 0 && high_frequency_rumble > 0) {
+ val = 0; /* if only low is 0 we want to do a regular stop*/
+ } else if (low_frequency_rumble == 0 && high_frequency_rumble == 0) {
+ val = 2; /* if both frequencies are 0 we want to do a hard stop */
+ } else {
+ val = 1; /* normal rumble */
+ }
+ } else {
+ val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
+ }
if (val != ctx->rumble[i + 1]) {
ctx->rumble[i + 1] = val;
ctx->rumbleUpdate = SDL_TRUE;
@@ -522,6 +544,8 @@ HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)
SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
SDL_GameControllerButtonReportingHintChanged, ctx);
+ SDL_DelHintCallback(SDL_HINT_JOYSTICK_GAMECUBE_RUMBLE_BRAKE,
+ SDL_JoystickGameCubeRumbleBrakeHintChanged, ctx);
SDL_LockMutex(device->dev_lock);
{