summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Lantinga <slouken@libsdl.org>2020-11-11 18:57:37 -0800
committerSam Lantinga <slouken@libsdl.org>2020-11-11 18:57:37 -0800
commit0d678445809fdac349be10854bfec6d9c1f734f2 (patch)
tree3eb78897c5c69bcde1f1bacb75b1a29f0e360dff
parent0c3572e719bef564ef33f0ca61a370ea88e33aea (diff)
downloadsdl-0d678445809fdac349be10854bfec6d9c1f734f2.tar.gz
Added SDL_JoystickRumbleTriggers() and SDL_GameControllerRumbleTriggers()
-rw-r--r--include/SDL_gamecontroller.h17
-rw-r--r--include/SDL_joystick.h15
-rw-r--r--src/dynapi/SDL_dynapi_overrides.h2
-rw-r--r--src/dynapi/SDL_dynapi_procs.h2
-rw-r--r--src/joystick/SDL_gamecontroller.c6
-rw-r--r--src/joystick/SDL_joystick.c47
-rw-r--r--src/joystick/SDL_sysjoystick.h5
-rw-r--r--src/joystick/android/SDL_sysjoystick.c7
-rw-r--r--src/joystick/bsd/SDL_sysjoystick.c7
-rw-r--r--src/joystick/darwin/SDL_sysjoystick.c7
-rw-r--r--src/joystick/dummy/SDL_sysjoystick.c7
-rw-r--r--src/joystick/emscripten/SDL_sysjoystick.c7
-rw-r--r--src/joystick/haiku/SDL_haikujoystick.cc7
-rw-r--r--src/joystick/hidapi/SDL_hidapi_gamecube.c7
-rw-r--r--src/joystick/hidapi/SDL_hidapi_ps4.c7
-rw-r--r--src/joystick/hidapi/SDL_hidapi_switch.c7
-rw-r--r--src/joystick/hidapi/SDL_hidapi_xbox360.c7
-rw-r--r--src/joystick/hidapi/SDL_hidapi_xbox360w.c7
-rw-r--r--src/joystick/hidapi/SDL_hidapi_xboxone.c7
-rw-r--r--src/joystick/hidapi/SDL_hidapijoystick.c18
-rw-r--r--src/joystick/hidapi/SDL_hidapijoystick_c.h1
-rw-r--r--src/joystick/iphoneos/SDL_sysjoystick.m56
-rw-r--r--src/joystick/linux/SDL_sysjoystick.c7
-rw-r--r--src/joystick/virtual/SDL_virtualjoystick.c7
-rw-r--r--src/joystick/windows/SDL_rawinputjoystick.c10
-rw-r--r--src/joystick/windows/SDL_windows_gaming_input.c31
-rw-r--r--src/joystick/windows/SDL_windowsjoystick.c7
-rw-r--r--test/testgamecontroller.c21
28 files changed, 326 insertions, 10 deletions
diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h
index a8d9a5e02..7ef500bb4 100644
--- a/include/SDL_gamecontroller.h
+++ b/include/SDL_gamecontroller.h
@@ -398,7 +398,7 @@ extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *ga
SDL_GameControllerButton button);
/**
- * Trigger a rumble effect
+ * Start a rumble effect
* Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
*
* \param gamecontroller The controller to vibrate
@@ -406,11 +406,24 @@ extern DECLSPEC Uint8 SDLCALL SDL_GameControllerGetButton(SDL_GameController *ga
* \param high_frequency_rumble The intensity of the high frequency (right) rumble motor, from 0 to 0xFFFF
* \param duration_ms The duration of the rumble effect, in milliseconds
*
- * \return 0, or -1 if rumble isn't supported on this joystick
+ * \return 0, or -1 if rumble isn't supported on this controller
*/
extern DECLSPEC int SDLCALL SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
/**
+ * Start a rumble effect in the game controller's triggers
+ * Each call to this function cancels any previous trigger rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ * \param gamecontroller The controller to vibrate
+ * \param left_rumble The intensity of the left trigger rumble motor, from 0 to 0xFFFF
+ * \param right_rumble The intensity of the right trigger rumble motor, from 0 to 0xFFFF
+ * \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ * \return 0, or -1 if rumble isn't supported on this controller
+ */
+extern DECLSPEC int SDLCALL SDL_GameControllerRumbleTriggers(SDL_GameController *gamecontroller, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms);
+
+/**
* Return whether a controller has an LED
*
* \param gamecontroller The controller to query
diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h
index 30790fcf9..be844e1c3 100644
--- a/include/SDL_joystick.h
+++ b/include/SDL_joystick.h
@@ -420,7 +420,7 @@ extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
int button);
/**
- * Trigger a rumble effect
+ * Start a rumble effect
* Each call to this function cancels any previous rumble effect, and calling it with 0 intensity stops any rumbling.
*
* \param joystick The joystick to vibrate
@@ -433,6 +433,19 @@ extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick,
extern DECLSPEC int SDLCALL SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
/**
+ * Start a rumble effect in the joystick's triggers
+ * Each call to this function cancels any previous trigger rumble effect, and calling it with 0 intensity stops any rumbling.
+ *
+ * \param joystick The joystick to vibrate
+ * \param left_rumble The intensity of the left trigger rumble motor, from 0 to 0xFFFF
+ * \param right_rumble The intensity of the right trigger rumble motor, from 0 to 0xFFFF
+ * \param duration_ms The duration of the rumble effect, in milliseconds
+ *
+ * \return 0, or -1 if trigger rumble isn't supported on this joystick
+ */
+extern DECLSPEC int SDLCALL SDL_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms);
+
+/**
* Return whether a joystick has an LED
*
* \param joystick The joystick to query
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 555255884..4a596a948 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -772,3 +772,5 @@
#define SDL_GameControllerSetLED SDL_GameControllerSetLED_REAL
#define SDL_JoystickHasLED SDL_JoystickHasLED_REAL
#define SDL_JoystickSetLED SDL_JoystickSetLED_REAL
+#define SDL_GameControllerRumbleTriggers SDL_GameControllerRumbleTriggers_REAL
+#define SDL_JoystickRumbleTriggers SDL_JoystickRumbleTriggers_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 1688a357e..d65153119 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -833,3 +833,5 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_GameControllerHasLED,(SDL_GameController *a),(a),re
SDL_DYNAPI_PROC(int,SDL_GameControllerSetLED,(SDL_GameController *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_JoystickHasLED,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_JoystickSetLED,(SDL_Joystick *a, Uint8 b, Uint8 c, Uint8 d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_GameControllerRumbleTriggers,(SDL_GameController *a, Uint16 b, Uint16 c, Uint32 d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_JoystickRumbleTriggers,(SDL_Joystick *a, Uint16 b, Uint16 c, Uint32 d),(a,b,c,d),return)
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index e7db9c199..9cb9d4fd3 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -2151,6 +2151,12 @@ SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequenc
return SDL_JoystickRumble(SDL_GameControllerGetJoystick(gamecontroller), low_frequency_rumble, high_frequency_rumble, duration_ms);
}
+int
+SDL_GameControllerRumbleTriggers(SDL_GameController *gamecontroller, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
+{
+ return SDL_JoystickRumbleTriggers(SDL_GameControllerGetJoystick(gamecontroller), left_rumble, right_rumble, duration_ms);
+}
+
SDL_bool
SDL_GameControllerHasLED(SDL_GameController *gamecontroller)
{
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 63ecf9340..94838f6d5 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -901,6 +901,40 @@ SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16
return result;
}
+int
+SDL_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
+{
+ int result;
+
+ if (!SDL_PrivateJoystickValid(joystick)) {
+ return -1;
+ }
+
+ SDL_LockJoysticks();
+ if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) {
+ /* Just update the expiration */
+ result = 0;
+ } else {
+ result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
+ }
+
+ /* Save the rumble value regardless of success, so we don't spam the driver */
+ joystick->left_trigger_rumble = left_rumble;
+ joystick->right_trigger_rumble = right_rumble;
+
+ if ((left_rumble || right_rumble) && duration_ms) {
+ joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
+ if (!joystick->trigger_rumble_expiration) {
+ joystick->trigger_rumble_expiration = 1;
+ }
+ } else {
+ joystick->trigger_rumble_expiration = 0;
+ }
+ SDL_UnlockJoysticks();
+
+ return result;
+}
+
SDL_bool
SDL_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -978,6 +1012,9 @@ SDL_JoystickClose(SDL_Joystick * joystick)
if (joystick->rumble_expiration) {
SDL_JoystickRumble(joystick, 0, 0, 0);
}
+ if (joystick->trigger_rumble_expiration) {
+ SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
+ }
joystick->driver->Close(joystick);
joystick->hwdata = NULL;
@@ -1437,6 +1474,16 @@ SDL_JoystickUpdate(void)
}
SDL_UnlockJoysticks();
}
+
+ if (joystick->trigger_rumble_expiration) {
+ SDL_LockJoysticks();
+ /* Double check now that the lock is held */
+ if (joystick->trigger_rumble_expiration &&
+ SDL_TICKS_PASSED(SDL_GetTicks(), joystick->trigger_rumble_expiration)) {
+ SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
+ }
+ SDL_UnlockJoysticks();
+ }
}
SDL_LockJoysticks();
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 6de1e37f3..5cf10a719 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -64,6 +64,10 @@ struct _SDL_Joystick
Uint16 high_frequency_rumble;
Uint32 rumble_expiration;
+ Uint16 left_trigger_rumble;
+ Uint16 right_trigger_rumble;
+ Uint32 trigger_rumble_expiration;
+
Uint8 led_red;
Uint8 led_green;
Uint8 led_blue;
@@ -126,6 +130,7 @@ typedef struct _SDL_JoystickDriver
/* Rumble functionality */
int (*Rumble)(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);
+ int (*RumbleTriggers)(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble);
/* LED functionality */
SDL_bool (*HasLED)(SDL_Joystick * joystick);
diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c
index 32fc1d82a..af5bf513e 100644
--- a/src/joystick/android/SDL_sysjoystick.c
+++ b/src/joystick/android/SDL_sysjoystick.c
@@ -633,6 +633,12 @@ ANDROID_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uin
return SDL_Unsupported();
}
+static int
+ANDROID_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
ANDROID_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -723,6 +729,7 @@ SDL_JoystickDriver SDL_ANDROID_JoystickDriver =
ANDROID_JoystickGetDeviceInstanceID,
ANDROID_JoystickOpen,
ANDROID_JoystickRumble,
+ ANDROID_JoystickRumbleTriggers,
ANDROID_JoystickHasLED,
ANDROID_JoystickSetLED,
ANDROID_JoystickUpdate,
diff --git a/src/joystick/bsd/SDL_sysjoystick.c b/src/joystick/bsd/SDL_sysjoystick.c
index ff5203466..c68629ae7 100644
--- a/src/joystick/bsd/SDL_sysjoystick.c
+++ b/src/joystick/bsd/SDL_sysjoystick.c
@@ -762,6 +762,12 @@ BSD_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16
return SDL_Unsupported();
}
+static int
+BSD_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
BSD_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
@@ -792,6 +798,7 @@ SDL_JoystickDriver SDL_BSD_JoystickDriver =
BSD_JoystickGetDeviceInstanceID,
BSD_JoystickOpen,
BSD_JoystickRumble,
+ BSD_JoystickRumbleTriggers,
BSD_JoystickHasLED,
BSD_JoystickSetLED,
BSD_JoystickUpdate,
diff --git a/src/joystick/darwin/SDL_sysjoystick.c b/src/joystick/darwin/SDL_sysjoystick.c
index 12b8a8fdd..408bdab67 100644
--- a/src/joystick/darwin/SDL_sysjoystick.c
+++ b/src/joystick/darwin/SDL_sysjoystick.c
@@ -922,6 +922,12 @@ DARWIN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint
return 0;
}
+static int
+DARWIN_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
DARWIN_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -1081,6 +1087,7 @@ SDL_JoystickDriver SDL_DARWIN_JoystickDriver =
DARWIN_JoystickGetDeviceInstanceID,
DARWIN_JoystickOpen,
DARWIN_JoystickRumble,
+ DARWIN_JoystickRumbleTriggers,
DARWIN_JoystickHasLED,
DARWIN_JoystickSetLED,
DARWIN_JoystickUpdate,
diff --git a/src/joystick/dummy/SDL_sysjoystick.c b/src/joystick/dummy/SDL_sysjoystick.c
index 345333f27..04d744d2d 100644
--- a/src/joystick/dummy/SDL_sysjoystick.c
+++ b/src/joystick/dummy/SDL_sysjoystick.c
@@ -89,6 +89,12 @@ DUMMY_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint1
return SDL_Unsupported();
}
+static int
+DUMMY_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
DUMMY_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -134,6 +140,7 @@ SDL_JoystickDriver SDL_DUMMY_JoystickDriver =
DUMMY_JoystickGetDeviceInstanceID,
DUMMY_JoystickOpen,
DUMMY_JoystickRumble,
+ DUMMY_JoystickRumbleTriggers,
DUMMY_JoystickHasLED,
DUMMY_JoystickSetLED,
DUMMY_JoystickUpdate,
diff --git a/src/joystick/emscripten/SDL_sysjoystick.c b/src/joystick/emscripten/SDL_sysjoystick.c
index 74727397f..74327ab3e 100644
--- a/src/joystick/emscripten/SDL_sysjoystick.c
+++ b/src/joystick/emscripten/SDL_sysjoystick.c
@@ -403,6 +403,12 @@ EMSCRIPTEN_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble,
return SDL_Unsupported();
}
+static int
+EMSCRIPTEN_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
EMSCRIPTEN_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
@@ -433,6 +439,7 @@ SDL_JoystickDriver SDL_EMSCRIPTEN_JoystickDriver =
EMSCRIPTEN_JoystickGetDeviceInstanceID,
EMSCRIPTEN_JoystickOpen,
EMSCRIPTEN_JoystickRumble,
+ EMSCRIPTEN_JoystickRumbleTriggers,
EMSCRIPTEN_JoystickHasLED,
EMSCRIPTEN_JoystickSetLED,
EMSCRIPTEN_JoystickUpdate,
diff --git a/src/joystick/haiku/SDL_haikujoystick.cc b/src/joystick/haiku/SDL_haikujoystick.cc
index ab5f743c4..6adb4da3e 100644
--- a/src/joystick/haiku/SDL_haikujoystick.cc
+++ b/src/joystick/haiku/SDL_haikujoystick.cc
@@ -259,6 +259,12 @@ extern "C"
return SDL_Unsupported();
}
+
+ static int HAIKU_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+ {
+ return SDL_Unsupported();
+ }
+
static SDL_bool
HAIKU_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
{
@@ -287,6 +293,7 @@ extern "C"
HAIKU_JoystickGetDeviceInstanceID,
HAIKU_JoystickOpen,
HAIKU_JoystickRumble,
+ HAIKU_JoystickRumbleTriggers,
HAIKU_JoystickHasLED,
HAIKU_JoystickSetLED,
HAIKU_JoystickUpdate,
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index 8c7a7bd47..61688c8b5 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -363,6 +363,12 @@ HIDAPI_DriverGameCube_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo
return -1;
}
+static int
+HIDAPI_DriverGameCube_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
HIDAPI_DriverGameCube_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -414,6 +420,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverGameCube =
HIDAPI_DriverGameCube_UpdateDevice,
HIDAPI_DriverGameCube_OpenJoystick,
HIDAPI_DriverGameCube_RumbleJoystick,
+ HIDAPI_DriverGameCube_RumbleJoystickTriggers,
HIDAPI_DriverGameCube_HasJoystickLED,
HIDAPI_DriverGameCube_SetJoystickLED,
HIDAPI_DriverGameCube_CloseJoystick,
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index ebf3a6490..1c12aa2a9 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -373,6 +373,12 @@ HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic
return 0;
}
+static int
+HIDAPI_DriverPS4_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
HIDAPI_DriverPS4_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -588,6 +594,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverPS4 =
HIDAPI_DriverPS4_UpdateDevice,
HIDAPI_DriverPS4_OpenJoystick,
HIDAPI_DriverPS4_RumbleJoystick,
+ HIDAPI_DriverPS4_RumbleJoystickTriggers,
HIDAPI_DriverPS4_HasJoystickLED,
HIDAPI_DriverPS4_SetJoystickLED,
HIDAPI_DriverPS4_CloseJoystick,
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index c7cec43de..0d9c1f208 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -923,6 +923,12 @@ HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, low_frequency_rumble, high_frequency_rumble);
}
+static int
+HIDAPI_DriverSwitch_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
HIDAPI_DriverSwitch_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -1289,6 +1295,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
HIDAPI_DriverSwitch_UpdateDevice,
HIDAPI_DriverSwitch_OpenJoystick,
HIDAPI_DriverSwitch_RumbleJoystick,
+ HIDAPI_DriverSwitch_RumbleJoystickTriggers,
HIDAPI_DriverSwitch_HasJoystickLED,
HIDAPI_DriverSwitch_SetJoystickLED,
HIDAPI_DriverSwitch_CloseJoystick,
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c
index 4ae30e4f3..77efb4c1a 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c
@@ -796,6 +796,12 @@ HIDAPI_DriverXbox360_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
return 0;
}
+static int
+HIDAPI_DriverXbox360_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
HIDAPI_DriverXbox360_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -1317,6 +1323,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 =
HIDAPI_DriverXbox360_UpdateDevice,
HIDAPI_DriverXbox360_OpenJoystick,
HIDAPI_DriverXbox360_RumbleJoystick,
+ HIDAPI_DriverXbox360_RumbleJoystickTriggers,
HIDAPI_DriverXbox360_HasJoystickLED,
HIDAPI_DriverXbox360_SetJoystickLED,
HIDAPI_DriverXbox360_CloseJoystick,
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
index 87357d215..3fe06eb2e 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
@@ -157,6 +157,12 @@ HIDAPI_DriverXbox360W_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *jo
return 0;
}
+static int
+HIDAPI_DriverXbox360W_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
HIDAPI_DriverXbox360W_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -307,6 +313,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W =
HIDAPI_DriverXbox360W_UpdateDevice,
HIDAPI_DriverXbox360W_OpenJoystick,
HIDAPI_DriverXbox360W_RumbleJoystick,
+ HIDAPI_DriverXbox360W_RumbleJoystickTriggers,
HIDAPI_DriverXbox360W_HasJoystickLED,
HIDAPI_DriverXbox360W_SetJoystickLED,
HIDAPI_DriverXbox360W_CloseJoystick,
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index ff217ded6..c98e527fd 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -350,6 +350,12 @@ HIDAPI_DriverXboxOne_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joy
return 0;
}
+static int
+HIDAPI_DriverXboxOne_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
HIDAPI_DriverXboxOne_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
@@ -887,6 +893,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne =
HIDAPI_DriverXboxOne_UpdateDevice,
HIDAPI_DriverXboxOne_OpenJoystick,
HIDAPI_DriverXboxOne_RumbleJoystick,
+ HIDAPI_DriverXboxOne_RumbleJoystickTriggers,
HIDAPI_DriverXboxOne_HasJoystickLED,
HIDAPI_DriverXboxOne_SetJoystickLED,
HIDAPI_DriverXboxOne_CloseJoystick,
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 9dcfe5c75..faf44424a 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -1071,6 +1071,23 @@ HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint
return result;
}
+static int
+HIDAPI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ int result;
+
+ if (joystick->hwdata) {
+ SDL_HIDAPI_Device *device = joystick->hwdata->device;
+
+ result = device->driver->RumbleJoystickTriggers(device, joystick, left_rumble, right_rumble);
+ } else {
+ SDL_SetError("Rumble failed, device disconnected");
+ result = -1;
+ }
+
+ return result;
+}
+
static SDL_bool
HIDAPI_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -1175,6 +1192,7 @@ SDL_JoystickDriver SDL_HIDAPI_JoystickDriver =
HIDAPI_JoystickGetDeviceInstanceID,
HIDAPI_JoystickOpen,
HIDAPI_JoystickRumble,
+ HIDAPI_JoystickRumbleTriggers,
HIDAPI_JoystickHasLED,
HIDAPI_JoystickSetLED,
HIDAPI_JoystickUpdate,
diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h
index 9a2136b7b..4ea3f6029 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick_c.h
+++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h
@@ -95,6 +95,7 @@ typedef struct _SDL_HIDAPI_DeviceDriver
SDL_bool (*UpdateDevice)(SDL_HIDAPI_Device *device);
SDL_bool (*OpenJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
int (*RumbleJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble);
+ int (*RumbleJoystickTriggers)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble);
SDL_bool (*HasJoystickLED)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
int (*SetJoystickLED)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue);
void (*CloseJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick);
diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m
index 47a911f17..57e9e9d1f 100644
--- a/src/joystick/iphoneos/SDL_sysjoystick.m
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m
@@ -1015,12 +1015,19 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
@implementation SDL_RumbleContext {
SDL_RumbleMotor *low_frequency_motor;
SDL_RumbleMotor *high_frequency_motor;
+ SDL_RumbleMotor *left_trigger_motor;
+ SDL_RumbleMotor *right_trigger_motor;
}
--(id) initWithLowFrequencyMotor:(SDL_RumbleMotor*)low_frequency_motor andHighFrequencyMotor:(SDL_RumbleMotor*)high_frequency_motor
+-(id) initWithLowFrequencyMotor:(SDL_RumbleMotor*)low_frequency_motor
+ HighFrequencyMotor:(SDL_RumbleMotor*)high_frequency_motor
+ LeftTriggerMotor:(SDL_RumbleMotor*)left_trigger_motor
+ RightTriggerMotor:(SDL_RumbleMotor*)right_trigger_motor
{
self->low_frequency_motor = low_frequency_motor;
self->high_frequency_motor = high_frequency_motor;
+ self->left_trigger_motor = left_trigger_motor;
+ self->right_trigger_motor = right_trigger_motor;
return self;
}
@@ -1033,6 +1040,19 @@ IOS_MFIJoystickUpdate(SDL_Joystick * joystick)
return ((result < 0) ? -1 : 0);
}
+-(int) rumbleLeftTrigger:(Uint16)left_rumble andRightTrigger:(Uint16)right_rumble
+{
+ int result = 0;
+
+ if (self->left_trigger_motor && self->right_trigger_motor) {
+ result += [self->left_trigger_motor setIntensity:((float)left_rumble / 65535.0f)];
+ result += [self->right_trigger_motor setIntensity:((float)right_rumble / 65535.0f)];
+ } else {
+ result = SDL_Unsupported();
+ }
+ return ((result < 0) ? -1 : 0);
+}
+
-(void)cleanup
{
[self->low_frequency_motor cleanup];
@@ -1047,8 +1067,13 @@ static SDL_RumbleContext *IOS_JoystickInitRumble(GCController *controller)
if (@available(iOS 14.0, tvOS 14.0, *)) {
SDL_RumbleMotor *low_frequency_motor = [[SDL_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityLeftHandle];
SDL_RumbleMotor *high_frequency_motor = [[SDL_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityRightHandle];
+ SDL_RumbleMotor *left_trigger_motor = [[SDL_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityLeftTrigger];
+ SDL_RumbleMotor *right_trigger_motor = [[SDL_RumbleMotor alloc] initWithController:controller locality:GCHapticsLocalityRightTrigger];
if (low_frequency_motor && high_frequency_motor) {
- return [[SDL_RumbleContext alloc] initWithLowFrequencyMotor:low_frequency_motor andHighFrequencyMotor:high_frequency_motor];
+ return [[SDL_RumbleContext alloc] initWithLowFrequencyMotor:low_frequency_motor
+ HighFrequencyMotor:high_frequency_motor
+ LeftTriggerMotor:left_trigger_motor
+ RightTriggerMotor:right_trigger_motor];
}
}
}
@@ -1083,6 +1108,32 @@ IOS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16
#endif
}
+static int
+IOS_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+#ifdef ENABLE_MFI_RUMBLE
+ SDL_JoystickDeviceItem *device = joystick->hwdata;
+
+ if (@available(iOS 14.0, tvOS 14.0, *)) {
+ if (!device->rumble && device->controller && device->controller.haptics) {
+ SDL_RumbleContext *rumble = IOS_JoystickInitRumble(device->controller);
+ if (rumble) {
+ device->rumble = (void *)CFBridgingRetain(rumble);
+ }
+ }
+ }
+
+ if (device->rumble) {
+ SDL_RumbleContext *rumble = (__bridge SDL_RumbleContext *)device->rumble;
+ return [rumble rumbleLeftTrigger:left_rumble andRightTrigger:right_rumble];
+ } else {
+ return SDL_Unsupported();
+ }
+#else
+ return SDL_Unsupported();
+#endif
+}
+
static SDL_bool
IOS_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -1230,6 +1281,7 @@ SDL_JoystickDriver SDL_IOS_JoystickDriver =
IOS_JoystickGetDeviceInstanceID,
IOS_JoystickOpen,
IOS_JoystickRumble,
+ IOS_JoystickRumbleTriggers,
IOS_JoystickHasLED,
IOS_JoystickSetLED,
IOS_JoystickUpdate,
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 4cc32f3a4..e41e5d966 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -891,6 +891,12 @@ LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint1
return 0;
}
+static int
+LINUX_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
LINUX_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -1378,6 +1384,7 @@ SDL_JoystickDriver SDL_LINUX_JoystickDriver =
LINUX_JoystickGetDeviceInstanceID,
LINUX_JoystickOpen,
LINUX_JoystickRumble,
+ LINUX_JoystickRumbleTriggers,
LINUX_JoystickHasLED,
LINUX_JoystickSetLED,
LINUX_JoystickUpdate,
diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c
index 9e34caeb4..9d441d7e8 100644
--- a/src/joystick/virtual/SDL_virtualjoystick.c
+++ b/src/joystick/virtual/SDL_virtualjoystick.c
@@ -338,6 +338,12 @@ VIRTUAL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uin
return SDL_Unsupported();
}
+static int
+VIRTUAL_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
VIRTUAL_JoystickHasLED(SDL_Joystick * joystick)
@@ -423,6 +429,7 @@ SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver =
VIRTUAL_JoystickGetDeviceInstanceID,
VIRTUAL_JoystickOpen,
VIRTUAL_JoystickRumble,
+ VIRTUAL_JoystickRumbleTriggers,
VIRTUAL_JoystickHasLED,
VIRTUAL_JoystickSetLED,
VIRTUAL_JoystickUpdate,
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index d4db0b513..02223cda4 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -614,6 +614,15 @@ RAWINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Ui
return device->driver->RumbleJoystick(&device->hiddevice, joystick, low_frequency_rumble, high_frequency_rumble);
}
+static int
+RAWINPUT_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ struct joystick_hwdata *hwdata = joystick->hwdata;
+ SDL_RAWINPUT_Device *device = hwdata->device;
+
+ return device->driver->RumbleJoystickTriggers(&device->hiddevice, joystick, low_frequency_rumble, high_frequency_rumble);
+}
+
static SDL_bool
RAWINPUT_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -756,6 +765,7 @@ SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver =
RAWINPUT_JoystickGetDeviceInstanceID,
RAWINPUT_JoystickOpen,
RAWINPUT_JoystickRumble,
+ RAWINPUT_JoystickRumbleTriggers,
RAWINPUT_JoystickHasLED,
RAWINPUT_JoystickSetLED,
RAWINPUT_JoystickUpdate,
diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c
index b1865599b..c67045069 100644
--- a/src/joystick/windows/SDL_windows_gaming_input.c
+++ b/src/joystick/windows/SDL_windows_gaming_input.c
@@ -38,6 +38,7 @@ struct joystick_hwdata
__x_ABI_CWindows_CGaming_CInput_CIGameController *gamecontroller;
__x_ABI_CWindows_CGaming_CInput_CIGameControllerBatteryInfo *battery;
__x_ABI_CWindows_CGaming_CInput_CIGamepad *gamepad;
+ __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
UINT64 timestamp;
};
@@ -559,12 +560,31 @@ WGI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16
if (hwdata->gamepad) {
HRESULT hr;
- struct __x_ABI_CWindows_CGaming_CInput_CGamepadVibration vibration;
- SDL_zero(vibration);
- vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
- vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
- hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, vibration);
+ hwdata->vibration.LeftMotor = (DOUBLE)low_frequency_rumble / SDL_MAX_UINT16;
+ hwdata->vibration.RightMotor = (DOUBLE)high_frequency_rumble / SDL_MAX_UINT16;
+ hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, hwdata->vibration);
+ if (SUCCEEDED(hr)) {
+ return 0;
+ } else {
+ return SDL_SetError("Setting vibration failed: 0x%x\n", hr);
+ }
+ } else {
+ return SDL_Unsupported();
+ }
+}
+
+static int
+WGI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ struct joystick_hwdata *hwdata = joystick->hwdata;
+
+ if (hwdata->gamepad) {
+ HRESULT hr;
+
+ hwdata->vibration.LeftTrigger = (DOUBLE)left_rumble / SDL_MAX_UINT16;
+ hwdata->vibration.RightTrigger = (DOUBLE)right_rumble / SDL_MAX_UINT16;
+ hr = __x_ABI_CWindows_CGaming_CInput_CIGamepad_put_Vibration(hwdata->gamepad, hwdata->vibration);
if (SUCCEEDED(hr)) {
return 0;
} else {
@@ -729,6 +749,7 @@ SDL_JoystickDriver SDL_WGI_JoystickDriver =
WGI_JoystickGetDeviceInstanceID,
WGI_JoystickOpen,
WGI_JoystickRumble,
+ WGI_JoystickRumbleTriggers,
WGI_JoystickHasLED,
WGI_JoystickSetLED,
WGI_JoystickUpdate,
diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c
index e37e7ddfe..b66e6c7b3 100644
--- a/src/joystick/windows/SDL_windowsjoystick.c
+++ b/src/joystick/windows/SDL_windowsjoystick.c
@@ -500,6 +500,12 @@ WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uin
}
}
+static int
+WINDOWS_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble)
+{
+ return SDL_Unsupported();
+}
+
static SDL_bool
WINDOWS_JoystickHasLED(SDL_Joystick * joystick)
{
@@ -595,6 +601,7 @@ SDL_JoystickDriver SDL_WINDOWS_JoystickDriver =
WINDOWS_JoystickGetDeviceInstanceID,
WINDOWS_JoystickOpen,
WINDOWS_JoystickRumble,
+ WINDOWS_JoystickRumbleTriggers,
WINDOWS_JoystickHasLED,
WINDOWS_JoystickSetLED,
WINDOWS_JoystickUpdate,
diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c
index 3d6a371b6..59419931e 100644
--- a/test/testgamecontroller.c
+++ b/test/testgamecontroller.c
@@ -114,6 +114,17 @@ UpdateWindowTitle()
}
}
+static Uint16 ConvertAxisToRumble(Sint16 axis)
+{
+ /* Only start rumbling if the axis is past the halfway point */
+ const int half_axis = (SDL_JOYSTICK_AXIS_MAX / 2);
+ if (axis > half_axis) {
+ return (Uint16)(axis - half_axis) * 4;
+ } else {
+ return 0;
+ }
+}
+
void
loop(void *arg)
{
@@ -227,6 +238,16 @@ loop(void *arg)
Uint16 high_frequency_rumble = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) * 2;
SDL_GameControllerRumble(gamecontroller, low_frequency_rumble, high_frequency_rumble, 250);
}
+
+ /* Update trigger rumble based on thumbstick state */
+ {
+ Sint16 left_y = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_LEFTY);
+ Sint16 right_y = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_RIGHTY);
+ Uint16 left_rumble = ConvertAxisToRumble(~left_y);
+ Uint16 right_rumble = ConvertAxisToRumble(~right_y);
+
+ SDL_GameControllerRumbleTriggers(gamecontroller, left_rumble, right_rumble, 250);
+ }
}
SDL_RenderPresent(screen);