From f0bc5c9cbf3d589239d18d6b29e5072a0b77d7da Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 16 May 2022 07:21:28 -0700
Subject: [PATCH] Added effects support for virtual controllers
---
include/SDL_joystick.h | 6 ++++
src/joystick/virtual/SDL_virtualjoystick.c | 41 +++++++++++++++++++++-
test/testgamecontroller.c | 27 ++++++++++++++
3 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h
index 277e29a371f..9825b5be64b 100644
--- a/include/SDL_joystick.h
+++ b/include/SDL_joystick.h
@@ -352,6 +352,7 @@ extern DECLSPEC int SDLCALL SDL_JoystickAttachVirtual(SDL_JoystickType type,
* The structure that defines an extended virtual joystick description
*
* The caller must zero the structure and then initialize the version with `SDL_VIRTUAL_JOYSTICK_DESC_VERSION` before passing it to SDL_JoystickAttachVirtualEx()
+ * All other elements of this structure are optional and can be left 0.
*
* \sa SDL_JoystickAttachVirtualEx
*/
@@ -373,6 +374,11 @@ typedef struct SDL_VirtualJoystickDesc
void *userdata; /**< User data pointer passed to callbacks */
void (*Update)(void *userdata); /**< Called when the joystick state should be updated */
+ void (*SetPlayerIndex)(void *userdata, int player_index); /**< Called when the player index is set */
+ int (*Rumble)(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble); /**< Implements SDL_JoystickRumble() */
+ int (*RumbleTriggers)(void *userdata, Uint16 left_rumble, Uint16 right_rumble); /**< Implements SDL_JoystickRumbleTriggers() */
+ int (*SetLED)(void *userdata, Uint8 red, Uint8 green, Uint8 blue); /**< Implements SDL_JoystickSetLED() */
+ int (*SendEffect)(void *userdata, const void *data, int size); /**< Implements SDL_JoystickSendEffect() */
} SDL_VirtualJoystickDesc;
diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c
index 6e80d385b0f..4449d0af069 100644
--- a/src/joystick/virtual/SDL_virtualjoystick.c
+++ b/src/joystick/virtual/SDL_virtualjoystick.c
@@ -395,6 +395,11 @@ VIRTUAL_JoystickGetDevicePlayerIndex(int device_index)
static void
VIRTUAL_JoystickSetDevicePlayerIndex(int device_index, int player_index)
{
+ joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index);
+
+ if (hwdata && hwdata->desc.SetPlayerIndex) {
+ hwdata->desc.SetPlayerIndex(hwdata->desc.userdata, player_index);
+ }
}
@@ -446,12 +451,22 @@ VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index)
static int
VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
{
+ joystick_hwdata *hwdata = joystick->hwdata;
+
+ if (hwdata && hwdata->desc.Rumble) {
+ return hwdata->desc.Rumble(hwdata->desc.userdata, low_frequency_rumble, high_frequency_rumble);
+ }
return SDL_Unsupported();
}
static int
VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
{
+ joystick_hwdata *hwdata = joystick->hwdata;
+
+ if (hwdata && hwdata->desc.RumbleTriggers) {
+ return hwdata->desc.RumbleTriggers(hwdata->desc.userdata, left_rumble, right_rumble);
+ }
return SDL_Unsupported();
}
@@ -459,19 +474,43 @@ VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint1
static Uint32
VIRTUAL_JoystickGetCapabilities(SDL_Joystick *joystick)
{
- return 0;
+ joystick_hwdata *hwdata = joystick->hwdata;
+ Uint32 caps = 0;
+
+ if (hwdata) {
+ if (hwdata->desc.Rumble) {
+ caps |= SDL_JOYCAP_RUMBLE;
+ }
+ if (hwdata->desc.RumbleTriggers) {
+ caps |= SDL_JOYCAP_RUMBLE_TRIGGERS;
+ }
+ if (hwdata->desc.SetLED) {
+ caps |= SDL_JOYCAP_LED;
+ }
+ }
+ return caps;
}
static int
VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
{
+ joystick_hwdata *hwdata = joystick->hwdata;
+
+ if (hwdata && hwdata->desc.SetLED) {
+ return hwdata->desc.SetLED(hwdata->desc.userdata, red, green, blue);
+ }
return SDL_Unsupported();
}
static int
VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
{
+ joystick_hwdata *hwdata = joystick->hwdata;
+
+ if (hwdata && hwdata->desc.SendEffect) {
+ return hwdata->desc.SendEffect(hwdata->desc.userdata, data, size);
+ }
return SDL_Unsupported();
}
diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c
index 086a340413f..b24581598a4 100644
--- a/test/testgamecontroller.c
+++ b/test/testgamecontroller.c
@@ -312,6 +312,29 @@ static SDL_bool ShowingFront()
return showing_front;
}
+static void VirtualControllerSetPlayerIndex(void *userdata, int player_index)
+{
+ SDL_Log("Virtual Controller: player index set to %d\n", player_index);
+}
+
+static int VirtualControllerRumble(void *userdata, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
+{
+ SDL_Log("Virtual Controller: rumble set to %d/%d\n", low_frequency_rumble, high_frequency_rumble);
+ return 0;
+}
+
+static int VirtualControllerRumbleTriggers(void *userdata, Uint16 left_rumble, Uint16 right_rumble)
+{
+ SDL_Log("Virtual Controller: trigger rumble set to %d/%d\n", left_rumble, right_rumble);
+ return 0;
+}
+
+static int VirtualControllerSetLED(void *userdata, Uint8 red, Uint8 green, Uint8 blue)
+{
+ SDL_Log("Virtual Controller: LED set to RGB %d,%d,%d\n", red, green, blue);
+ return 0;
+}
+
static int OpenVirtualController()
{
SDL_VirtualJoystickDesc desc;
@@ -321,6 +344,10 @@ static int OpenVirtualController()
desc.type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
desc.naxes = SDL_CONTROLLER_AXIS_MAX;
desc.nbuttons = SDL_CONTROLLER_BUTTON_MAX;
+ desc.SetPlayerIndex = VirtualControllerSetPlayerIndex;
+ desc.Rumble = VirtualControllerRumble;
+ desc.RumbleTriggers = VirtualControllerRumbleTriggers;
+ desc.SetLED = VirtualControllerSetLED;
return SDL_JoystickAttachVirtualEx(&desc);
}