From d135c0762f11c29eb9cce377648f25e5a91b4522 Mon Sep 17 00:00:00 2001 From: Sam Lantinga 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 728e749ad..2248fb730 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 c9cb92329..56f1c8efd 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 99662c036..165fa09eb 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 17e7eb317..a1251e807 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 97b7b78a2..87663f57f 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 9a0038bf1..dea2aab3d 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 749c6efd2..bf6361502 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 4d7624f9b..a4efdc1bc 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 57c44ba40..8735b4dff 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 2232e1456..d377183b0 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 3fab5d81a..c6947c725 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 5e23e4bfb..bbd481d49 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 cd27dce48..687dd4995 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 9d6ddd80b..e4407f063 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 62e4213bb..e39b56848 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 eda3ebade..a32e88fe5 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); + SDL_zero(effects); - 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]; - - 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); + 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)); - } - - 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 6df4acec1..232435f53 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_RumbleJoystickTriggers, HIDAPI_DriverPS5_HasJoystickLED, HIDAPI_DriverPS5_SetJoystickLED, + HIDAPI_DriverPS5_SendJoystickEffect, HIDAPI_DriverPS5_SetJoystickSensorsEnabled, HIDAPI_DriverPS5_CloseJoystick, HIDAPI_DriverPS5_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapi_stadia.c b/src/joystick/hidapi/SDL_hidapi_stadia.c index e11d249e6..896b480cf 100644 --- a/src/joystick/hidapi/SDL_hidapi_stadia.c +++ b/src/joystick/hidapi/SDL_hidapi_stadia.c @@ -141,6 +141,12 @@ HIDAPI_DriverStadia_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joys return SDL_Unsupported(); } +static int +HIDAPI_DriverStadia_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int HIDAPI_DriverStadia_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { @@ -314,6 +320,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverStadia = HIDAPI_DriverStadia_RumbleJoystickTriggers, HIDAPI_DriverStadia_HasJoystickLED, HIDAPI_DriverStadia_SetJoystickLED, + HIDAPI_DriverStadia_SendJoystickEffect, HIDAPI_DriverStadia_SetJoystickSensorsEnabled, HIDAPI_DriverStadia_CloseJoystick, HIDAPI_DriverStadia_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c index 74042400e..cf8463f6e 100644 --- a/src/joystick/hidapi/SDL_hidapi_steam.c +++ b/src/joystick/hidapi/SDL_hidapi_steam.c @@ -1058,6 +1058,12 @@ HIDAPI_DriverSteam_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joyst return SDL_Unsupported(); } +static int +HIDAPI_DriverSteam_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int HIDAPI_DriverSteam_SetSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { @@ -1207,6 +1213,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSteam = HIDAPI_DriverSteam_RumbleJoystickTriggers, HIDAPI_DriverSteam_HasJoystickLED, HIDAPI_DriverSteam_SetJoystickLED, + HIDAPI_DriverSteam_SendJoystickEffect, HIDAPI_DriverSteam_SetSensorsEnabled, HIDAPI_DriverSteam_CloseJoystick, HIDAPI_DriverSteam_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 5df45fa34..e01014601 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -1052,6 +1052,12 @@ HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joys return SDL_Unsupported(); } +static int +HIDAPI_DriverSwitch_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { @@ -1497,6 +1503,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch = HIDAPI_DriverSwitch_RumbleJoystickTriggers, HIDAPI_DriverSwitch_HasJoystickLED, HIDAPI_DriverSwitch_SetJoystickLED, + HIDAPI_DriverSwitch_SendJoystickEffect, HIDAPI_DriverSwitch_SetJoystickSensorsEnabled, HIDAPI_DriverSwitch_CloseJoystick, HIDAPI_DriverSwitch_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c index f6c5cbe26..4914fdaf1 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c @@ -216,6 +216,12 @@ HIDAPI_DriverXbox360_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joy return SDL_Unsupported(); } +static int +HIDAPI_DriverXbox360_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int HIDAPI_DriverXbox360_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { @@ -342,6 +348,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360 = HIDAPI_DriverXbox360_RumbleJoystickTriggers, HIDAPI_DriverXbox360_HasJoystickLED, HIDAPI_DriverXbox360_SetJoystickLED, + HIDAPI_DriverXbox360_SendJoystickEffect, HIDAPI_DriverXbox360_SetJoystickSensorsEnabled, HIDAPI_DriverXbox360_CloseJoystick, HIDAPI_DriverXbox360_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c index c69727e7a..247490930 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c @@ -186,6 +186,12 @@ HIDAPI_DriverXbox360W_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *jo return SDL_Unsupported(); } +static int +HIDAPI_DriverXbox360W_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { @@ -339,6 +345,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXbox360W = HIDAPI_DriverXbox360W_RumbleJoystickTriggers, HIDAPI_DriverXbox360W_HasJoystickLED, HIDAPI_DriverXbox360W_SetJoystickLED, + HIDAPI_DriverXbox360W_SendJoystickEffect, HIDAPI_DriverXbox360W_SetJoystickSensorsEnabled, HIDAPI_DriverXbox360W_CloseJoystick, HIDAPI_DriverXbox360W_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index 12d78078c..0f3c49d42 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.c @@ -439,6 +439,12 @@ HIDAPI_DriverXboxOne_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joy return SDL_Unsupported(); } +static int +HIDAPI_DriverXboxOne_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled) { @@ -1078,6 +1084,7 @@ SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverXboxOne = HIDAPI_DriverXboxOne_RumbleJoystickTriggers, HIDAPI_DriverXboxOne_HasJoystickLED, HIDAPI_DriverXboxOne_SetJoystickLED, + HIDAPI_DriverXboxOne_SendJoystickEffect, HIDAPI_DriverXboxOne_SetJoystickSensorsEnabled, HIDAPI_DriverXboxOne_CloseJoystick, HIDAPI_DriverXboxOne_FreeDevice, diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c index 4fce702cc..c8f34c203 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick.c +++ b/src/joystick/hidapi/SDL_hidapijoystick.c @@ -565,7 +565,7 @@ HIDAPI_RemapVal(float val, float val_min, float val_max, float output_min, float } static void HIDAPI_JoystickDetect(void); -static void HIDAPI_JoystickClose(SDL_Joystick * joystick); +static void HIDAPI_JoystickClose(SDL_Joystick *joystick); static SDL_bool HIDAPI_IsDeviceSupported(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) @@ -1269,7 +1269,7 @@ HIDAPI_JoystickGetDeviceInstanceID(int device_index) } static int -HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index) +HIDAPI_JoystickOpen(SDL_Joystick *joystick, int device_index) { SDL_JoystickID joystickID; SDL_HIDAPI_Device *device = HIDAPI_GetDeviceByIndex(device_index, &joystickID); @@ -1295,7 +1295,7 @@ HIDAPI_JoystickOpen(SDL_Joystick * joystick, int device_index) } static int -HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +HIDAPI_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { int result; @@ -1312,7 +1312,7 @@ HIDAPI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint } static int -HIDAPI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +HIDAPI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { int result; @@ -1329,7 +1329,7 @@ HIDAPI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint1 } static SDL_bool -HIDAPI_JoystickHasLED(SDL_Joystick * joystick) +HIDAPI_JoystickHasLED(SDL_Joystick *joystick) { SDL_bool result = SDL_FALSE; @@ -1343,7 +1343,7 @@ HIDAPI_JoystickHasLED(SDL_Joystick * joystick) } static int -HIDAPI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +HIDAPI_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { int result; @@ -1360,7 +1360,24 @@ HIDAPI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blu } static int -HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick * joystick, SDL_bool enabled) +HIDAPI_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + int result; + + if (joystick->hwdata) { + SDL_HIDAPI_Device *device = joystick->hwdata->device; + + result = device->driver->SendJoystickEffect(device, joystick, data, size); + } else { + SDL_SetError("SendEffect failed, device disconnected"); + result = -1; + } + + return result; +} + +static int +HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { int result; @@ -1377,13 +1394,13 @@ HIDAPI_JoystickSetSensorsEnabled(SDL_Joystick * joystick, SDL_bool enabled) } static void -HIDAPI_JoystickUpdate(SDL_Joystick * joystick) +HIDAPI_JoystickUpdate(SDL_Joystick *joystick) { /* This is handled in SDL_HIDAPI_UpdateDevices() */ } static void -HIDAPI_JoystickClose(SDL_Joystick * joystick) +HIDAPI_JoystickClose(SDL_Joystick *joystick) { if (joystick->hwdata) { SDL_HIDAPI_Device *device = joystick->hwdata->device; @@ -1470,6 +1487,7 @@ SDL_JoystickDriver SDL_HIDAPI_JoystickDriver = HIDAPI_JoystickRumbleTriggers, HIDAPI_JoystickHasLED, HIDAPI_JoystickSetLED, + HIDAPI_JoystickSendEffect, HIDAPI_JoystickSetSensorsEnabled, HIDAPI_JoystickUpdate, HIDAPI_JoystickClose, diff --git a/src/joystick/hidapi/SDL_hidapijoystick_c.h b/src/joystick/hidapi/SDL_hidapijoystick_c.h index 642c316e4..b80c6be4b 100644 --- a/src/joystick/hidapi/SDL_hidapijoystick_c.h +++ b/src/joystick/hidapi/SDL_hidapijoystick_c.h @@ -99,6 +99,7 @@ typedef struct _SDL_HIDAPI_DeviceDriver 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); + int (*SendJoystickEffect)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *data, int size); int (*SetJoystickSensorsEnabled)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled); void (*CloseJoystick)(SDL_HIDAPI_Device *device, SDL_Joystick *joystick); void (*FreeDevice)(SDL_HIDAPI_Device *device); diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m index 1a192ff8b..654f4967a 100644 --- a/src/joystick/iphoneos/SDL_mfijoystick.m +++ b/src/joystick/iphoneos/SDL_mfijoystick.m @@ -1283,6 +1283,12 @@ IOS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) return SDL_Unsupported(); } +static int +IOS_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int IOS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { @@ -1434,6 +1440,7 @@ SDL_JoystickDriver SDL_IOS_JoystickDriver = IOS_JoystickRumbleTriggers, IOS_JoystickHasLED, IOS_JoystickSetLED, + IOS_JoystickSendEffect, IOS_JoystickSetSensorsEnabled, IOS_JoystickUpdate, IOS_JoystickClose, diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c index 25146d10a..f0c2d5ce5 100644 --- a/src/joystick/linux/SDL_sysjoystick.c +++ b/src/joystick/linux/SDL_sysjoystick.c @@ -1089,6 +1089,12 @@ LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) return SDL_Unsupported(); } +static int +LINUX_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { @@ -1603,6 +1609,7 @@ SDL_JoystickDriver SDL_LINUX_JoystickDriver = LINUX_JoystickRumbleTriggers, LINUX_JoystickHasLED, LINUX_JoystickSetLED, + LINUX_JoystickSendEffect, LINUX_JoystickSetSensorsEnabled, LINUX_JoystickUpdate, LINUX_JoystickClose, diff --git a/src/joystick/os2/SDL_os2joystick.c b/src/joystick/os2/SDL_os2joystick.c index 402dac078..a3683123a 100644 --- a/src/joystick/os2/SDL_os2joystick.c +++ b/src/joystick/os2/SDL_os2joystick.c @@ -484,6 +484,11 @@ static int OS2_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Ui return SDL_Unsupported(); } +static int OS2_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int OS2_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); @@ -777,6 +782,7 @@ SDL_JoystickDriver SDL_OS2_JoystickDriver = OS2_JoystickRumbleTriggers, OS2_JoystickHasLED, OS2_JoystickSetLED, + OS2_JoystickSendEffect, OS2_JoystickSetSensorsEnabled, OS2_JoystickUpdate, OS2_JoystickClose, diff --git a/src/joystick/psp/SDL_sysjoystick.c b/src/joystick/psp/SDL_sysjoystick.c index f80646561..bea3f610c 100644 --- a/src/joystick/psp/SDL_sysjoystick.c +++ b/src/joystick/psp/SDL_sysjoystick.c @@ -220,6 +220,12 @@ PSP_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) return SDL_Unsupported(); } +static int +PSP_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int PSP_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); @@ -307,6 +313,7 @@ SDL_JoystickDriver SDL_PSP_JoystickDriver = PSP_JoystickRumbleTriggers, PSP_JoystickHasLED, PSP_JoystickSetLED, + PSP_JoystickSendEffect, PSP_JoystickSetSensorsEnabled, PSP_JoystickUpdate, PSP_JoystickClose, diff --git a/src/joystick/virtual/SDL_virtualjoystick.c b/src/joystick/virtual/SDL_virtualjoystick.c index be32b2de1..2971efc35 100644 --- a/src/joystick/virtual/SDL_virtualjoystick.c +++ b/src/joystick/virtual/SDL_virtualjoystick.c @@ -164,7 +164,7 @@ SDL_JoystickDetachVirtualInner(int device_index) int -SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value) +SDL_JoystickSetVirtualAxisInner(SDL_Joystick *joystick, int axis, Sint16 value) { joystick_hwdata *hwdata; @@ -189,7 +189,7 @@ SDL_JoystickSetVirtualAxisInner(SDL_Joystick * joystick, int axis, Sint16 value) int -SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick, int button, Uint8 value) +SDL_JoystickSetVirtualButtonInner(SDL_Joystick *joystick, int button, Uint8 value) { joystick_hwdata *hwdata; @@ -214,7 +214,7 @@ SDL_JoystickSetVirtualButtonInner(SDL_Joystick * joystick, int button, Uint8 val int -SDL_JoystickSetVirtualHatInner(SDL_Joystick * joystick, int hat, Uint8 value) +SDL_JoystickSetVirtualHatInner(SDL_Joystick *joystick, int hat, Uint8 value) { joystick_hwdata *hwdata; @@ -313,7 +313,7 @@ VIRTUAL_JoystickGetDeviceInstanceID(int device_index) static int -VIRTUAL_JoystickOpen(SDL_Joystick * joystick, int device_index) +VIRTUAL_JoystickOpen(SDL_Joystick *joystick, int device_index) { joystick_hwdata *hwdata = VIRTUAL_HWDataForIndex(device_index); if (!hwdata) { @@ -333,27 +333,33 @@ VIRTUAL_JoystickOpen(SDL_Joystick * joystick, int device_index) static int -VIRTUAL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +VIRTUAL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { return SDL_Unsupported(); } static int -VIRTUAL_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +VIRTUAL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } static SDL_bool -VIRTUAL_JoystickHasLED(SDL_Joystick * joystick) +VIRTUAL_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -VIRTUAL_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +VIRTUAL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +VIRTUAL_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) { return SDL_Unsupported(); } @@ -366,7 +372,7 @@ VIRTUAL_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) static void -VIRTUAL_JoystickUpdate(SDL_Joystick * joystick) +VIRTUAL_JoystickUpdate(SDL_Joystick *joystick) { joystick_hwdata *hwdata; int i; @@ -393,7 +399,7 @@ VIRTUAL_JoystickUpdate(SDL_Joystick * joystick) static void -VIRTUAL_JoystickClose(SDL_Joystick * joystick) +VIRTUAL_JoystickClose(SDL_Joystick *joystick) { joystick_hwdata *hwdata; @@ -438,6 +444,7 @@ SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver = VIRTUAL_JoystickRumbleTriggers, VIRTUAL_JoystickHasLED, VIRTUAL_JoystickSetLED, + VIRTUAL_JoystickSendEffect, VIRTUAL_JoystickSetSensorsEnabled, VIRTUAL_JoystickUpdate, VIRTUAL_JoystickClose, diff --git a/src/joystick/vita/SDL_sysjoystick.c b/src/joystick/vita/SDL_sysjoystick.c index 13439cad7..1704c31c5 100644 --- a/src/joystick/vita/SDL_sysjoystick.c +++ b/src/joystick/vita/SDL_sysjoystick.c @@ -347,7 +347,7 @@ SDL_JoystickGUID VITA_JoystickGetDeviceGUID( int device_index ) } static int -VITA_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +VITA_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { int index = (int) SDL_JoystickInstanceID(joystick); SceCtrlActuator act; @@ -360,13 +360,13 @@ VITA_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 } static int -VITA_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left, Uint16 right) +VITA_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) { return SDL_Unsupported(); } static SDL_bool -VITA_JoystickHasLED(SDL_Joystick * joystick) +VITA_JoystickHasLED(SDL_Joystick *joystick) { // always return true for now return SDL_TRUE; @@ -374,13 +374,19 @@ VITA_JoystickHasLED(SDL_Joystick * joystick) static int -VITA_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +VITA_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { int index = (int) SDL_JoystickInstanceID(joystick); sceCtrlSetLightBar(ext_port_map[index], red, green, blue); return 0; } +static int +VITA_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int VITA_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { @@ -405,6 +411,7 @@ SDL_JoystickDriver SDL_VITA_JoystickDriver = VITA_JoystickHasLED, VITA_JoystickSetLED, + VITA_JoystickSendEffect, VITA_JoystickSetSensorsEnabled, VITA_JoystickUpdate, diff --git a/src/joystick/windows/SDL_mmjoystick.c b/src/joystick/windows/SDL_mmjoystick.c index 79ac67f90..613c4068d 100644 --- a/src/joystick/windows/SDL_mmjoystick.c +++ b/src/joystick/windows/SDL_mmjoystick.c @@ -244,7 +244,7 @@ static SDL_JoystickID WINMM_JoystickGetDeviceInstanceID(int device_index) It returns 0, or -1 if there is an error. */ static int -WINMM_JoystickOpen(SDL_Joystick * joystick, int device_index) +WINMM_JoystickOpen(SDL_Joystick *joystick, int device_index) { int index, i; int caps_flags[MAX_AXES - 2] = @@ -345,6 +345,12 @@ WINMM_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) return SDL_Unsupported(); } +static int +WINMM_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int WINMM_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { return SDL_Unsupported(); @@ -356,7 +362,7 @@ static int WINMM_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enab * and update joystick device state. */ static void -WINMM_JoystickUpdate(SDL_Joystick * joystick) +WINMM_JoystickUpdate(SDL_Joystick *joystick) { MMRESULT result; int i; @@ -414,7 +420,7 @@ WINMM_JoystickUpdate(SDL_Joystick * joystick) /* Function to close a joystick after use */ static void -WINMM_JoystickClose(SDL_Joystick * joystick) +WINMM_JoystickClose(SDL_Joystick *joystick) { SDL_free(joystick->hwdata); } @@ -496,6 +502,7 @@ SDL_JoystickDriver SDL_WINMM_JoystickDriver = WINMM_JoystickRumbleTriggers, WINMM_JoystickHasLED, WINMM_JoystickSetLED, + WINMM_JoystickSendEffect, WINMM_JoystickSetSensorsEnabled, WINMM_JoystickUpdate, WINMM_JoystickClose, diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c index e6d3318dd..f323b379f 100644 --- a/src/joystick/windows/SDL_rawinputjoystick.c +++ b/src/joystick/windows/SDL_rawinputjoystick.c @@ -1289,6 +1289,12 @@ RAWINPUT_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 bl return SDL_Unsupported(); } +static int +RAWINPUT_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ + return SDL_Unsupported(); +} + static int RAWINPUT_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { @@ -1924,6 +1930,7 @@ SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver = RAWINPUT_JoystickRumbleTriggers, RAWINPUT_JoystickHasLED, RAWINPUT_JoystickSetLED, + RAWINPUT_JoystickSendEffect, RAWINPUT_JoystickSetSensorsEnabled, RAWINPUT_JoystickUpdate, RAWINPUT_JoystickClose, diff --git a/src/joystick/windows/SDL_windows_gaming_input.c b/src/joystick/windows/SDL_windows_gaming_input.c index 2fd36cd50..d6d0e7f89 100644 --- a/src/joystick/windows/SDL_windows_gaming_input.c +++ b/src/joystick/windows/SDL_windows_gaming_input.c @@ -486,7 +486,7 @@ WGI_JoystickGetDeviceInstanceID(int device_index) } static int -WGI_JoystickOpen(SDL_Joystick * joystick, int device_index) +WGI_JoystickOpen(SDL_Joystick *joystick, int device_index) { WindowsGamingInputControllerState *state = &wgi.controllers[device_index]; struct joystick_hwdata *hwdata; @@ -558,7 +558,7 @@ WGI_JoystickOpen(SDL_Joystick * joystick, int device_index) } static int -WGI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +WGI_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { struct joystick_hwdata *hwdata = joystick->hwdata; @@ -579,7 +579,7 @@ WGI_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 } static int -WGI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +WGI_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { struct joystick_hwdata *hwdata = joystick->hwdata; @@ -600,13 +600,19 @@ WGI_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 r } static SDL_bool -WGI_JoystickHasLED(SDL_Joystick * joystick) +WGI_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -WGI_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +WGI_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +WGI_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) { return SDL_Unsupported(); } @@ -643,7 +649,7 @@ ConvertHatValue(__x_ABI_CWindows_CGaming_CInput_CGameControllerSwitchPosition va } static void -WGI_JoystickUpdate(SDL_Joystick * joystick) +WGI_JoystickUpdate(SDL_Joystick *joystick) { struct joystick_hwdata *hwdata = joystick->hwdata; HRESULT hr; @@ -677,7 +683,7 @@ WGI_JoystickUpdate(SDL_Joystick * joystick) } static void -WGI_JoystickClose(SDL_Joystick * joystick) +WGI_JoystickClose(SDL_Joystick *joystick) { struct joystick_hwdata *hwdata = joystick->hwdata; @@ -762,6 +768,7 @@ SDL_JoystickDriver SDL_WGI_JoystickDriver = WGI_JoystickRumbleTriggers, WGI_JoystickHasLED, WGI_JoystickSetLED, + WGI_JoystickSendEffect, WGI_JoystickSetSensorsEnabled, WGI_JoystickUpdate, WGI_JoystickClose, diff --git a/src/joystick/windows/SDL_windowsjoystick.c b/src/joystick/windows/SDL_windowsjoystick.c index 7a2310a5a..29dd4e95b 100644 --- a/src/joystick/windows/SDL_windowsjoystick.c +++ b/src/joystick/windows/SDL_windowsjoystick.c @@ -526,7 +526,7 @@ WINDOWS_JoystickGetDeviceInstanceID(int device_index) It returns 0, or -1 if there is an error. */ static int -WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index) +WINDOWS_JoystickOpen(SDL_Joystick *joystick, int device_index) { JoyStick_DeviceData *device = SYS_Joystick; int index; @@ -552,7 +552,7 @@ WINDOWS_JoystickOpen(SDL_Joystick * joystick, int device_index) } static int -WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +WINDOWS_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { if (joystick->hwdata->bXInputDevice) { return SDL_XINPUT_JoystickRumble(joystick, low_frequency_rumble, high_frequency_rumble); @@ -562,19 +562,25 @@ WINDOWS_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uin } static int -WINDOWS_JoystickRumbleTriggers(SDL_Joystick * joystick, Uint16 left_rumble, Uint16 right_rumble) +WINDOWS_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble) { return SDL_Unsupported(); } static SDL_bool -WINDOWS_JoystickHasLED(SDL_Joystick * joystick) +WINDOWS_JoystickHasLED(SDL_Joystick *joystick) { return SDL_FALSE; } static int -WINDOWS_JoystickSetLED(SDL_Joystick * joystick, Uint8 red, Uint8 green, Uint8 blue) +WINDOWS_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ + return SDL_Unsupported(); +} + +static int +WINDOWS_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) { return SDL_Unsupported(); } @@ -586,7 +592,7 @@ WINDOWS_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) } static void -WINDOWS_JoystickUpdate(SDL_Joystick * joystick) +WINDOWS_JoystickUpdate(SDL_Joystick *joystick) { if (!joystick->hwdata) { return; @@ -601,7 +607,7 @@ WINDOWS_JoystickUpdate(SDL_Joystick * joystick) /* Function to close a joystick after use */ static void -WINDOWS_JoystickClose(SDL_Joystick * joystick) +WINDOWS_JoystickClose(SDL_Joystick *joystick) { if (joystick->hwdata->bXInputDevice) { SDL_XINPUT_JoystickClose(joystick); @@ -659,6 +665,7 @@ SDL_JoystickDriver SDL_WINDOWS_JoystickDriver = WINDOWS_JoystickRumbleTriggers, WINDOWS_JoystickHasLED, WINDOWS_JoystickSetLED, + WINDOWS_JoystickSendEffect, WINDOWS_JoystickSetSensorsEnabled, WINDOWS_JoystickUpdate, WINDOWS_JoystickClose, diff --git a/test/testgamecontroller.c b/test/testgamecontroller.c index d48f92f76..71de6417c 100644 --- a/test/testgamecontroller.c +++ b/test/testgamecontroller.c @@ -61,15 +61,16 @@ static const struct { int x; int y; double angle; } axis_positions[] = { {375, -20, 0.0}, /* TRIGGERRIGHT */ }; -SDL_Window *window = NULL; -SDL_Renderer *screen = NULL; -SDL_bool retval = SDL_FALSE; -SDL_bool done = SDL_FALSE; -SDL_bool set_LED = SDL_FALSE; -SDL_Texture *background_front, *background_back, *button, *axis; -SDL_GameController *gamecontroller; -SDL_GameController **gamecontrollers; -int num_controllers = 0; +static SDL_Window *window = NULL; +static SDL_Renderer *screen = NULL; +static SDL_bool retval = SDL_FALSE; +static SDL_bool done = SDL_FALSE; +static SDL_bool set_LED = SDL_FALSE; +static int trigger_effect = 0; +static SDL_Texture *background_front, *background_back, *button, *axis; +static SDL_GameController *gamecontroller; +static SDL_GameController **gamecontrollers; +static int num_controllers = 0; static void UpdateWindowTitle() { @@ -146,6 +147,7 @@ static void AddController(int device_index, SDL_bool verbose) controllers[num_controllers++] = controller; gamecontrollers = controllers; gamecontroller = controller; + trigger_effect = 0; if (verbose) { const char *name = SDL_GameControllerName(gamecontroller); @@ -245,6 +247,57 @@ static Uint16 ConvertAxisToRumble(Sint16 axis) } } +/* PS5 trigger effect documentation: + https://controllers.fandom.com/wiki/Sony_DualSense#FFB_Trigger_Modes +*/ +typedef struct +{ + Uint8 ucEnableBits1; /* 0 */ + Uint8 ucEnableBits2; /* 1 */ + Uint8 ucRumbleRight; /* 2 */ + Uint8 ucRumbleLeft; /* 3 */ + Uint8 ucHeadphoneVolume; /* 4 */ + Uint8 ucSpeakerVolume; /* 5 */ + Uint8 ucMicrophoneVolume; /* 6 */ + Uint8 ucAudioEnableBits; /* 7 */ + Uint8 ucMicLightMode; /* 8 */ + Uint8 ucAudioMuteBits; /* 9 */ + Uint8 rgucRightTriggerEffect[11]; /* 10 */ + Uint8 rgucLeftTriggerEffect[11]; /* 21 */ + Uint8 rgucUnknown1[6]; /* 32 */ + Uint8 ucLedFlags; /* 38 */ + Uint8 rgucUnknown2[2]; /* 39 */ + Uint8 ucLedAnim; /* 41 */ + Uint8 ucLedBrightness; /* 42 */ + Uint8 ucPadLights; /* 43 */ + Uint8 ucLedRed; /* 44 */ + Uint8 ucLedGreen; /* 45 */ + Uint8 ucLedBlue; /* 46 */ +} DS5EffectsState_t; + +static void CyclePS5TriggerEffect() +{ + DS5EffectsState_t state; + + Uint8 effects[3][11] = + { + /* Clear trigger effect */ + { 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* Constant resistance across entire trigger pull */ + { 0x01, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0 }, + /* Resistance and vibration when trigger is pulled */ + { 0x06, 15, 63, 128, 0, 0, 0, 0, 0, 0, 0 }, + }; + + trigger_effect = (trigger_effect + 1) % SDL_arraysize(effects); + + SDL_zero(state); + state.ucEnableBits1 |= (0x04 | 0x08); /* Modify right and left trigger effect respectively */ + SDL_memcpy(state.rgucRightTriggerEffect, effects[trigger_effect], sizeof(effects[trigger_effect])); + SDL_memcpy(state.rgucLeftTriggerEffect, effects[trigger_effect], sizeof(effects[trigger_effect])); + SDL_GameControllerSendEffect(gamecontroller, &state, sizeof(state)); +} + void loop(void *arg) { @@ -279,6 +332,8 @@ loop(void *arg) event.ctouchpad.pressure); break; +#define VERBOSE_SENSORS +#ifdef VERBOSE_SENSORS case SDL_CONTROLLERSENSORUPDATE: SDL_Log("Controller %d sensor %s: %.2f, %.2f, %.2f\n", event.csensor.which, @@ -288,13 +343,17 @@ loop(void *arg) event.csensor.data[1], event.csensor.data[2]); break; +#endif /* VERBOSE_SENSORS */ +#define VERBOSE_AXES +#ifdef VERBOSE_AXES case SDL_CONTROLLERAXISMOTION: if (event.caxis.value <= (-SDL_JOYSTICK_AXIS_MAX / 2) || event.caxis.value >= (SDL_JOYSTICK_AXIS_MAX / 2)) { SetController(event.caxis.which); } SDL_Log("Controller %d axis %s changed to %d\n", event.caxis.which, SDL_GameControllerGetStringForAxis((SDL_GameControllerAxis)event.caxis.axis), event.caxis.value); break; +#endif /* VERBOSE_AXES */ case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONUP: @@ -302,6 +361,13 @@ loop(void *arg) SetController(event.cbutton.which); } SDL_Log("Controller %d button %s %s\n", event.cbutton.which, SDL_GameControllerGetStringForButton((SDL_GameControllerButton)event.cbutton.button), event.cbutton.state ? "pressed" : "released"); + + /* Cycle PS5 trigger effects when the microphone button is pressed */ + if (event.type == SDL_CONTROLLERBUTTONDOWN && + event.cbutton.button == SDL_CONTROLLER_BUTTON_MISC1 && + SDL_GameControllerGetType(gamecontroller) == SDL_CONTROLLER_TYPE_PS5) { + CyclePS5TriggerEffect(); + } break; case SDL_KEYDOWN: @@ -408,23 +474,25 @@ loop(void *arg) } } - /* Update rumble based on trigger state */ - { - Sint16 left = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); - Sint16 right = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); - Uint16 low_frequency_rumble = ConvertAxisToRumble(left); - Uint16 high_frequency_rumble = ConvertAxisToRumble(right); - SDL_GameControllerRumble(gamecontroller, low_frequency_rumble, high_frequency_rumble, 250); - } + if (trigger_effect == 0) { + /* Update rumble based on trigger state */ + { + Sint16 left = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERLEFT); + Sint16 right = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + Uint16 low_frequency_rumble = ConvertAxisToRumble(left); + Uint16 high_frequency_rumble = ConvertAxisToRumble(right); + SDL_GameControllerRumble(gamecontroller, low_frequency_rumble, high_frequency_rumble, 250); + } - /* Update trigger rumble based on thumbstick state */ - { - Sint16 left = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_LEFTY); - Sint16 right = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_RIGHTY); - Uint16 left_rumble = ConvertAxisToRumble(~left); - Uint16 right_rumble = ConvertAxisToRumble(~right); + /* Update trigger rumble based on thumbstick state */ + { + Sint16 left = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_LEFTY); + Sint16 right = SDL_GameControllerGetAxis(gamecontroller, SDL_CONTROLLER_AXIS_RIGHTY); + Uint16 left_rumble = ConvertAxisToRumble(~left); + Uint16 right_rumble = ConvertAxisToRumble(~right); - SDL_GameControllerRumbleTriggers(gamecontroller, left_rumble, right_rumble, 250); + SDL_GameControllerRumbleTriggers(gamecontroller, left_rumble, right_rumble, 250); + } } } @@ -577,6 +645,12 @@ main(int argc, char *argv[]) } #endif + /* Reset trigger state */ + if (trigger_effect != 0) { + trigger_effect = -1; + CyclePS5TriggerEffect(); + } + SDL_DestroyRenderer(screen); SDL_DestroyWindow(window); SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);