Parcourir la source

Added rumble to Gamecube Adapter PC_Mode (#15431)

(cherry picked from commit c43ab978fd69289ddd3ac40117331a0fb384b9ac)
replicacoil il y a 1 jour
Parent
commit
11cb97888b
1 fichiers modifiés avec 87 ajouts et 27 suppressions
  1. 87 27
      src/joystick/hidapi/SDL_hidapi_gamecube.c

+ 87 - 27
src/joystick/hidapi/SDL_hidapi_gamecube.c

@@ -37,6 +37,7 @@
 #endif
 
 #define MAX_CONTROLLERS 4
+#define PC_RUMBLE_REFRESH 16
 
 typedef struct
 {
@@ -50,6 +51,8 @@ typedef struct
     // Without this variable, hid_write starts to lag a TON
     bool rumbleUpdate;
     bool useRumbleBrake;
+    bool rumbleActive;
+    Uint64 pc_rumble_sent;
 } SDL_DriverGameCube_Context;
 
 static void HIDAPI_DriverGameCube_RegisterHints(SDL_HintCallback callback, void *userdata)
@@ -202,12 +205,26 @@ static bool HIDAPI_DriverGameCube_InitDevice(SDL_HIDAPI_Device *device)
     }
 
     if (ctx->pc_mode) {
+        // Check to see if this firmware supports rumble
+        bool rumbleAllowed = false;
+        if ((size = SDL_hid_read_timeout(device->dev, packet, sizeof(packet), 0)) > 0) {
+#ifdef DEBUG_GAMECUBE_PROTOCOL
+            HIDAPI_DumpPacket("Nintendo GameCube packet: size = %d", packet, size);
+#endif
+            if (size == 9) {
+                // This is firmware version 0x7 or newer
+                // Rumble is supported if the second USB cable is plugged in
+                rumbleAllowed = true;
+            }
+        }
 #ifdef SDL_PLATFORM_WIN32
         // We get a separate device for each slot
+        ctx->rumbleAllowed[0] = rumbleAllowed;
         ResetAxisRange(ctx, 0);
         HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
 #else
         for (i = 0; i < MAX_CONTROLLERS; ++i) {
+            ctx->rumbleAllowed[i] = rumbleAllowed;
             ResetAxisRange(ctx, i);
             HIDAPI_JoystickConnected(device, &ctx->joysticks[i]);
         }
@@ -427,6 +444,14 @@ static void HIDAPI_DriverGameCube_HandleNintendoPacket(SDL_HIDAPI_Device *device
     }
 }
 
+static void HIDAPI_DriverGameCube_SendPCRumble(SDL_HIDAPI_Device *device, SDL_DriverGameCube_Context *ctx)
+{
+    Uint8 rumblepkt[3] = { 0x00, 0x00, 0x00 };
+    rumblepkt[1] = rumblepkt[2] = ctx->rumbleActive ? 0xFF : 0x00;
+    SDL_HIDAPI_SendRumble(device, rumblepkt, sizeof(rumblepkt));
+    ctx->pc_rumble_sent = SDL_GetTicks();
+}
+
 static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
 {
     SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
@@ -456,6 +481,11 @@ static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
         }
     }
 
+    // PC_Mode rumble needs constant packets in order to keep rumble going
+    if (ctx->pc_mode && ctx->rumbleActive && SDL_GetTicks() >= (ctx->pc_rumble_sent + PC_RUMBLE_REFRESH)) {
+        HIDAPI_DriverGameCube_SendPCRumble(device, ctx);
+    }
+
     // Write rumble packet
     if (ctx->rumbleUpdate) {
         SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble));
@@ -496,33 +526,51 @@ static bool HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_
     SDL_AssertJoysticksLocked();
 
     if (ctx->pc_mode) {
-        return SDL_Unsupported();
-    }
-
-    for (i = 0; i < MAX_CONTROLLERS; i += 1) {
-        if (joystick->instance_id == ctx->joysticks[i]) {
-            if (ctx->wireless[i]) {
-                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");
+        for (i = 0; i < MAX_CONTROLLERS; i += 1) {
+            if (joystick->instance_id == ctx->joysticks[i]) {
+                if (!ctx->rumbleAllowed[i]) {
+                    return SDL_SetError("Rumble is disabled because the adapter is not at least of firmware 0x7");
+                }
+                bool shouldrumble = false, coast = false;
+                if (ctx->useRumbleBrake) {
+                    coast = (low_frequency_rumble == 0 && high_frequency_rumble > 0);
+                }
+                shouldrumble = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
+                if (coast) {
+                    ctx->rumbleActive = false;
+                } else if (shouldrumble != ctx->rumbleActive) {
+                    ctx->rumbleActive = shouldrumble;
+                    HIDAPI_DriverGameCube_SendPCRumble(device, ctx);
+                }
+                return true;
             }
-            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 {
+        for (i = 0; i < MAX_CONTROLLERS; i += 1) {
+            if (joystick->instance_id == ctx->joysticks[i]) {
+                if (ctx->wireless[i]) {
+                    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");
+                }
+                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 = 1; // normal rumble
+                    val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
                 }
-            } else {
-                val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
-            }
-            if (val != ctx->rumble[i + 1]) {
-                ctx->rumble[i + 1] = val;
-                ctx->rumbleUpdate = true;
+                if (val != ctx->rumble[i + 1]) {
+                    ctx->rumble[i + 1] = val;
+                    ctx->rumbleUpdate = true;
+                }
+                return true;
             }
-            return true;
         }
     }
 
@@ -541,10 +589,17 @@ static Uint32 HIDAPI_DriverGameCube_GetJoystickCapabilities(SDL_HIDAPI_Device *d
     Uint32 result = 0;
 
     SDL_AssertJoysticksLocked();
-
-    if (!ctx->pc_mode) {
-        Uint8 i;
-
+    Uint8 i;
+    if (ctx->pc_mode) {
+        for (i = 0; i < MAX_CONTROLLERS; i += 1) {
+            if (joystick->instance_id == ctx->joysticks[i]) {
+                if (ctx->rumbleAllowed[i]) {
+                    result |= SDL_JOYSTICK_CAP_RUMBLE;
+                    break;
+                }
+            }
+        }
+    } else {
         for (i = 0; i < MAX_CONTROLLERS; i += 1) {
             if (joystick->instance_id == ctx->joysticks[i]) {
                 if (!ctx->wireless[i] && ctx->rumbleAllowed[i]) {
@@ -582,6 +637,11 @@ static void HIDAPI_DriverGameCube_CloseJoystick(SDL_HIDAPI_Device *device, SDL_J
         SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble));
         ctx->rumbleUpdate = false;
     }
+
+    if (ctx->pc_mode && ctx->rumbleActive) {
+        ctx->rumbleActive = false;
+        HIDAPI_DriverGameCube_SendPCRumble(device, ctx);
+    }
 }
 
 static void HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)