hidapi: Add support for Wii U/Switch USB GameCube controller adapter.
Note that a single USB device is responsible for all 4 joysticks, so a large
rewrite of the DeviceDriver functions was necessary to allow a single device to
produce multiple joysticks.
diff --git a/include/SDL_hints.h b/include/SDL_hints.h
index cd5adb2..ac605db 100644
--- a/include/SDL_hints.h
+++ b/include/SDL_hints.h
@@ -556,6 +556,17 @@
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX "SDL_JOYSTICK_HIDAPI_XBOX"
/**
+ * \brief A variable controlling whether the HIDAPI driver for Nintendo GameCube controllers should be used.
+ *
+ * This variable can be set to the following values:
+ * "0" - HIDAPI driver is not used
+ * "1" - HIDAPI driver is used
+ *
+ * The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE "SDL_JOYSTICK_HIDAPI_GAMECUBE"
+
+/**
* \brief A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
*
* The variable can be set to the following values:
diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index 7478b9e..77fe52e 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -564,6 +564,7 @@
"03000000b50700001503000010010000,impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,",
"030000009b2800000300000001010000,raphnet.net 4nes4snes v1.5,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,",
"03000000d80400008200000003000000,IMS PCU#0 Gamepad Interface,platform:Linux,a:b1,b:b0,x:b3,y:b2,back:b4,start:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,",
+ "030000007e0500003703000000016800,Nintendo GameCube Controller,platform:Linux,a:b0,b:b2,x:b1,y:b3,start:b8,rightshoulder:b9,dpup:b7,dpdown:b6,dpleft:b4,dpright:b5,leftx:a0,lefty:a1~,rightx:a2,righty:a3~,lefttrigger:a4,righttrigger:a5,",
#endif
#if defined(__ANDROID__)
"05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,",
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index a0d5b7b..a5b3e63 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -1033,6 +1033,11 @@
/* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
SDL_UnlockJoysticks();
+ /* Special function for HIDAPI devices, as a single device can provide multiple SDL_Joysticks */
+#ifdef SDL_JOYSTICK_HIDAPI
+ SDL_HIDAPI_UpdateDevices();
+#endif /* SDL_JOYSTICK_HIDAPI */
+
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
if (joystick->attached) {
joystick->driver->Update(joystick);
@@ -1188,6 +1193,12 @@
}
SDL_bool
+SDL_IsJoystickGameCube(Uint16 vendor, Uint16 product)
+{
+ return (GuessControllerType(vendor, product) == k_eControllerType_GameCube);
+}
+
+SDL_bool
SDL_IsJoystickXInput(SDL_JoystickGUID guid)
{
return (guid.data[14] == 'x') ? SDL_TRUE : SDL_FALSE;
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index 165c370..f02d30b 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -66,6 +66,9 @@
/* Function to return whether a joystick is an Xbox One controller */
extern SDL_bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id);
+/* Function to return whether a joystick is a GameCube controller */
+extern SDL_bool SDL_IsJoystickGameCube(Uint16 vendor_id, Uint16 product_id);
+
/* Function to return whether a joystick guid comes from the XInput driver */
extern SDL_bool SDL_IsJoystickXInput(SDL_JoystickGUID guid);
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 8f57523..ef7f082 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -152,6 +152,9 @@
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
extern SDL_JoystickDriver SDL_WINDOWS_JoystickDriver;
+/* Special function to update HIDAPI devices */
+extern void SDL_HIDAPI_UpdateDevices(void);
+
#endif /* SDL_sysjoystick_h_ */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/controller_type.h b/src/joystick/controller_type.h
index 51ac20b..22dec71 100644
--- a/src/joystick/controller_type.h
+++ b/src/joystick/controller_type.h
@@ -57,6 +57,7 @@
k_eControllerType_SwitchJoyConPair = 41,
k_eControllerType_SwitchInputOnlyController = 42,
k_eControllerType_MobileTouch = 43,
+ k_eControllerType_GameCube = 44,
k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value
// Keyboards and Mice
@@ -387,6 +388,8 @@
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController }, // PowerA Wired Controller Plus
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0092 ), k_eControllerType_SwitchInputOnlyController }, // HORI Pokken Tournament DX Pro Pad
+ { MAKE_CONTROLLER_ID( 0x057e, 0x0337 ), k_eControllerType_GameCube }, // Nintendo Wii U/Switch GameCube USB Adapter
+
// Valve products - don't add to public list
{ MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch }, // Streaming mobile touch virtual controls
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
new file mode 100644
index 0000000..d08fff2
--- /dev/null
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -0,0 +1,339 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifdef SDL_JOYSTICK_HIDAPI
+
+#include "SDL_hints.h"
+#include "SDL_log.h"
+#include "SDL_events.h"
+#include "SDL_timer.h"
+#include "SDL_haptic.h"
+#include "SDL_joystick.h"
+#include "SDL_gamecontroller.h"
+#include "../SDL_sysjoystick.h"
+#include "SDL_hidapijoystick_c.h"
+
+
+#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
+
+typedef struct {
+ SDL_JoystickID joysticks[4];
+ Uint8 rumble[5];
+ Uint32 rumbleExpiration[4];
+ /* Without this variable, hid_write starts to lag a TON */
+ Uint8 rumbleUpdate;
+} SDL_DriverGameCube_Context;
+
+static SDL_bool
+HIDAPI_DriverGameCube_IsSupportedDevice(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number)
+{
+ return SDL_IsJoystickGameCube(vendor_id, product_id);
+}
+
+static const char *
+HIDAPI_DriverGameCube_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
+{
+ /* Give a user friendly name for this controller */
+ if (SDL_IsJoystickGameCube(vendor_id, product_id)) {
+ return "Nintendo GameCube Controller";
+ }
+ return NULL;
+}
+
+static SDL_bool
+HIDAPI_DriverGameCube_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
+{
+ SDL_DriverGameCube_Context *ctx;
+ Uint8 packet[37];
+ Uint8 *curSlot;
+ Uint8 i;
+ int size;
+ Uint8 initMagic = 0x13;
+ Uint8 rumbleMagic = 0x11;
+
+ ctx = (SDL_DriverGameCube_Context *)SDL_calloc(1, sizeof(*ctx));
+ if (!ctx) {
+ SDL_OutOfMemory();
+ return SDL_FALSE;
+ }
+ ctx->joysticks[0] = -1;
+ ctx->joysticks[1] = -1;
+ ctx->joysticks[2] = -1;
+ ctx->joysticks[3] = -1;
+ ctx->rumble[0] = rumbleMagic;
+
+ context->context = ctx;
+
+ /* This is all that's needed to initialize the device. Really! */
+ if (hid_write(context->device, &initMagic, sizeof(initMagic)) <= 0) {
+ SDL_SetError("Couldn't initialize WUP-028");
+ SDL_free(ctx);
+ return SDL_FALSE;
+ }
+
+ /* Add all the applicable joysticks */
+ while ((size = hid_read_timeout(context->device, packet, sizeof(packet), 0)) > 0) {
+ if (size < 37 || packet[0] != 0x21) {
+ continue; /* Nothing to do yet...? */
+ }
+
+ /* Go through all 4 slots */
+ curSlot = packet + 1;
+ for (i = 0; i < 4; i += 1, curSlot += 9) {
+ if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
+ if (ctx->joysticks[i] == -1) {
+ ctx->joysticks[i] = SDL_GetNextJoystickInstanceID();
+
+ *num_joysticks += 1;
+
+ SDL_PrivateJoystickAdded(ctx->joysticks[i]);
+ }
+ } else {
+ if (ctx->joysticks[i] != -1) {
+ SDL_PrivateJoystickRemoved(ctx->joysticks[i]);
+
+ *num_joysticks -= 1;
+
+ ctx->joysticks[i] = -1;
+ }
+ continue;
+ }
+ }
+ }
+
+ return SDL_TRUE;
+}
+
+static void
+HIDAPI_DriverGameCube_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
+{
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
+ Uint8 i;
+
+ /* Stop all rumble activity */
+ for (i = 1; i < 5; i += 1) {
+ ctx->rumble[i] = 0;
+ }
+ hid_write(context->device, ctx->rumble, sizeof(ctx->rumble));
+
+ /* Remove all joysticks! */
+ for (i = 0; i < 4; i += 1) {
+ if (ctx->joysticks[i] != -1) {
+ *num_joysticks -= 1;
+ if (send_event) {
+ SDL_PrivateJoystickRemoved(ctx->joysticks[i]);
+ }
+ }
+ }
+
+ SDL_free(context->context);
+}
+
+static SDL_bool
+HIDAPI_DriverGameCube_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
+{
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
+ SDL_Joystick *joystick;
+ Uint8 packet[37];
+ Uint8 *curSlot;
+ Uint32 now;
+ Uint8 i;
+ int size;
+
+ /* Read input packet */
+ while ((size = hid_read_timeout(context->device, packet, sizeof(packet), 0)) > 0) {
+ if (size < 37 || packet[0] != 0x21) {
+ continue; /* Nothing to do right now...? */
+ }
+
+ /* Go through all 4 slots */
+ curSlot = packet + 1;
+ for (i = 0; i < 4; i += 1, curSlot += 9) {
+ if (curSlot[0] & 0x30) { /* 0x10 - Wired, 0x20 - Wireless */
+ if (ctx->joysticks[i] == -1) {
+ ctx->joysticks[i] = SDL_GetNextJoystickInstanceID();
+
+ *num_joysticks += 1;
+
+ SDL_PrivateJoystickAdded(ctx->joysticks[i]);
+ }
+ joystick = SDL_JoystickFromInstanceID(ctx->joysticks[i]);
+
+ /* Hasn't been opened yet, skip */
+ if (joystick == NULL) {
+ continue;
+ }
+ } else {
+ if (ctx->joysticks[i] != -1) {
+ SDL_PrivateJoystickRemoved(ctx->joysticks[i]);
+
+ *num_joysticks -= 1;
+
+ ctx->joysticks[i] = -1;
+ }
+ continue;
+ }
+
+ #define READ_BUTTON(off, flag, button) \
+ SDL_PrivateJoystickButton( \
+ joystick, \
+ button, \
+ (curSlot[off] & flag) ? SDL_PRESSED : SDL_RELEASED \
+ );
+ READ_BUTTON(1, 0x01, 0) /* A */
+ READ_BUTTON(1, 0x02, 1) /* B */
+ READ_BUTTON(1, 0x04, 2) /* X */
+ READ_BUTTON(1, 0x08, 3) /* Y */
+ READ_BUTTON(1, 0x10, 4) /* DPAD_LEFT */
+ READ_BUTTON(1, 0x20, 5) /* DPAD_RIGHT */
+ READ_BUTTON(1, 0x40, 6) /* DPAD_DOWN */
+ READ_BUTTON(1, 0x80, 7) /* DPAD_UP */
+ READ_BUTTON(2, 0x01, 8) /* START */
+ READ_BUTTON(2, 0x02, 9) /* RIGHTSHOULDER */
+ /* [2] 0x04 - R, [2] 0x08 - L */
+ #undef READ_BUTTON
+
+ /* Axis math taken from SDL_xinputjoystick.c */
+ #define READ_AXIS(off, axis) \
+ SDL_PrivateJoystickAxis( \
+ joystick, \
+ axis, \
+ (Sint16)(((int)curSlot[off] * 257) - 32768) \
+ );
+ READ_AXIS(3, 0) /* LEFTX */
+ READ_AXIS(4, 1) /* LEFTY */
+ READ_AXIS(5, 2) /* RIGHTX */
+ READ_AXIS(6, 3) /* RIGHTY */
+ READ_AXIS(7, 4) /* TRIGGERLEFT */
+ READ_AXIS(8, 5) /* TRIGGERRIGHT */
+ #undef READ_AXIS
+ }
+ }
+
+ /* Write rumble packet */
+ now = SDL_GetTicks();
+ for (i = 0; i < 4; i += 1) {
+ if (ctx->rumbleExpiration[i] > 0) {
+ if (SDL_TICKS_PASSED(now, ctx->rumbleExpiration[i])) {
+ ctx->rumble[i + 1] = 0;
+ ctx->rumbleExpiration[i] = 0;
+ ctx->rumbleUpdate = 1;
+ }
+ }
+ }
+ if (ctx->rumbleUpdate) {
+ hid_write(context->device, ctx->rumble, sizeof(ctx->rumble));
+ ctx->rumbleUpdate = 0;
+ }
+
+ /* If we got here, nothing bad happened! */
+ return SDL_TRUE;
+}
+
+static int
+HIDAPI_DriverGameCube_NumJoysticks(SDL_HIDAPI_DriverData *context)
+{
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
+ int i, joysticks = 0;
+ for (i = 0; i < 4; i += 1) {
+ if (ctx->joysticks[i] != -1) {
+ joysticks += 1;
+ }
+ }
+ return joysticks;
+}
+
+static SDL_JoystickID
+HIDAPI_DriverGameCube_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
+{
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
+ Uint8 i;
+ for (i = 0; i < 4; i += 1) {
+ if (ctx->joysticks[i] != -1) {
+ if (index == 0) {
+ return ctx->joysticks[i];
+ }
+ index -= 1;
+ }
+ }
+ return -1; /* Should never get here! */
+}
+
+static SDL_bool
+HIDAPI_DriverGameCube_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
+{
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
+ SDL_JoystickID instance = SDL_JoystickInstanceID(joystick);
+ Uint8 i;
+ for (i = 0; i < 4; i += 1) {
+ if (instance == ctx->joysticks[i]) {
+ joystick->nbuttons = 10;
+ joystick->naxes = 6;
+ joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
+ return SDL_TRUE;
+ }
+ }
+ return SDL_FALSE; /* Should never get here! */
+}
+
+static int
+HIDAPI_DriverGameCube_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+{
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)context->context;
+ SDL_JoystickID instance = SDL_JoystickInstanceID(joystick);
+ Uint8 i, val;
+ for (i = 0; i < 4; i += 1) {
+ if (instance == ctx->joysticks[i]) {
+ val = (low_frequency_rumble > 0 || high_frequency_rumble > 0);
+ if (val != ctx->rumble[i + 1]) {
+ ctx->rumble[i + 1] = val;
+ ctx->rumbleUpdate = 1;
+ }
+ if (val && duration_ms < SDL_HAPTIC_INFINITY) {
+ ctx->rumbleExpiration[i] = SDL_GetTicks() + duration_ms;
+ } else {
+ ctx->rumbleExpiration[i] = 0;
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+
+SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
+{
+ SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE,
+ SDL_TRUE,
+ HIDAPI_DriverGameCube_IsSupportedDevice,
+ HIDAPI_DriverGameCube_GetDeviceName,
+ HIDAPI_DriverGameCube_InitDriver,
+ HIDAPI_DriverGameCube_QuitDriver,
+ HIDAPI_DriverGameCube_UpdateDriver,
+ HIDAPI_DriverGameCube_NumJoysticks,
+ HIDAPI_DriverGameCube_InstanceIDForIndex,
+ HIDAPI_DriverGameCube_OpenJoystick,
+ HIDAPI_DriverGameCube_Rumble
+};
+
+#endif /* SDL_JOYSTICK_HIDAPI_GAMECUBE */
+
+#endif /* SDL_JOYSTICK_HIDAPI */
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index 9d160f9..e673200 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -108,6 +108,7 @@
} DS4EffectsState_t;
typedef struct {
+ SDL_JoystickID joystickID;
SDL_bool is_dongle;
SDL_bool is_bluetooth;
SDL_bool audio_supported;
@@ -272,10 +273,8 @@
return SDL_TRUE;
}
-static int HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
-
static SDL_bool
-HIDAPI_DriverPS4_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
+HIDAPI_DriverPS4_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
{
SDL_DriverPS4_Context *ctx;
@@ -284,14 +283,14 @@
SDL_OutOfMemory();
return SDL_FALSE;
}
- *context = ctx;
+ context->context = ctx;
/* Check for type of connection */
ctx->is_dongle = (vendor_id == SONY_USB_VID && product_id == SONY_DS4_DONGLE_PID);
if (ctx->is_dongle) {
ctx->is_bluetooth = SDL_FALSE;
} else if (vendor_id == SONY_USB_VID) {
- ctx->is_bluetooth = !CheckUSBConnected(dev);
+ ctx->is_bluetooth = !CheckUSBConnected(context->device);
} else {
/* Third party controllers appear to all be wired */
ctx->is_bluetooth = SDL_FALSE;
@@ -314,8 +313,45 @@
}
}
+ ctx->joystickID = SDL_GetNextJoystickInstanceID();
+ *num_joysticks += 1;
+ SDL_PrivateJoystickAdded(ctx->joystickID);
+
+ return SDL_TRUE;
+}
+
+static void
+HIDAPI_DriverPS4_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
+{
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
+
+ *num_joysticks -= 1;
+ if (send_event) {
+ SDL_PrivateJoystickRemoved(ctx->joystickID);
+ }
+ SDL_free(context->context);
+}
+
+static int
+HIDAPI_DriverPS4_NumJoysticks(SDL_HIDAPI_DriverData *context)
+{
+ return 1;
+}
+
+static SDL_JoystickID
+HIDAPI_DriverPS4_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
+{
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
+ return ctx->joystickID;
+}
+
+static int HIDAPI_DriverPS4_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
+
+static SDL_bool
+HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
+{
/* Initialize LED and effect state */
- HIDAPI_DriverPS4_Rumble(joystick, dev, ctx, 0, 0, 0);
+ HIDAPI_DriverPS4_Rumble(context, joystick, 0, 0, 0);
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
@@ -326,9 +362,9 @@
}
static int
-HIDAPI_DriverPS4_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+HIDAPI_DriverPS4_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
{
- SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
DS4EffectsState_t *effects;
Uint8 data[78];
int report_size, offset;
@@ -386,7 +422,7 @@
SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
}
- if (hid_write(dev, data, report_size) != report_size) {
+ if (hid_write(context->device, data, report_size) != report_size) {
return SDL_SetError("Couldn't send rumble packet");
}
@@ -508,20 +544,25 @@
}
static SDL_bool
-HIDAPI_DriverPS4_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
+HIDAPI_DriverPS4_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
{
- SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context;
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)context->context;
+ SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
Uint8 data[USB_PACKET_LENGTH];
int size;
- while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
+ if (joystick == NULL) {
+ return SDL_TRUE; /* Nothing to do right now! */
+ }
+
+ while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
switch (data[0]) {
case k_EPS4ReportIdUsbState:
- HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[1]);
+ HIDAPI_DriverPS4_HandleStatePacket(joystick, context->device, ctx, (PS4StatePacket_t *)&data[1]);
break;
case k_EPS4ReportIdBluetoothState:
/* Bluetooth state packets have two additional bytes at the beginning */
- HIDAPI_DriverPS4_HandleStatePacket(joystick, dev, ctx, (PS4StatePacket_t *)&data[3]);
+ HIDAPI_DriverPS4_HandleStatePacket(joystick, context->device, ctx, (PS4StatePacket_t *)&data[3]);
break;
default:
#ifdef DEBUG_JOYSTICK
@@ -534,29 +575,26 @@
if (ctx->rumble_expiration) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
- HIDAPI_DriverPS4_Rumble(joystick, dev, context, 0, 0, 0);
+ HIDAPI_DriverPS4_Rumble(context, joystick, 0, 0, 0);
}
}
return (size >= 0);
}
-static void
-HIDAPI_DriverPS4_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
-{
- SDL_free(context);
-}
-
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
{
SDL_HINT_JOYSTICK_HIDAPI_PS4,
SDL_TRUE,
HIDAPI_DriverPS4_IsSupportedDevice,
HIDAPI_DriverPS4_GetDeviceName,
- HIDAPI_DriverPS4_Init,
- HIDAPI_DriverPS4_Rumble,
- HIDAPI_DriverPS4_Update,
- HIDAPI_DriverPS4_Quit
+ HIDAPI_DriverPS4_InitDriver,
+ HIDAPI_DriverPS4_QuitDriver,
+ HIDAPI_DriverPS4_UpdateDriver,
+ HIDAPI_DriverPS4_NumJoysticks,
+ HIDAPI_DriverPS4_InstanceIDForIndex,
+ HIDAPI_DriverPS4_OpenJoystick,
+ HIDAPI_DriverPS4_Rumble
};
#endif /* SDL_JOYSTICK_HIDAPI_PS4 */
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index 27c988c..b81112b 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -183,6 +183,7 @@
#pragma pack()
typedef struct {
+ SDL_JoystickID joystickID;
hid_device *dev;
SDL_bool m_bIsUsingBluetooth;
Uint8 m_nCommandNumber;
@@ -570,7 +571,7 @@
}
static SDL_bool
-HIDAPI_DriverSwitch_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
+HIDAPI_DriverSwitch_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
{
SDL_DriverSwitch_Context *ctx;
Uint8 input_mode;
@@ -580,9 +581,9 @@
SDL_OutOfMemory();
return SDL_FALSE;
}
- ctx->dev = dev;
+ ctx->dev = context->device;
- *context = ctx;
+ context->context = ctx;
/* Initialize rumble data */
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
@@ -627,6 +628,18 @@
}
}
+ ctx->joystickID = SDL_GetNextJoystickInstanceID();
+ *num_joysticks += 1;
+ SDL_PrivateJoystickAdded(ctx->joystickID);
+
+ return SDL_TRUE;
+}
+
+static SDL_bool
+HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
+{
+ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
+
/* Set the LED state */
SetHomeLED(ctx, 100);
SetSlotLED(ctx, (joystick->instance_id % 4));
@@ -640,9 +653,9 @@
}
static int
-HIDAPI_DriverSwitch_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+HIDAPI_DriverSwitch_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
{
- SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
+ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
/* Experimentally determined rumble values. These will only matter on some controllers as tested ones
* seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble
@@ -847,11 +860,16 @@
}
static SDL_bool
-HIDAPI_DriverSwitch_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
+HIDAPI_DriverSwitch_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
{
- SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
+ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
+ SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
int size;
+ if (joystick == NULL) {
+ return SDL_TRUE; /* Nothing to do right now! */
+ }
+
while ((size = ReadInput(ctx)) > 0) {
switch (ctx->m_rgucReadBuffer[0]) {
case k_eSwitchInputReportIDs_SimpleControllerState:
@@ -868,7 +886,7 @@
if (ctx->m_nRumbleExpiration) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->m_nRumbleExpiration)) {
- HIDAPI_DriverSwitch_Rumble(joystick, dev, context, 0, 0, 0);
+ HIDAPI_DriverSwitch_Rumble(context, joystick, 0, 0, 0);
}
}
@@ -876,14 +894,31 @@
}
static void
-HIDAPI_DriverSwitch_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
+HIDAPI_DriverSwitch_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
{
- SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
+ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
/* Restore simple input mode for other applications */
SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
- SDL_free(context);
+ *num_joysticks -= 1;
+ if (send_event) {
+ SDL_PrivateJoystickRemoved(ctx->joystickID);
+ }
+ SDL_free(context->context);
+}
+
+static int
+HIDAPI_DriverSwitch_NumJoysticks(SDL_HIDAPI_DriverData *context)
+{
+ return 1;
+}
+
+static SDL_JoystickID
+HIDAPI_DriverSwitch_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
+{
+ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context->context;
+ return ctx->joystickID;
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
@@ -892,10 +927,13 @@
SDL_TRUE,
HIDAPI_DriverSwitch_IsSupportedDevice,
HIDAPI_DriverSwitch_GetDeviceName,
- HIDAPI_DriverSwitch_Init,
- HIDAPI_DriverSwitch_Rumble,
- HIDAPI_DriverSwitch_Update,
- HIDAPI_DriverSwitch_Quit
+ HIDAPI_DriverSwitch_InitDriver,
+ HIDAPI_DriverSwitch_QuitDriver,
+ HIDAPI_DriverSwitch_UpdateDriver,
+ HIDAPI_DriverSwitch_NumJoysticks,
+ HIDAPI_DriverSwitch_InstanceIDForIndex,
+ HIDAPI_DriverSwitch_OpenJoystick,
+ HIDAPI_DriverSwitch_Rumble
};
#endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c
index ab1ee9e..ad0a192 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c
@@ -54,6 +54,7 @@
typedef struct {
+ SDL_JoystickID joystickID;
Uint8 last_state[USB_PACKET_LENGTH];
Uint32 rumble_expiration;
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
@@ -277,7 +278,7 @@
}
static SDL_bool
-HIDAPI_DriverXbox360_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
+HIDAPI_DriverXbox360_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
{
SDL_DriverXbox360_Context *ctx;
@@ -296,10 +297,20 @@
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
#endif
- *context = ctx;
+ context->context = ctx;
+ ctx->joystickID = SDL_GetNextJoystickInstanceID();
+ *num_joysticks += 1;
+ SDL_PrivateJoystickAdded(ctx->joystickID);
+
+ return SDL_TRUE;
+}
+
+static SDL_bool
+HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
+{
/* Set the controller LED */
- SetSlotLED(dev, (joystick->instance_id % 4));
+ SetSlotLED(context->device, (joystick->instance_id % 4));
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
@@ -310,9 +321,22 @@
}
static int
-HIDAPI_DriverXbox360_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+HIDAPI_DriverXbox360_NumJoysticks(SDL_HIDAPI_DriverData *context)
{
- SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
+ return 1;
+}
+
+static SDL_JoystickID
+HIDAPI_DriverXbox360_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
+{
+ SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
+ return ctx->joystickID;
+}
+
+static int
+HIDAPI_DriverXbox360_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+{
+ SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
#ifdef __WIN32__
SDL_bool rumbled = SDL_FALSE;
@@ -365,7 +389,7 @@
rumble_packet[4] = (high_frequency_rumble >> 8);
#endif
- if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
+ if (hid_write(context->device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
#endif /* __WIN32__ */
@@ -705,26 +729,31 @@
#endif /* __MACOSX__ */
static SDL_bool
-HIDAPI_DriverXbox360_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
+HIDAPI_DriverXbox360_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
{
- SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
+ SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
+ SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
Uint8 data[USB_PACKET_LENGTH];
int size;
- while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
+ if (joystick == NULL) {
+ return SDL_TRUE; /* Nothing to do right now! */
+ }
+
+ while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
#ifdef __WIN32__
- HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
+ HIDAPI_DriverXbox360_HandleStatePacket(joystick, context->device, ctx, data, size);
#else
switch (data[0]) {
case 0x00:
- HIDAPI_DriverXbox360_HandleStatePacket(joystick, dev, ctx, data, size);
+ HIDAPI_DriverXbox360_HandleStatePacket(joystick, context->device, ctx, data, size);
break;
#ifdef __MACOSX__
case 0x01:
- HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, dev, ctx, data, size);
+ HIDAPI_DriverXboxOneS_HandleStatePacket(joystick, context->device, ctx, data, size);
break;
case 0x02:
- HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, dev, ctx, data, size);
+ HIDAPI_DriverXboxOneS_HandleGuidePacket(joystick, context->device, ctx, data, size);
break;
#endif
default:
@@ -742,7 +771,7 @@
if (ctx->rumble_expiration) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
- HIDAPI_DriverXbox360_Rumble(joystick, dev, context, 0, 0, 0);
+ HIDAPI_DriverXbox360_Rumble(context, joystick, 0, 0, 0);
}
}
@@ -750,11 +779,9 @@
}
static void
-HIDAPI_DriverXbox360_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
+HIDAPI_DriverXbox360_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
{
-#if defined(SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT) || defined(SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT)
- SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context;
-#endif
+ SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)context->context;
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_XINPUT
if (ctx->xinput_enabled) {
@@ -765,7 +792,11 @@
#ifdef SDL_JOYSTICK_HIDAPI_WINDOWS_GAMING_INPUT
HIDAPI_DriverXbox360_InitWindowsGamingInput(ctx);
#endif
- SDL_free(context);
+ *num_joysticks -= 1;
+ if (send_event) {
+ SDL_PrivateJoystickRemoved(ctx->joystickID);
+ }
+ SDL_free(context->context);
}
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
@@ -774,10 +805,13 @@
SDL_TRUE,
HIDAPI_DriverXbox360_IsSupportedDevice,
HIDAPI_DriverXbox360_GetDeviceName,
- HIDAPI_DriverXbox360_Init,
- HIDAPI_DriverXbox360_Rumble,
- HIDAPI_DriverXbox360_Update,
- HIDAPI_DriverXbox360_Quit
+ HIDAPI_DriverXbox360_InitDriver,
+ HIDAPI_DriverXbox360_QuitDriver,
+ HIDAPI_DriverXbox360_UpdateDriver,
+ HIDAPI_DriverXbox360_NumJoysticks,
+ HIDAPI_DriverXbox360_InstanceIDForIndex,
+ HIDAPI_DriverXbox360_OpenJoystick,
+ HIDAPI_DriverXbox360_Rumble
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOX360 */
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index fde74bb..90c2aa3 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -124,6 +124,7 @@
};
typedef struct {
+ SDL_JoystickID joystickID;
Uint8 sequence;
Uint8 last_state[USB_PACKET_LENGTH];
Uint32 rumble_expiration;
@@ -143,7 +144,7 @@
}
static SDL_bool
-HIDAPI_DriverXboxOne_Init(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context)
+HIDAPI_DriverXboxOne_InitDriver(SDL_HIDAPI_DriverData *context, Uint16 vendor_id, Uint16 product_id, int *num_joysticks)
{
SDL_DriverXboxOne_Context *ctx;
int i;
@@ -154,7 +155,7 @@
SDL_OutOfMemory();
return SDL_FALSE;
}
- *context = ctx;
+ context->context = ctx;
/* Send the controller init data */
for (i = 0; i < SDL_arraysize(xboxone_init_packets); ++i) {
@@ -162,7 +163,7 @@
if (!packet->vendor_id || (vendor_id == packet->vendor_id && product_id == packet->product_id)) {
SDL_memcpy(init_packet, packet->data, packet->size);
init_packet[2] = ctx->sequence++;
- if (hid_write(dev, init_packet, packet->size) != packet->size) {
+ if (hid_write(context->device, init_packet, packet->size) != packet->size) {
SDL_SetError("Couldn't write Xbox One initialization packet");
SDL_free(ctx);
return SDL_FALSE;
@@ -170,6 +171,16 @@
}
}
+ ctx->joystickID = SDL_GetNextJoystickInstanceID();
+ *num_joysticks += 1;
+ SDL_PrivateJoystickAdded(ctx->joystickID);
+
+ return SDL_TRUE;
+}
+
+static SDL_bool
+HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick)
+{
/* Initialize the joystick capabilities */
joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
@@ -178,10 +189,35 @@
return SDL_TRUE;
}
-static int
-HIDAPI_DriverXboxOne_Rumble(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+static void
+HIDAPI_DriverXboxOne_QuitDriver(SDL_HIDAPI_DriverData *context, SDL_bool send_event, int *num_joysticks)
{
- SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
+ SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
+
+ *num_joysticks -= 1;
+ if (send_event) {
+ SDL_PrivateJoystickRemoved(ctx->joystickID);
+ }
+ SDL_free(context->context);
+}
+
+static int
+HIDAPI_DriverXboxOne_NumJoysticks(SDL_HIDAPI_DriverData *context)
+{
+ return 1;
+}
+
+static SDL_JoystickID
+HIDAPI_DriverXboxOne_InstanceIDForIndex(SDL_HIDAPI_DriverData *context, int index)
+{
+ SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
+ return ctx->joystickID;
+}
+
+static int
+HIDAPI_DriverXboxOne_Rumble(SDL_HIDAPI_DriverData *context, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+{
+ SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
Uint8 rumble_packet[] = { 0x09, 0x00, 0x00, 0x09, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF };
/* The Rock Candy Xbox One Controller limits the range of
@@ -194,7 +230,7 @@
rumble_packet[8] = (low_frequency_rumble >> 9);
rumble_packet[9] = (high_frequency_rumble >> 9);
- if (hid_write(dev, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
+ if (hid_write(context->device, rumble_packet, sizeof(rumble_packet)) != sizeof(rumble_packet)) {
return SDL_SetError("Couldn't send rumble packet");
}
@@ -267,19 +303,24 @@
}
static SDL_bool
-HIDAPI_DriverXboxOne_Update(SDL_Joystick *joystick, hid_device *dev, void *context)
+HIDAPI_DriverXboxOne_UpdateDriver(SDL_HIDAPI_DriverData *context, int *num_joysticks)
{
- SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context;
+ SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)context->context;
+ SDL_Joystick *joystick = SDL_JoystickFromInstanceID(ctx->joystickID);
Uint8 data[USB_PACKET_LENGTH];
int size;
- while ((size = hid_read_timeout(dev, data, sizeof(data), 0)) > 0) {
+ if (joystick == NULL) {
+ return SDL_TRUE; /* Nothing to do right now! */
+ }
+
+ while ((size = hid_read_timeout(context->device, data, sizeof(data), 0)) > 0) {
switch (data[0]) {
case 0x20:
- HIDAPI_DriverXboxOne_HandleStatePacket(joystick, dev, ctx, data, size);
+ HIDAPI_DriverXboxOne_HandleStatePacket(joystick, context->device, ctx, data, size);
break;
case 0x07:
- HIDAPI_DriverXboxOne_HandleModePacket(joystick, dev, ctx, data, size);
+ HIDAPI_DriverXboxOne_HandleModePacket(joystick, context->device, ctx, data, size);
break;
default:
#ifdef DEBUG_JOYSTICK
@@ -292,29 +333,26 @@
if (ctx->rumble_expiration) {
Uint32 now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->rumble_expiration)) {
- HIDAPI_DriverXboxOne_Rumble(joystick, dev, context, 0, 0, 0);
+ HIDAPI_DriverXboxOne_Rumble(context, joystick, 0, 0, 0);
}
}
return (size >= 0);
}
-static void
-HIDAPI_DriverXboxOne_Quit(SDL_Joystick *joystick, hid_device *dev, void *context)
-{
- SDL_free(context);
-}
-
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
{
SDL_HINT_JOYSTICK_HIDAPI_XBOX,
SDL_TRUE,
HIDAPI_DriverXboxOne_IsSupportedDevice,
HIDAPI_DriverXboxOne_GetDeviceName,
- HIDAPI_DriverXboxOne_Init,
- HIDAPI_DriverXboxOne_Rumble,
- HIDAPI_DriverXboxOne_Update,
- HIDAPI_DriverXboxOne_Quit
+ HIDAPI_DriverXboxOne_InitDriver,
+ HIDAPI_DriverXboxOne_QuitDriver,
+ HIDAPI_DriverXboxOne_UpdateDriver,
+ HIDAPI_DriverXboxOne_NumJoysticks,
+ HIDAPI_DriverXboxOne_InstanceIDForIndex,
+ HIDAPI_DriverXboxOne_OpenJoystick,
+ HIDAPI_DriverXboxOne_Rumble
};
#endif /* SDL_JOYSTICK_HIDAPI_XBOXONE */
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index e420354..7cbd9f4 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -50,18 +50,10 @@
#endif
#endif
-struct joystick_hwdata
-{
- SDL_HIDAPI_DeviceDriver *driver;
- void *context;
-
- SDL_mutex *mutex;
- hid_device *dev;
-};
-
typedef struct _SDL_HIDAPI_Device
{
- SDL_JoystickID instance_id;
+ SDL_HIDAPI_DriverData devdata;
+ SDL_mutex *mutex;
char *name;
char *path;
Uint16 vendor_id;
@@ -95,6 +87,9 @@
#ifdef SDL_JOYSTICK_HIDAPI_XBOXONE
&SDL_HIDAPI_DriverXboxOne,
#endif
+#ifdef SDL_JOYSTICK_HIDAPI_GAMECUBE
+ &SDL_HIDAPI_DriverGameCube,
+#endif
};
static SDL_HIDAPI_Device *SDL_HIDAPI_devices;
static int SDL_HIDAPI_numjoysticks = 0;
@@ -393,6 +388,36 @@
#endif
}
+static void
+HIDAPI_InitDriver(SDL_HIDAPI_Device *device)
+{
+ device->devdata.device = hid_open_path(device->path, 0);
+ if (!device->devdata.device) {
+ SDL_SetError("Couldn't open HID device %s", device->path);
+ device->driver = NULL;
+ } else {
+ device->driver->InitDriver(
+ &device->devdata,
+ device->vendor_id,
+ device->product_id,
+ &SDL_HIDAPI_numjoysticks
+ );
+ device->mutex = SDL_CreateMutex();
+ }
+}
+
+static void
+HIDAPI_QuitDriver(SDL_HIDAPI_Device *device, SDL_bool send_event)
+{
+ device->driver->QuitDriver(
+ &device->devdata,
+ send_event,
+ &SDL_HIDAPI_numjoysticks
+ );
+ hid_close(device->devdata.device);
+ SDL_DestroyMutex(device->mutex);
+ device->driver = NULL;
+}
const char *
HIDAPI_XboxControllerName(Uint16 vendor_id, Uint16 product_id)
@@ -605,15 +630,17 @@
}
static SDL_HIDAPI_Device *
-HIDAPI_GetJoystickByIndex(int device_index)
+HIDAPI_GetDeviceByIndex(int device_index)
{
SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
+ int joysticks;
while (device) {
if (device->driver) {
- if (device_index == 0) {
+ joysticks = device->driver->NumJoysticks(&device->devdata);
+ if (device_index < joysticks) {
break;
}
- --device_index;
+ device_index -= joysticks;
}
device = device->next;
}
@@ -660,20 +687,12 @@
while (device) {
if (device->driver) {
if (!device->driver->enabled) {
- device->driver = NULL;
-
- --SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickRemoved(device->instance_id);
+ HIDAPI_QuitDriver(device, SDL_TRUE);
}
} else {
device->driver = HIDAPI_GetDeviceDriver(device);
if (device->driver) {
- device->instance_id = SDL_GetNextJoystickInstanceID();
-
- ++SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickAdded(device->instance_id);
+ HIDAPI_InitDriver(device);
}
}
device = device->next;
@@ -723,7 +742,6 @@
if (!device) {
return;
}
- device->instance_id = -1;
device->seen = SDL_TRUE;
device->vendor_id = info->vendor_id;
device->product_id = info->product_id;
@@ -818,12 +836,8 @@
}
if (device->driver) {
- /* It's a joystick! */
- device->instance_id = SDL_GetNextJoystickInstanceID();
-
- ++SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickAdded(device->instance_id);
+ /* It's a joystick device! */
+ HIDAPI_InitDriver(device);
}
}
@@ -840,11 +854,8 @@
SDL_HIDAPI_devices = curr->next;
}
- if (device->driver && send_event) {
- /* Need to decrement the joystick count before we post the event */
- --SDL_HIDAPI_numjoysticks;
-
- SDL_PrivateJoystickRemoved(device->instance_id);
+ if (device->driver) {
+ HIDAPI_QuitDriver(device, send_event);
}
SDL_free(device->name);
@@ -931,7 +942,7 @@
static const char *
HIDAPI_JoystickGetDeviceName(int device_index)
{
- return HIDAPI_GetJoystickByIndex(device_index)->name;
+ return HIDAPI_GetDeviceByIndex(device_index)->name;
}
static int
@@ -943,89 +954,61 @@
static SDL_JoystickGUID
HIDAPI_JoystickGetDeviceGUID(int device_index)
{
- return HIDAPI_GetJoystickByIndex(device_index)->guid;
+ return HIDAPI_GetDeviceByIndex(device_index)->guid;
}
static SDL_JoystickID
HIDAPI_JoystickGetDeviceInstanceID(int device_index)
{
- return HIDAPI_GetJoystickByIndex(device_index)->instance_id;
+ SDL_HIDAPI_Device *device = SDL_HIDAPI_devices;
+ int joysticks;
+ while (device) {
+ if (device->driver) {
+ joysticks = device->driver->NumJoysticks(&device->devdata);
+ if (device_index < joysticks) {
+ break;
+ }
+ device_index -= joysticks;
+ }
+ device = device->next;
+ }
+ return device->driver->InstanceIDForIndex(&device->devdata, device_index);
}
static int
HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
- SDL_HIDAPI_Device *device = HIDAPI_GetJoystickByIndex(device_index);
- struct joystick_hwdata *hwdata;
+ SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index);
- hwdata = (struct joystick_hwdata *)SDL_calloc(1, sizeof(*hwdata));
- if (!hwdata) {
- return SDL_OutOfMemory();
- }
-
- hwdata->driver = device->driver;
- hwdata->dev = hid_open_path(device->path, 0);
- if (!hwdata->dev) {
- SDL_free(hwdata);
- return SDL_SetError("Couldn't open HID device %s", device->path);
- }
- hwdata->mutex = SDL_CreateMutex();
-
- if (!device->driver->Init(joystick, hwdata->dev, device->vendor_id, device->product_id, &hwdata->context)) {
- hid_close(hwdata->dev);
- SDL_free(hwdata);
+ if (!device->driver->OpenJoystick(&device->devdata, joystick)) {
return -1;
}
- joystick->hwdata = hwdata;
+ joystick->hwdata = (struct joystick_hwdata *)device;
return 0;
}
static int
HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
{
- struct joystick_hwdata *hwdata = joystick->hwdata;
- SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
+ SDL_HIDAPI_Device *device = (SDL_HIDAPI_Device *)joystick->hwdata;
int result;
- SDL_LockMutex(hwdata->mutex);
- result = driver->Rumble(joystick, hwdata->dev, hwdata->context, low_frequency_rumble, high_frequency_rumble, duration_ms);
- SDL_UnlockMutex(hwdata->mutex);
+ SDL_LockMutex(device->mutex);
+ result = device->driver->Rumble(&device->devdata, joystick, low_frequency_rumble, high_frequency_rumble, duration_ms);
+ SDL_UnlockMutex(device->mutex);
return result;
}
static void
HIDAPI_JoystickUpdate(SDL_Joystick * joystick)
{
- struct joystick_hwdata *hwdata = joystick->hwdata;
- SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
- SDL_bool succeeded;
-
- SDL_LockMutex(hwdata->mutex);
- succeeded = driver->Update(joystick, hwdata->dev, hwdata->context);
- SDL_UnlockMutex(hwdata->mutex);
-
- if (!succeeded) {
- SDL_HIDAPI_Device *device;
- for (device = SDL_HIDAPI_devices; device; device = device->next) {
- if (device->instance_id == joystick->instance_id) {
- HIDAPI_DelDevice(device, SDL_TRUE);
- break;
- }
- }
- }
+ /* No-op, all updates are done in SDL_HIDAPI_UpdateDevices */
}
static void
HIDAPI_JoystickClose(SDL_Joystick * joystick)
{
- struct joystick_hwdata *hwdata = joystick->hwdata;
- SDL_HIDAPI_DeviceDriver *driver = hwdata->driver;
- driver->Quit(joystick, hwdata->dev, hwdata->context);
-
- hid_close(hwdata->dev);
- SDL_DestroyMutex(hwdata->mutex);
- SDL_free(hwdata);
joystick->hwdata = NULL;
}
@@ -1050,6 +1033,30 @@
hid_exit();
}
+void
+SDL_HIDAPI_UpdateDevices(void)
+{
+ SDL_HIDAPI_Device *next, *device = SDL_HIDAPI_devices;
+ SDL_bool succeeded;
+
+ while (device) {
+ if (device->driver) {
+ SDL_LockMutex(device->mutex);
+ succeeded = device->driver->UpdateDriver(&device->devdata, &SDL_HIDAPI_numjoysticks);
+ SDL_UnlockMutex(device->mutex);
+ if (!succeeded) {
+ next = device->next;
+ HIDAPI_DelDevice(device, SDL_TRUE);
+ device = next;
+ } else {
+ device = device->next;
+ }
+ } else {
+ device = device->next;
+ }
+ }
+}
+
SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
{
HIDAPI_JoystickInit,
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index a8e7073..807a301 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -30,6 +30,7 @@
#define SDL_JOYSTICK_HIDAPI_SWITCH
#define SDL_JOYSTICK_HIDAPI_XBOX360
#define SDL_JOYSTICK_HIDAPI_XBOXONE
+#define SDL_JOYSTICK_HIDAPI_GAMECUBE
#ifdef __WINDOWS__
/* On Windows, Xbox One controllers are handled by the Xbox 360 driver */
@@ -43,16 +44,36 @@
#undef SDL_JOYSTICK_HIDAPI_XBOXONE
#endif
+typedef struct _SDL_HIDAPI_DriverData
+{
+ hid_device *device;
+ void *context;
+} SDL_HIDAPI_DriverData;
+
typedef struct _SDL_HIDAPI_DeviceDriver
{
const char *hint;
SDL_bool enabled;
SDL_bool (*IsSupportedDevice)(Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number);
const char *(*GetDeviceName)(Uint16 vendor_id, Uint16 product_id);
- SDL_bool (*Init)(SDL_Joystick *joystick, hid_device *dev, Uint16 vendor_id, Uint16 product_id, void **context);
- int (*Rumble)(SDL_Joystick *joystick, hid_device *dev, void *context, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
- SDL_bool (*Update)(SDL_Joystick *joystick, hid_device *dev, void *context);
- void (*Quit)(SDL_Joystick *joystick, hid_device *dev, void *context);
+
+ SDL_bool (*InitDriver)(SDL_HIDAPI_DriverData *context,
+ Uint16 vendor_id, Uint16 product_id, int *num_joysticks);
+ void (*QuitDriver)(SDL_HIDAPI_DriverData *context,
+ SDL_bool send_event,
+ int *num_joysticks);
+ SDL_bool (*UpdateDriver)(SDL_HIDAPI_DriverData *context,
+ int *num_joysticks);
+ int (*NumJoysticks)(SDL_HIDAPI_DriverData *context);
+ SDL_JoystickID (*InstanceIDForIndex)(SDL_HIDAPI_DriverData *context,
+ int index);
+ SDL_bool (*OpenJoystick)(SDL_HIDAPI_DriverData *context,
+ SDL_Joystick *joystick);
+ int (*Rumble)(SDL_HIDAPI_DriverData *context,
+ SDL_Joystick *joystick,
+ Uint16 low_frequency_rumble,
+ Uint16 high_frequency_rumble,
+ Uint32 duration_ms);
} SDL_HIDAPI_DeviceDriver;
@@ -62,6 +83,7 @@
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360;
extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne;
+extern SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube;
/* Return true if a HID device is present and supported as a joystick */
extern SDL_bool HIDAPI_IsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version);