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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index fe3e279..92fbb57 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 ec1b029..6945564 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);
{