From afccabb88183a0c7c3513223b1e026fe16233819 Mon Sep 17 00:00:00 2001
From: Cameron Gutman <[EMAIL REDACTED]>
Date: Thu, 11 Nov 2021 12:12:05 -0600
Subject: [PATCH] joystick: Add capability flags for rumble and trigger rumble
When API limitations force us to guess, we favor a false positive (reporting
support when it doesn't exist) compared to a false negative.
---
src/joystick/SDL_sysjoystick.h | 2 ++
src/joystick/darwin/SDL_iokitjoystick.c | 13 +++++++++-
src/joystick/hidapi/SDL_hidapi_gamecube.c | 18 +++++++++++++-
src/joystick/hidapi/SDL_hidapi_luna.c | 8 ++++++-
src/joystick/hidapi/SDL_hidapi_ps4.c | 9 ++++++-
src/joystick/hidapi/SDL_hidapi_ps5.c | 9 ++++++-
src/joystick/hidapi/SDL_hidapi_stadia.c | 2 +-
src/joystick/hidapi/SDL_hidapi_switch.c | 11 +++++++--
src/joystick/hidapi/SDL_hidapi_xbox360.c | 2 +-
src/joystick/hidapi/SDL_hidapi_xbox360w.c | 2 +-
src/joystick/hidapi/SDL_hidapi_xboxone.c | 5 ++++
src/joystick/iphoneos/SDL_mfijoystick.m | 19 +++++++++++----
src/joystick/linux/SDL_sysjoystick.c | 8 ++++++-
src/joystick/vita/SDL_sysjoystick.c | 4 ++--
src/joystick/windows/SDL_dinputjoystick.c | 8 ++++++-
src/joystick/windows/SDL_rawinputjoystick.c | 24 +++++++++++++++++++
.../windows/SDL_windows_gaming_input.c | 9 ++++++-
src/joystick/windows/SDL_xinputjoystick.c | 2 +-
18 files changed, 135 insertions(+), 20 deletions(-)
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index e897c44b0b..dff6b3692d 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -123,6 +123,8 @@ struct _SDL_Joystick
/* Joystick capability flags for GetCapabilities() */
#define SDL_JOYCAP_LED 0x01
+#define SDL_JOYCAP_RUMBLE 0x02
+#define SDL_JOYCAP_RUMBLE_TRIGGERS 0x04
/* Macro to combine a USB vendor ID and product ID into a single Uint32 value */
#define MAKE_VIDPID(VID, PID) (((Uint32)(VID))<<16|(PID))
diff --git a/src/joystick/darwin/SDL_iokitjoystick.c b/src/joystick/darwin/SDL_iokitjoystick.c
index ee02891f91..1d5b80a301 100644
--- a/src/joystick/darwin/SDL_iokitjoystick.c
+++ b/src/joystick/darwin/SDL_iokitjoystick.c
@@ -942,7 +942,18 @@ DARWIN_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16
static Uint32
DARWIN_JoystickGetCapabilities(SDL_Joystick *joystick)
{
- return 0;
+ recDevice *device = joystick->hwdata;
+ Uint32 result = 0;
+
+ if (!device) {
+ return 0;
+ }
+
+ if (device->ffservice) {
+ result |= SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_gamecube.c b/src/joystick/hidapi/SDL_hidapi_gamecube.c
index 9fc3ff7914..2b6f7b9d8e 100644
--- a/src/joystick/hidapi/SDL_hidapi_gamecube.c
+++ b/src/joystick/hidapi/SDL_hidapi_gamecube.c
@@ -467,7 +467,23 @@ HIDAPI_DriverGameCube_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joys
static Uint32
HIDAPI_DriverGameCube_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
- return 0;
+ SDL_DriverGameCube_Context *ctx = (SDL_DriverGameCube_Context *)device->context;
+ Uint32 result = 0;
+
+ if (!ctx->pc_mode) {
+ Uint8 i;
+
+ for (i = 0; i < MAX_CONTROLLERS; i += 1) {
+ if (joystick->instance_id == ctx->joysticks[i]) {
+ if (!ctx->wireless[i] && ctx->rumbleAllowed[i]) {
+ result |= SDL_JOYCAP_RUMBLE;
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_luna.c b/src/joystick/hidapi/SDL_hidapi_luna.c
index 48de69f5ac..90d50d41ef 100644
--- a/src/joystick/hidapi/SDL_hidapi_luna.c
+++ b/src/joystick/hidapi/SDL_hidapi_luna.c
@@ -135,7 +135,13 @@ HIDAPI_DriverLuna_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick
static Uint32
HIDAPI_DriverLuna_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
- return 0;
+ Uint32 result = 0;
+
+ if (device->product_id == BLUETOOTH_PRODUCT_LUNA_CONTROLLER) {
+ result |= SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index 7bd2434f62..b6df375c8b 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -601,7 +601,14 @@ HIDAPI_DriverPS4_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick
static Uint32
HIDAPI_DriverPS4_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
- return SDL_JOYCAP_LED;
+ SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context;
+ Uint32 result = 0;
+
+ if (ctx->enhanced_mode && ctx->effects_supported) {
+ result |= SDL_JOYCAP_LED | SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index ff8fc66a0a..c52c6df89d 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -666,7 +666,14 @@ HIDAPI_DriverPS5_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joystick
static Uint32
HIDAPI_DriverPS5_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
- return SDL_JOYCAP_LED;
+ SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
+ Uint32 result = 0;
+
+ if (ctx->enhanced_mode) {
+ result |= SDL_JOYCAP_LED | SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_stadia.c b/src/joystick/hidapi/SDL_hidapi_stadia.c
index f6ddd350ef..0df431555a 100644
--- a/src/joystick/hidapi/SDL_hidapi_stadia.c
+++ b/src/joystick/hidapi/SDL_hidapi_stadia.c
@@ -129,7 +129,7 @@ HIDAPI_DriverStadia_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joysti
static Uint32
HIDAPI_DriverStadia_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
- return 0;
+ return SDL_JOYCAP_RUMBLE;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index a12aa267da..9341d1d8f8 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -1109,8 +1109,15 @@ HIDAPI_DriverSwitch_RumbleJoystickTriggers(SDL_HIDAPI_Device *device, SDL_Joysti
static Uint32
HIDAPI_DriverSwitch_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
- /* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
- return 0;
+ SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
+ Uint32 result = 0;
+
+ if (!ctx->m_bInputOnly) {
+ /* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
+ result |= SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c
index 13911ff620..39cbbfa99b 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c
@@ -207,7 +207,7 @@ static Uint32
HIDAPI_DriverXbox360_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
/* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
- return 0;
+ return SDL_JOYCAP_RUMBLE;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
index 9603e32e9e..ae8bbdcafd 100644
--- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c
+++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c
@@ -177,7 +177,7 @@ static Uint32
HIDAPI_DriverXbox360W_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{
/* Doesn't have an RGB LED, so don't return SDL_JOYCAP_LED here */
- return 0;
+ return SDL_JOYCAP_RUMBLE;
}
static int
diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c
index a96740541e..097deac5bd 100644
--- a/src/joystick/hidapi/SDL_hidapi_xboxone.c
+++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c
@@ -428,6 +428,11 @@ HIDAPI_DriverXboxOne_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joys
SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context;
Uint32 result = 0;
+ result |= SDL_JOYCAP_RUMBLE;
+ if (ctx->has_trigger_rumble) {
+ result |= SDL_JOYCAP_RUMBLE_TRIGGERS;
+ }
+
if (ctx->has_color_led) {
result |= SDL_JOYCAP_LED;
}
diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m
index e15df71a25..08ed418a10 100644
--- a/src/joystick/iphoneos/SDL_mfijoystick.m
+++ b/src/joystick/iphoneos/SDL_mfijoystick.m
@@ -1331,7 +1331,6 @@ -(void)cleanup
{
Uint32 result = 0;
-#ifdef ENABLE_MFI_LIGHT
@autoreleasepool {
SDL_JoystickDeviceItem *device = joystick->hwdata;
@@ -1341,13 +1340,25 @@ -(void)cleanup
if (@available(macos 11.0, iOS 14.0, tvOS 14.0, *)) {
GCController *controller = device->controller;
- GCDeviceLight *light = controller.light;
- if (light) {
+#ifdef ENABLE_MFI_LIGHT
+ if (controller.light) {
result |= SDL_JOYCAP_LED;
}
+#endif /* ENABLE_MFI_LIGHT */
+
+#ifdef ENABLE_MFI_RUMBLE
+ if (controller.haptics) {
+ for (GCHapticsLocality locality in controller.haptics.supportedLocalities) {
+ if ([locality isEqualToString:GCHapticsLocalityHandles]) {
+ result |= SDL_JOYCAP_RUMBLE;
+ } else if ([locality isEqualToString:GCHapticsLocalityTriggers]) {
+ result |= SDL_JOYCAP_RUMBLE_TRIGGERS;
+ }
+ }
+ }
+#endif /* ENABLE_MFI_RUMBLE */
}
}
-#endif /* ENABLE_MFI_LIGHT */
return result;
}
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index f04924884c..56019cc8fe 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -1193,7 +1193,13 @@ LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16
static Uint32
LINUX_JoystickGetCapabilities(SDL_Joystick *joystick)
{
- return 0;
+ Uint32 result = 0;
+
+ if (joystick->hwdata->ff_rumble || joystick->hwdata->ff_sine) {
+ result |= SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static int
diff --git a/src/joystick/vita/SDL_sysjoystick.c b/src/joystick/vita/SDL_sysjoystick.c
index 1d80207a42..387679f366 100644
--- a/src/joystick/vita/SDL_sysjoystick.c
+++ b/src/joystick/vita/SDL_sysjoystick.c
@@ -368,8 +368,8 @@ VITA_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right)
static Uint32
VITA_JoystickGetCapabilities(SDL_Joystick *joystick)
{
- // always return LED supported for now
- return SDL_JOYCAP_LED;
+ // always return LED and rumble supported for now
+ return SDL_JOYCAP_LED | SDL_JOYCAP_RUMBLE;
}
diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c
index 43a5b49f44..16deb512a9 100644
--- a/src/joystick/windows/SDL_dinputjoystick.c
+++ b/src/joystick/windows/SDL_dinputjoystick.c
@@ -927,7 +927,13 @@ SDL_DINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble,
Uint32
SDL_DINPUT_JoystickGetCapabilities(SDL_Joystick * joystick)
{
- return 0;
+ Uint32 result = 0;
+
+ if (joystick->hwdata->Capabilities.dwFlags & DIDC_FORCEFEEDBACK) {
+ result |= SDL_JOYCAP_RUMBLE;
+ }
+
+ return result;
}
static Uint8
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index d66fe00d32..5765686abb 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -40,6 +40,7 @@
#include "SDL_timer.h"
#include "../usb_ids.h"
#include "../SDL_sysjoystick.h"
+#include "../controller_type.h"
#include "../../core/windows/SDL_windows.h"
#include "../../core/windows/SDL_hid.h"
#include "../hidapi/SDL_hidapijoystick_c.h"
@@ -102,6 +103,7 @@ typedef struct _SDL_RAWINPUT_Device
Uint16 version;
SDL_JoystickGUID guid;
SDL_bool is_xinput;
+ SDL_bool is_xboxone;
PHIDP_PREPARSED_DATA preparsed_data;
HANDLE hDevice;
@@ -114,6 +116,7 @@ typedef struct _SDL_RAWINPUT_Device
struct joystick_hwdata
{
SDL_bool is_xinput;
+ SDL_bool is_xboxone;
PHIDP_PREPARSED_DATA preparsed_data;
ULONG max_data_length;
HIDP_DATA *data;
@@ -705,6 +708,7 @@ RAWINPUT_AddDevice(HANDLE hDevice)
device->product_id = (Uint16)rdi.hid.dwProductId;
device->version = (Uint16)rdi.hid.dwVersionNumber;
device->is_xinput = SDL_TRUE;
+ device->is_xboxone = GuessControllerType(device->vendor_id, device->product_id) == k_eControllerType_XBoxOneController;
{
const Uint16 vendor = device->vendor_id;
@@ -1054,6 +1058,7 @@ RAWINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
}
ctx->is_xinput = device->is_xinput;
+ ctx->is_xboxone = device->is_xboxone;
ctx->preparsed_data = device->preparsed_data;
ctx->max_data_length = SDL_HidP_MaxDataListLength(HidP_Input, ctx->preparsed_data);
ctx->data = (HIDP_DATA *)SDL_malloc(ctx->max_data_length * sizeof(*ctx->data));
@@ -1280,6 +1285,25 @@ RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
static Uint32
RAWINPUT_JoystickGetCapabilities(SDL_Joystick *joystick)
{
+ RAWINPUT_DeviceContext *ctx = joystick->hwdata;
+ Uint32 result = 0;
+
+#ifdef SDL_JOYSTICK_RAWINPUT_XINPUT
+ if (ctx->is_xinput) {
+ result |= SDL_JOYCAP_RUMBLE;
+ }
+#endif
+
+#ifdef SDL_JOYSTICK_RAWINPUT_WGI
+ if (ctx->is_xinput) {
+ result |= SDL_JOYCAP_RUMBLE;
+
+ if (ctx->is_xboxone) {
+ result |= SDL_JOYCAP_RUMBLE_TRIGGERS;
+ }
+ }
+#endif
+
return 0;
}
diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c
index 475b6cdcb1..33b4eb5a0b 100644
--- a/src/joystick/windows/SDL_windows_gaming_input.c
+++ b/src/joystick/windows/SDL_windows_gaming_input.c
@@ -668,7 +668,14 @@ WGI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 ri
static Uint32
WGI_JoystickGetCapabilities(SDL_Joystick *joystick)
{
- return 0;
+ struct joystick_hwdata *hwdata = joystick->hwdata;
+
+ if (hwdata->gamepad) {
+ /* FIXME: Can WGI even tell us if trigger rumble is supported? */
+ return SDL_JOYCAP_RUMBLE | SDL_JOYCAP_RUMBLE_TRIGGERS;
+ } else {
+ return 0;
+ }
}
static int
diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c
index 350cace31f..b265e3fba5 100644
--- a/src/joystick/windows/SDL_xinputjoystick.c
+++ b/src/joystick/windows/SDL_xinputjoystick.c
@@ -506,7 +506,7 @@ SDL_XINPUT_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble,
Uint32
SDL_XINPUT_JoystickGetCapabilities(SDL_Joystick * joystick)
{
- return 0;
+ return SDL_JOYCAP_RUMBLE;
}
void