From d135c0762f11c29eb9cce377648f25e5a91b4522 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 8 Jul 2021 13:22:41 -0700
Subject: [PATCH] Added SDL_GameControllerSendEffect() and
SDL_JoystickSendEffect() to allow applications to send custom effects to the
PS4 and PS5 controllers
See testgamecontroller.c for an example of a custom PS5 trigger effect
---
include/SDL_gamecontroller.h | 10 ++
include/SDL_joystick.h | 10 ++
src/dynapi/SDL_dynapi_overrides.h | 2 +
src/dynapi/SDL_dynapi_procs.h | 2 +
src/joystick/SDL_gamecontroller.c | 6 +
src/joystick/SDL_joystick.c | 18 +++
src/joystick/SDL_sysjoystick.h | 3 +
src/joystick/android/SDL_sysjoystick.c | 21 ++-
src/joystick/bsd/SDL_bsdjoystick.c | 7 +
src/joystick/darwin/SDL_iokitjoystick.c | 21 ++-
src/joystick/dummy/SDL_sysjoystick.c | 7 +
src/joystick/emscripten/SDL_sysjoystick.c | 7 +
src/joystick/haiku/SDL_haikujoystick.cc | 7 +
src/joystick/hidapi/SDL_hidapi_gamecube.c | 7 +
src/joystick/hidapi/SDL_hidapi_luna.c | 7 +
src/joystick/hidapi/SDL_hidapi_ps4.c | 105 +++++++------
src/joystick/hidapi/SDL_hidapi_ps5.c | 147 ++++++++++--------
src/joystick/hidapi/SDL_hidapi_stadia.c | 7 +
src/joystick/hidapi/SDL_hidapi_steam.c | 7 +
src/joystick/hidapi/SDL_hidapi_switch.c | 7 +
src/joystick/hidapi/SDL_hidapi_xbox360.c | 7 +
src/joystick/hidapi/SDL_hidapi_xbox360w.c | 7 +
src/joystick/hidapi/SDL_hidapi_xboxone.c | 7 +
src/joystick/hidapi/SDL_hidapijoystick.c | 36 +++--
src/joystick/hidapi/SDL_hidapijoystick_c.h | 1 +
src/joystick/iphoneos/SDL_mfijoystick.m | 7 +
src/joystick/linux/SDL_sysjoystick.c | 7 +
src/joystick/os2/SDL_os2joystick.c | 6 +
src/joystick/psp/SDL_sysjoystick.c | 7 +
src/joystick/virtual/SDL_virtualjoystick.c | 27 ++--
src/joystick/vita/SDL_sysjoystick.c | 15 +-
src/joystick/windows/SDL_mmjoystick.c | 13 +-
src/joystick/windows/SDL_rawinputjoystick.c | 7 +
.../windows/SDL_windows_gaming_input.c | 21 ++-
src/joystick/windows/SDL_windowsjoystick.c | 21 ++-
test/testgamecontroller.c | 122 ++++++++++++---
36 files changed, 533 insertions(+), 186 deletions(-)
diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h
index 728e749ade..2248fb7303 100644
--- a/include/SDL_gamecontroller.h
+++ b/include/SDL_gamecontroller.h
@@ -820,6 +820,16 @@ extern DECLSPEC SDL_bool SDLCALL SDL_GameControllerHasLED(SDL_GameController *ga
*/
extern DECLSPEC int SDLCALL SDL_GameControllerSetLED(SDL_GameController *gamecontroller, Uint8 red, Uint8 green, Uint8 blue);
+/**
+ * Send a controller specific effect packet
+ *
+ * \param gamecontroller The controller to affect
+ * \param data The data to send to the controller
+ * \param size The size of the data to send to the controller
+ * \returns 0, or -1 if this controller or driver doesn't support effect packets
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerSendEffect(SDL_GameController *gamecontroller, const void *data, int size);
+
/**
* Close a game controller previously opened with SDL_GameControllerOpen().
*
diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h
index c9cb923294..56f1c8efde 100644
--- a/include/SDL_joystick.h
+++ b/include/SDL_joystick.h
@@ -782,6 +782,16 @@ extern DECLSPEC SDL_bool SDLCALL SDL_JoystickHasLED(SDL_Joystick *joystick);
*/
extern DECLSPEC int SDLCALL SDL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue);
+/**
+ * Send a joystick specific effect packet
+ *
+ * \param joystick The joystick to affect
+ * \param data The data to send to the joystick
+ * \param size The size of the data to send to the joystick
+ * \returns 0, or -1 if this joystick or driver doesn't support effect packets
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size);
+
/**
* Close a joystick previously opened with SDL_JoystickOpen().
*
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 99662c0364..165fa09eb2 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -812,3 +812,5 @@
#define SDL_TLSCleanup SDL_TLSCleanup_REAL
#define SDL_SetWindowAlwaysOnTop SDL_SetWindowAlwaysOnTop_REAL
#define SDL_FlashWindow SDL_FlashWindow_REAL
+#define SDL_GameControllerSendEffect SDL_GameControllerSendEffect_REAL
+#define SDL_JoystickSendEffect SDL_JoystickSendEffect_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 17e7eb317f..a1251e807a 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -877,3 +877,5 @@ SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceSpec,(int a, int b, SDL_AudioSpec *c),(a,b
SDL_DYNAPI_PROC(void,SDL_TLSCleanup,(void),(),)
SDL_DYNAPI_PROC(void,SDL_SetWindowAlwaysOnTop,(SDL_Window *a, SDL_bool b),(a,b),)
SDL_DYNAPI_PROC(int,SDL_FlashWindow,(SDL_Window *a, Uint32 b),(a, b),return)
+SDL_DYNAPI_PROC(int,SDL_GameControllerSendEffect,(SDL_GameController *a, const void *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_JoystickSendEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return)
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 97b7b78a20..87663f57f0 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -2411,6 +2411,12 @@ SDL_GameControllerSetLED(SDL_GameController *gamecontroller, Uint8 red, Uint8 gr
return SDL_JoystickSetLED(SDL_GameControllerGetJoystick(gamecontroller), red, green, blue);
}
+int
+SDL_GameControllerSendEffect(SDL_GameController *gamecontroller, const void *data, int size)
+{
+ return SDL_JoystickSendEffect(SDL_GameControllerGetJoystick(gamecontroller), data, size);
+}
+
void
SDL_GameControllerClose(SDL_GameController *gamecontroller)
{
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 9a0038bf13..dea2aab3d5 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -986,6 +986,24 @@ SDL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
return result;
}
+int
+SDL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+{
+ int result;
+
+ if (!SDL_PrivateJoystickValid(joystick)) {
+ return -1;
+ }
+
+ SDL_LockJoysticks();
+
+ result = joystick->driver->SendEffect(joystick, data, size);
+
+ SDL_UnlockJoysticks();
+
+ return result;
+}
+
/*
* Close a joystick previously opened with SDL_JoystickOpen()
*/
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 749c6efd29..bf6361502d 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -166,6 +166,9 @@ typedef struct _SDL_JoystickDriver
SDL_bool (*HasLED)(SDL_Joystick *joystick);
int (*SetLED)(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue);
+ /* General effects */
+ int (*SendEffect)(SDL_Joystick *joystick, const void *data, int size);
+
/* Sensor functionality */
int (*SetSensorsEnabled)(SDL_Joystick *joystick, SDL_bool enabled);
diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c
index 4d7624f9b7..a4efdc1bca 100644
--- a/src/joystick/android/SDL_sysjoystick.c
+++ b/src/joystick/android/SDL_sysjoystick.c
@@ -581,7 +581,7 @@ ANDROID_JoystickGetDeviceInstanceID(int device_index)
}
static int
-ANDROID_JoystickOpen(SDL_Joystick * joystick, int device_index)
+ANDROID_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
SDL_joylist_item *item = JoystickByDevIndex(device_index);
@@ -605,25 +605,31 @@ ANDROID_JoystickOpen(SDL_Joystick * joystick, int device_index)
}
static int
-ANDROID_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+ANDROID_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
return SDL_Unsupported();
}
static int
-ANDROID_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+ANDROID_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static SDL_bool
-ANDROID_JoystickHasLED(SDL_Joystick * joystick)
+ANDROID_JoystickHasLED(SDL_Joystick *joystick)
{
return SDL_FALSE;
}
static int
-ANDROID_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue)
+ANDROID_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+ return SDL_Unsupported();
+}
+
+static int
+ANDROID_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
@@ -635,7 +641,7 @@ ANDROID_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
}
static void
-ANDROID_JoystickUpdate(SDL_Joystick * joystick)
+ANDROID_JoystickUpdate(SDL_Joystick *joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
@@ -664,7 +670,7 @@ ANDROID_JoystickUpdate(SDL_Joystick * joystick)
}
static void
-ANDROID_JoystickClose(SDL_Joystick * joystick)
+ANDROID_JoystickClose(SDL_Joystick *joystick)
{
SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
if (item) {
@@ -715,6 +721,7 @@ SDL_JoystickDriver SDL_ANDROID_JoystickDriver =
ANDROID_JoystickRumbleTriggers,
ANDROID_JoystickHasLED,
ANDROID_JoystickSetLED,
+ ANDROID_JoystickSendEffect,
ANDROID_JoystickSetSensorsEnabled,
ANDROID_JoystickUpdate,
ANDROID_JoystickClose,
diff --git a/src/joystick/bsd/SDL_bsdjoystick.c b/src/joystick/bsd/SDL_bsdjoystick.c
index 57c44ba40d..8735b4dff3 100644
--- a/src/joystick/bsd/SDL_bsdjoystick.c
+++ b/src/joystick/bsd/SDL_bsdjoystick.c
@@ -789,6 +789,12 @@ BSD_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
return SDL_Unsupported();
}
+static int
+BSD_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+{
+ return SDL_Unsupported();
+}
+
static int
BSD_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -810,6 +816,7 @@ SDL_JoystickDriver SDL_BSD_JoystickDriver =
BSD_JoystickRumbleTriggers,
BSD_JoystickHasLED,
BSD_JoystickSetLED,
+ BSD_JoystickSendEffect,
BSD_JoystickSetSensorsEnabled,
BSD_JoystickUpdate,
BSD_JoystickClose,
diff --git a/src/joystick/darwin/SDL_iokitjoystick.c b/src/joystick/darwin/SDL_iokitjoystick.c
index 2232e1456b..d377183b00 100644
--- a/src/joystick/darwin/SDL_iokitjoystick.c
+++ b/src/joystick/darwin/SDL_iokitjoystick.c
@@ -784,7 +784,7 @@ DARWIN_JoystickGetDeviceInstanceID(int device_index)
}
static int
-DARWIN_JoystickOpen(SDL_Joystick * joystick, int device_index)
+DARWIN_JoystickOpen(SDL_Joystick *joystick, int device_index)
{
recDevice *device = GetDeviceForIndex(device_index);
@@ -894,7 +894,7 @@ DARWIN_JoystickInitRumble(recDevice *device, Sint16 magnitude)
}
static int
-DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+DARWIN_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
HRESULT result;
recDevice *device = joystick->hwdata;
@@ -934,19 +934,25 @@ DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint
}
static int
-DARWIN_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+DARWIN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
return SDL_Unsupported();
}
static SDL_bool
-DARWIN_JoystickHasLED(SDL_Joystick * joystick)
+DARWIN_JoystickHasLED(SDL_Joystick *joystick)
{
return SDL_FALSE;
}
static int
-DARWIN_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue)
+DARWIN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+ return SDL_Unsupported();
+}
+
+static int
+DARWIN_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
return SDL_Unsupported();
}
@@ -958,7 +964,7 @@ DARWIN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
}
static void
-DARWIN_JoystickUpdate(SDL_Joystick * joystick)
+DARWIN_JoystickUpdate(SDL_Joystick *joystick)
{
recDevice *device = joystick->hwdata;
recElement *element;
@@ -1063,7 +1069,7 @@ DARWIN_JoystickUpdate(SDL_Joystick * joystick)
}
static void
-DARWIN_JoystickClose(SDL_Joystick * joystick)
+DARWIN_JoystickClose(SDL_Joystick *joystick)
{
recDevice *device = joystick->hwdata;
if (device) {
@@ -1107,6 +1113,7 @@ SDL_JoystickDriver SDL_DARWIN_JoystickDriver =
DARWIN_JoystickRumbleTriggers,
DARWIN_JoystickHasLED,
DARWIN_JoystickSetLED,
+ DARWIN_JoystickSendEffect,
DARWIN_JoystickSetSensorsEnabled,
DARWIN_JoystickUpdate,
DARWIN_JoystickClose,
diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c
index 3fab5d81ac..c6947c725a 100644
--- a/src/joystick/dummy/SDL_sysjoystick.c
+++ b/src/joystick/dummy/SDL_sysjoystick.c
@@ -107,6 +107,12 @@ DUMMY_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
return SDL_Unsupported();
}
+static int
+DUMMY_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+{
+ return SDL_Unsupported();
+}
+
static int
DUMMY_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -149,6 +155,7 @@ SDL_JoystickDriver SDL_DUMMY_JoystickDriver =
DUMMY_JoystickRumbleTriggers,
DUMMY_JoystickHasLED,
DUMMY_JoystickSetLED,
+ DUMMY_JoystickSendEffect,
DUMMY_JoystickSetSensorsEnabled,
DUMMY_JoystickUpdate,
DUMMY_JoystickClose,
diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c
index 5e23e4bfb2..bbd481d493 100644
--- a/src/joystick/emscripten/SDL_sysjoystick.c
+++ b/src/joystick/emscripten/SDL_sysjoystick.c
@@ -426,6 +426,12 @@ EMSCRIPTEN_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8
return SDL_Unsupported();
}
+static int
+EMSCRIPTEN_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+{
+ return SDL_Unsupported();
+}
+
static int
EMSCRIPTEN_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -447,6 +453,7 @@ SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver =
EMSCRIPTEN_JoystickRumbleTriggers,
EMSCRIPTEN_JoystickHasLED,
EMSCRIPTEN_JoystickSetLED,
+ EMSCRIPTEN_JoystickSendEffect,
EMSCRIPTEN_JoystickSetSensorsEnabled,
EMSCRIPTEN_JoystickUpdate,
EMSCRIPTEN_JoystickClose,
diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc
index cd27dce482..687dd49953 100644
--- a/src/joystick/haiku/SDL_haikujoystick.cc
+++ b/src/joystick/haiku/SDL_haikujoystick.cc
@@ -281,6 +281,12 @@ extern "C"
return SDL_Unsupported();
}
+
+ static int HAIKU_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
+ {
+ return SDL_Unsupported();
+ }
+
static int HAIKU_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
@@ -301,6 +307,7 @@ extern "C"
HAIKU_JoystickRumbleTriggers,
HAIKU_JoystickHasLED,
HAIKU_JoystickSetLED,
+ HAIKU_JoystickSendEffect,
HAIKU_JoystickSetSensorsEnabled,
HAIKU_JoystickUpdate,
HAIKU_JoystickClose,
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index 9d6ddd80bc..e4407f0634 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -476,6 +476,12 @@ HIDAPI_DriverGameCube_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *jo
return SDL_Unsupported();
}
+static int
+HIDAPI_DriverGameCube_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
+{
+ return SDL_Unsupported();
+}
+
static int
HIDAPI_DriverGameCube_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -528,6 +534,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
HIDAPI_DriverGameCube_RumbleJoystickTriggers,
HIDAPI_DriverGameCube_HasJoystickLED,
HIDAPI_DriverGameCube_SetJoystickLED,
+ HIDAPI_DriverGameCube_SendJoystickEffect,
HIDAPI_DriverGameCube_SetJoystickSensorsEnabled,
HIDAPI_DriverGameCube_CloseJoystick,
HIDAPI_DriverGameCube_FreeDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_luna.c b/src/joystick/hidapi/SDL_hidapi_luna.c
index 62e4213bb4..e39b568480 100644
--- a/src/joystick/hidapi/SDL_hidapi_luna.c
+++ b/src/joystick/hidapi/SDL_hidapi_luna.c
@@ -148,6 +148,12 @@ HIDAPI_DriverLuna_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
return SDL_Unsupported();
}
+static int
+HIDAPI_DriverLuna_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size)
+{
+ return SDL_Unsupported();
+}
+
static int
HIDAPI_DriverLuna_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -441,6 +447,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverLuna =
HIDAPI_DriverLuna_RumbleJoystickTriggers,
HIDAPI_DriverLuna_HasJoystickLED,
HIDAPI_DriverLuna_SetJoystickLED,
+ HIDAPI_DriverLuna_SendJoystickEffect,
HIDAPI_DriverLuna_SetJoystickSensorsEnabled,
HIDAPI_DriverLuna_CloseJoystick,
HIDAPI_DriverLuna_FreeDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index eda3ebadef..a32e88fe57 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -146,6 +146,8 @@ typedef struct {
} SDL_DriverPS4_Context;
+static int HIDAPI_DriverPS4_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size);
+
static SDL_bool
HIDAPI_DriverPS4_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
@@ -385,61 +387,26 @@ static int
HIDAPI_DriverPS4_UpdateEffects(SDL_HIDAPI_Device *device)
{
SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
- DS4EffectsState_t *effects;
- Uint8 data[78];
- int report_size, offset;
-
- if (!ctx->effects_supported) {
- return SDL_Unsupported();
- }
+ DS4EffectsState_t effects;
if (!ctx->enhanced_mode) {
return SDL_Unsupported();
}
- SDL_zero(data);
-
- if (ctx->is_bluetooth) {
- data[0] = k_EPS4ReportIdBluetoothEffects;
- data[1] = 0xC0 | 0x04; /* Magic value HID + CRC, also sets interval to 4ms for samples */
- data[3] = 0x03; /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
-
- report_size = 78;
- offset = 6;
- } else {
- data[0] = k_EPS4ReportIdUsbEffects;
- data[1] = 0x07; /* Magic value */
-
- report_size = 32;
- offset = 4;
- }
- effects = (DS4EffectsState_t *)&data[offset];
+ SDL_zero(effects);
- effects->ucRumbleLeft = ctx->rumble_left;
- effects->ucRumbleRight = ctx->rumble_right;
+ effects.ucRumbleLeft = ctx->rumble_left;
+ effects.ucRumbleRight = ctx->rumble_right;
/* Populate the LED state with the appropriate color from our lookup table */
if (ctx->color_set) {
- effects->ucLedRed = ctx->led_red;
- effects->ucLedGreen = ctx->led_green;
- effects->ucLedBlue = ctx->led_blue;
+ effects.ucLedRed = ctx->led_red;
+ effects.ucLedGreen = ctx->led_green;
+ effects.ucLedBlue = ctx->led_blue;
} else {
- SetLedsForPlayerIndex(effects, ctx->player_index);
- }
-
- if (ctx->is_bluetooth) {
- /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
- Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
- Uint32 unCRC;
- unCRC = SDL_crc32(0, &ubHdr, 1);
- unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC)));
- SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
+ SetLedsForPlayerIndex(&effects, ctx->player_index);
}
-
- if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) {
- return SDL_SetError("Couldn't send rumble packet");
- }
- return 0;
+ return HIDAPI_DriverPS4_SendJoystickEffect(device, ctx->joystick, &effects, sizeof(effects));
}
static void
@@ -650,6 +617,55 @@ HIDAPI_DriverPS4_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
return HIDAPI_DriverPS4_UpdateEffects(device);
}
+static int
+HIDAPI_DriverPS4_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size)
+{
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
+ Uint8 data[78];
+ int report_size, offset;
+
+ if (!ctx->effects_supported) {
+ return SDL_Unsupported();
+ }
+
+ if (!ctx->enhanced_mode) {
+ HIDAPI_DriverPS4_SetEnhancedMode(device, joystick);
+ }
+
+ SDL_zero(data);
+
+ if (ctx->is_bluetooth) {
+ data[0] = k_EPS4ReportIdBluetoothEffects;
+ data[1] = 0xC0 | 0x04; /* Magic value HID + CRC, also sets interval to 4ms for samples */
+ data[3] = 0x03; /* 0x1 is rumble, 0x2 is lightbar, 0x4 is the blink interval */
+
+ report_size = 78;
+ offset = 6;
+ } else {
+ data[0] = k_EPS4ReportIdUsbEffects;
+ data[1] = 0x07; /* Magic value */
+
+ report_size = 32;
+ offset = 4;
+ }
+
+ SDL_memcpy(&data[offset], effect, SDL_min((sizeof(data) - offset), size));
+
+ if (ctx->is_bluetooth) {
+ /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
+ Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
+ Uint32 unCRC;
+ unCRC = SDL_crc32(0, &ubHdr, 1);
+ unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC)));
+ SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
+ }
+
+ if (SDL_HIDAPI_SendRumble(device, data, report_size) != report_size) {
+ return SDL_SetError("Couldn't send rumble packet");
+ }
+ return 0;
+}
+
static int
HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -921,6 +937,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
HIDAPI_DriverPS4_RumbleJoystickTriggers,
HIDAPI_DriverPS4_HasJoystickLED,
HIDAPI_DriverPS4_SetJoystickLED,
+ HIDAPI_DriverPS4_SendJoystickEffect,
HIDAPI_DriverPS4_SetJoystickSensorsEnabled,
HIDAPI_DriverPS4_CloseJoystick,
HIDAPI_DriverPS4_FreeDevice,
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 6df4acec18..232435f532 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -175,6 +175,8 @@ typedef struct {
} SDL_DriverPS5_Context;
+static int HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size);
+
static SDL_bool
HIDAPI_DriverPS5_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
{
@@ -375,32 +377,13 @@ static int
HIDAPI_DriverPS5_UpdateEffects(SDL_HIDAPI_Device *device, int effect_mask)
{
SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
- DS5EffectsState_t *effects;
- Uint8 data[78];
- int report_size, offset;
- Uint8 *pending_data;
- int *pending_size;
- int maximum_size;
+ DS5EffectsState_t effects;
if (!ctx->enhanced_mode) {
return SDL_Unsupported();
}
- SDL_zero(data);
-
- if (ctx->is_bluetooth) {
- data[0] = k_EPS5ReportIdBluetoothEffects;
- data[1] = 0x02; /* Magic value */
-
- report_size = 78;
- offset = 2;
- } else {
- data[0] = k_EPS5ReportIdUsbEffects;
-
- report_size = 48;
- offset = 1;
- }
- effects = (DS5EffectsState_t *)&data[offset];
+ SDL_zero(effects);
/* Make sure the Bluetooth connection sequence has completed before sending LED color change */
if (ctx->is_bluetooth &&
@@ -412,79 +395,53 @@ HIDAPI_DriverPS5_UpdateEffects(SDL_HIDAPI_Device *device, int effect_mask)
}
if (ctx->rumble_left || ctx->rumble_right) {
- effects->ucEnableBits1 |= 0x01; /* Enable rumble emulation */
- effects->ucEnableBits1 |= 0x02; /* Disable audio haptics */
+ effects.ucEnableBits1 |= 0x01; /* Enable rumble emulation */
+ effects.ucEnableBits1 |= 0x02; /* Disable audio haptics */
/* Shift to reduce effective rumble strength to match Xbox controllers */
- effects->ucRumbleLeft = ctx->rumble_left >> 1;
- effects->ucRumbleRight = ctx->rumble_right >> 1;
+ effects.ucRumbleLeft = ctx->rumble_left >> 1;
+ effects.ucRumbleRight = ctx->rumble_right >> 1;
} else {
/* Leaving emulated rumble bits off will restore audio haptics */
}
if ((effect_mask & k_EDS5EffectRumbleStart) != 0) {
- effects->ucEnableBits1 |= 0x02; /* Disable audio haptics */
+ effects.ucEnableBits1 |= 0x02; /* Disable audio haptics */
}
if ((effect_mask & k_EDS5EffectRumble) != 0) {
/* Already handled above */
}
if ((effect_mask & k_EDS5EffectLEDReset) != 0) {
- effects->ucEnableBits2 |= 0x08; /* Reset LED state */
+ effects.ucEnableBits2 |= 0x08; /* Reset LED state */
}
if ((effect_mask & k_EDS5EffectLED) != 0) {
- effects->ucEnableBits2 |= 0x04; /* Enable LED color */
+ effects.ucEnableBits2 |= 0x04; /* Enable LED color */
/* Populate the LED state with the appropriate color from our lookup table */
if (ctx->color_set) {
- effects->ucLedRed = ctx->led_red;
- effects->ucLedGreen = ctx->led_green;
- effects->ucLedBlue = ctx->led_blue;
+ effects.ucLedRed = ctx->led_red;
+ effects.ucLedGreen = ctx->led_green;
+ effects.ucLedBlue = ctx->led_blue;
} else {
- SetLedsForPlayerIndex(effects, ctx->player_index);
+ SetLedsForPlayerIndex(&effects, ctx->player_index);
}
}
if ((effect_mask & k_EDS5EffectPadLights) != 0) {
- effects->ucEnableBits2 |= 0x10; /* Enable touchpad lights */
+ effects.ucEnableBits2 |= 0x10; /* Enable touchpad lights */
if (ctx->player_lights) {
- SetLightsForPlayerIndex(effects, ctx->player_index);
+ SetLightsForPlayerIndex(&effects, ctx->player_index);
} else {
- effects->ucPadLights = 0x00;
+ effects.ucPadLights = 0x00;
}
}
if ((effect_mask & k_EDS5EffectMicLight) != 0) {
- effects->ucEnableBits2 |= 0x01; /* Enable microphone light */
+ effects.ucEnableBits2 |= 0x01; /* Enable microphone light */
- effects->ucMicLightMode = 0; /* Bitmask, 0x00 = off, 0x01 = solid, 0x02 = pulse */
+ effects.ucMicLightMode = 0; /* Bitmask, 0x00 = off, 0x01 = solid, 0x02 = pulse */
}
- if (ctx->is_bluetooth) {
- /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
- Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
- Uint32 unCRC;
- unCRC = SDL_crc32(0, &ubHdr, 1);
- unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC)));
- SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
- }
-
- if (SDL_HIDAPI_LockRumble() < 0) {
- return -1;
- }
-
- /* See if we can update an existing pending request */
- if (SDL_HIDAPI_GetPendingRumbleLocked(device, &pending_data, &pending_size, &maximum_size)) {
- DS5EffectsState_t *pending_effects = (DS5EffectsState_t *)&pending_data[offset];
- if (report_size == *pending_size &&
- effects->ucEnableBits1 == pending_effects->ucEnableBits1 &&
- effects->ucEnableBits2 == pending_effects->ucEnableBits2) {
- /* We're simply updating the data for this request */
- SDL_memcpy(pending_data, data, report_size);
- SDL_HIDAPI_UnlockRumble();
- return 0;
- }
- }
-
- return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size);
+ return HIDAPI_DriverPS5_SendJoystickEffect(device, ctx->joystick, &effects, sizeof(effects));
}
static void
@@ -725,6 +682,67 @@ HIDAPI_DriverPS5_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
return HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLED);
}
+static int
+HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size)
+{
+ SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
+ Uint8 data[78];
+ int report_size, offset;
+ Uint8 *pending_data;
+ int *pending_size;
+ int maximum_size;
+
+ if (!ctx->enhanced_mode) {
+ HIDAPI_DriverPS5_SetEnhancedMode(device, joystick);
+ }
+
+ SDL_zero(data);
+
+ if (ctx->is_bluetooth) {
+ data[0] = k_EPS5ReportIdBluetoothEffects;
+ data[1] = 0x02; /* Magic value */
+
+ report_size = 78;
+ offset = 2;
+ } else {
+ data[0] = k_EPS5ReportIdUsbEffects;
+
+ report_size = 48;
+ offset = 1;
+ }
+
+ SDL_memcpy(&data[offset], effect, SDL_min((sizeof(data) - offset), size));
+
+ if (ctx->is_bluetooth) {
+ /* Bluetooth reports need a CRC at the end of the packet (at least on Linux) */
+ Uint8 ubHdr = 0xA2; /* hidp header is part of the CRC calculation */
+ Uint32 unCRC;
+ unCRC = SDL_crc32(0, &ubHdr, 1);
+ unCRC = SDL_crc32(unCRC, data, (size_t)(report_size - sizeof(unCRC)));
+ SDL_memcpy(&data[report_size - sizeof(unCRC)], &unCRC, sizeof(unCRC));
+ }
+
+ if (SDL_HIDAPI_LockRumble() < 0) {
+ return -1;
+ }
+
+ /* See if we can update an existing pending request */
+ if (SDL_HIDAPI_GetPendingRumbleLocked(device, &pending_data, &pending_size, &maximum_size)) {
+ DS5EffectsState_t *effects = (DS5EffectsState_t *)&data[offset];
+ DS5EffectsState_t *pending_effects = (DS5EffectsState_t *)&pending_data[offset];
+ if (report_size == *pending_size &&
+ effects->ucEnableBits1 == pending_effects->ucEnableBits1 &&
+ effects->ucEnableBits2 == pending_effects->ucEnableBits2) {
+ /* We're simply updating the data for this request */
+ SDL_memcpy(pending_data, data, report_size);
+ SDL_HIDAPI_UnlockRumble();
+ return 0;
+ }
+ }
+
+ return SDL_HIDAPI_SendRumbleAndUnlock(device, data, report_size);
+}
+
static int
HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
@@ -1082,6 +1100,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS5 =
HIDAPI_DriverPS5_Rumbl
(Patch may be truncated, please check the link at the top of this post.)