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 @@ IOS_JoystickGetCapabilities(SDL_Joystick *joystick) { Uint32 result = 0; -#ifdef ENABLE_MFI_LIGHT @autoreleasepool { SDL_JoystickDeviceItem *device = joystick->hwdata; @@ -1341,13 +1340,25 @@ IOS_JoystickGetCapabilities(SDL_Joystick *joystick) 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