|
@@ -37,6 +37,7 @@
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
#define MAX_CONTROLLERS 4
|
|
#define MAX_CONTROLLERS 4
|
|
|
|
|
+#define PC_RUMBLE_REFRESH 16
|
|
|
|
|
|
|
|
typedef struct
|
|
typedef struct
|
|
|
{
|
|
{
|
|
@@ -50,6 +51,8 @@ typedef struct
|
|
|
// Without this variable, hid_write starts to lag a TON
|
|
// Without this variable, hid_write starts to lag a TON
|
|
|
bool rumbleUpdate;
|
|
bool rumbleUpdate;
|
|
|
bool useRumbleBrake;
|
|
bool useRumbleBrake;
|
|
|
|
|
+ bool rumbleActive;
|
|
|
|
|
+ Uint64 pc_rumble_sent;
|
|
|
} SDL_DriverGameCube_Context;
|
|
} SDL_DriverGameCube_Context;
|
|
|
|
|
|
|
|
static void HIDAPI_DriverGameCube_RegisterHints(SDL_HintCallback callback, void *userdata)
|
|
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) {
|
|
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
|
|
#ifdef SDL_PLATFORM_WIN32
|
|
|
// We get a separate device for each slot
|
|
// We get a separate device for each slot
|
|
|
|
|
+ ctx->rumbleAllowed[0] = rumbleAllowed;
|
|
|
ResetAxisRange(ctx, 0);
|
|
ResetAxisRange(ctx, 0);
|
|
|
HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
|
|
HIDAPI_JoystickConnected(device, &ctx->joysticks[0]);
|
|
|
#else
|
|
#else
|
|
|
for (i = 0; i < MAX_CONTROLLERS; ++i) {
|
|
for (i = 0; i < MAX_CONTROLLERS; ++i) {
|
|
|
|
|
+ ctx->rumbleAllowed[i] = rumbleAllowed;
|
|
|
ResetAxisRange(ctx, i);
|
|
ResetAxisRange(ctx, i);
|
|
|
HIDAPI_JoystickConnected(device, &ctx->joysticks[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)
|
|
static bool HIDAPI_DriverGameCube_UpdateDevice(SDL_HIDAPI_Device *device)
|
|
|
{
|
|
{
|
|
|
SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
|
|
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
|
|
// Write rumble packet
|
|
|
if (ctx->rumbleUpdate) {
|
|
if (ctx->rumbleUpdate) {
|
|
|
SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble));
|
|
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();
|
|
SDL_AssertJoysticksLocked();
|
|
|
|
|
|
|
|
if (ctx->pc_mode) {
|
|
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 {
|
|
} 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;
|
|
Uint32 result = 0;
|
|
|
|
|
|
|
|
SDL_AssertJoysticksLocked();
|
|
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) {
|
|
for (i = 0; i < MAX_CONTROLLERS; i += 1) {
|
|
|
if (joystick->instance_id == ctx->joysticks[i]) {
|
|
if (joystick->instance_id == ctx->joysticks[i]) {
|
|
|
if (!ctx->wireless[i] && ctx->rumbleAllowed[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));
|
|
SDL_HIDAPI_SendRumble(device, ctx->rumble, sizeof(ctx->rumble));
|
|
|
ctx->rumbleUpdate = false;
|
|
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)
|
|
static void HIDAPI_DriverGameCube_FreeDevice(SDL_HIDAPI_Device *device)
|