From 5a3adbfdb22e6f3d9d8260356ad9a7e44f8ae829 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 19 Aug 2022 11:11:25 -0700 Subject: [PATCH] Added the hint SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED to control whether the player LED is set on Xbox 360 controllers --- include/SDL_hints.h | 9 ++++ src/joystick/hidapi/SDL_hidapi_xbox360.c | 59 ++++++++++++++++++----- src/joystick/hidapi/SDL_hidapi_xbox360w.c | 58 +++++++++++++++++++--- 3 files changed, 108 insertions(+), 18 deletions(-) diff --git a/include/SDL_hints.h b/include/SDL_hints.h index c13c20624..d99fe1373 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -862,6 +862,15 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360 "SDL_JOYSTICK_HIDAPI_XBOX_360" +/** + * \brief A variable controlling whether the player LEDs should be lit to indicate which player is associated with an Xbox 360 controller. + * + * This variable can be set to the following values: + * "0" - player LEDs are not enabled + * "1" - player LEDs are enabled (the default) + */ +#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED "SDL_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED" + /** * \brief A variable controlling whether the HIDAPI driver for XBox 360 wireless controllers should be used. * diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360.c b/src/joystick/hidapi/SDL_hidapi_xbox360.c index 2ac3b17ba..a3a968ba9 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360.c @@ -26,6 +26,7 @@ #include "SDL_timer.h" #include "SDL_joystick.h" #include "SDL_gamecontroller.h" +#include "../../SDL_hints_c.h" #include "../SDL_sysjoystick.h" #include "SDL_hidapijoystick_c.h" #include "SDL_hidapi_rumble.h" @@ -38,6 +39,9 @@ typedef struct { + SDL_HIDAPI_Device *device; + int player_index; + SDL_bool player_lights; Uint8 last_state[USB_PACKET_LENGTH]; } SDL_DriverXbox360_Context; @@ -110,10 +114,10 @@ HIDAPI_DriverXbox360_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 pr return NULL; } -static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot) +static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on) { const SDL_bool blink = SDL_FALSE; - Uint8 mode = (blink ? 0x02 : 0x06) + slot; + Uint8 mode = on ? ((blink ? 0x02 : 0x06) + slot) : 0; Uint8 led_packet[] = { 0x01, 0x03, 0x00 }; led_packet[2] = mode; @@ -123,6 +127,27 @@ static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot) return SDL_TRUE; } +static void UpdateSlotLED(SDL_DriverXbox360_Context *ctx) +{ + if (ctx->player_lights && ctx->player_lights >= 0) { + SetSlotLED(ctx->device->dev, (ctx->player_index % 4), SDL_TRUE); + } else { + SetSlotLED(ctx->device->dev, 0, SDL_FALSE); + } +} + +static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)userdata; + SDL_bool player_lights = SDL_GetStringBoolean(hint, SDL_TRUE); + + if (player_lights != ctx->player_lights) { + ctx->player_lights = player_lights; + + UpdateSlotLED(ctx); + } +} + static SDL_bool HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device) { @@ -138,25 +163,28 @@ HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic static void HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) { - if (!device->dev) { + SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; + + if (!ctx) { return; } - if (player_index >= 0) { - SetSlotLED(device->dev, (player_index % 4)); - } + + ctx->player_index = player_index; + + UpdateSlotLED(ctx); } static SDL_bool HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { SDL_DriverXbox360_Context *ctx; - int player_index; ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx)); if (!ctx) { SDL_OutOfMemory(); return SDL_FALSE; } + ctx->device = device; device->dev = SDL_hid_open_path(device->path, 0); if (!device->dev) { @@ -166,11 +194,13 @@ HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst } device->context = ctx; - /* Set the controller LED */ - player_index = SDL_JoystickGetPlayerIndex(joystick); - if (player_index >= 0) { - SetSlotLED(device->dev, (player_index % 4)); - } + /* Initialize player index (needed for setting LEDs) */ + ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); + ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE); + UpdateSlotLED(ctx); + + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, + SDL_PlayerLEDHintChanged, ctx); /* Initialize the joystick capabilities */ joystick->nbuttons = 15; @@ -337,6 +367,11 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { + SDL_DriverXbox360_Context *ctx = (SDL_DriverXbox360_Context *)device->context; + + SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, + SDL_PlayerLEDHintChanged, ctx); + SDL_LockMutex(device->dev_lock); { if (device->dev) { diff --git a/src/joystick/hidapi/SDL_hidapi_xbox360w.c b/src/joystick/hidapi/SDL_hidapi_xbox360w.c index a75d1bd59..2d0ad026e 100644 --- a/src/joystick/hidapi/SDL_hidapi_xbox360w.c +++ b/src/joystick/hidapi/SDL_hidapi_xbox360w.c @@ -26,6 +26,7 @@ #include "SDL_timer.h" #include "SDL_joystick.h" #include "SDL_gamecontroller.h" +#include "../../SDL_hints_c.h" #include "../SDL_sysjoystick.h" #include "SDL_hidapijoystick_c.h" #include "SDL_hidapi_rumble.h" @@ -38,7 +39,11 @@ typedef struct { + SDL_HIDAPI_Device *device; SDL_bool connected; + SDL_bool opened; + int player_index; + SDL_bool player_lights; Uint8 last_state[USB_PACKET_LENGTH]; } SDL_DriverXbox360W_Context; @@ -87,10 +92,10 @@ HIDAPI_DriverXbox360W_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 p return "Xbox 360 Wireless Controller"; } -static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot) +static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot, SDL_bool on) { const SDL_bool blink = SDL_FALSE; - Uint8 mode = (blink ? 0x02 : 0x06) + slot; + Uint8 mode = on ? ((blink ? 0x02 : 0x06) + slot) : 0; Uint8 led_packet[] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; led_packet[3] = 0x40 + (mode % 0x0e); @@ -100,6 +105,27 @@ static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot) return SDL_TRUE; } +static void UpdateSlotLED(SDL_DriverXbox360W_Context *ctx) +{ + if (ctx->player_lights && ctx->player_lights >= 0) { + SetSlotLED(ctx->device->dev, (ctx->player_index % 4), SDL_TRUE); + } else { + SetSlotLED(ctx->device->dev, 0, SDL_FALSE); + } +} + +static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)userdata; + SDL_bool player_lights = SDL_GetStringBoolean(hint, SDL_TRUE); + + if (player_lights != ctx->player_lights) { + ctx->player_lights = player_lights; + + UpdateSlotLED(ctx); + } +} + static void UpdatePowerLevel(SDL_Joystick *joystick, Uint8 level) { @@ -129,6 +155,7 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device) SDL_OutOfMemory(); return SDL_FALSE; } + ctx->device = device; device->dev = SDL_hid_open_path(device->path, 0); if (!device->dev) { @@ -155,12 +182,15 @@ HIDAPI_DriverXbox360W_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joysti static void HIDAPI_DriverXbox360W_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) { - if (!device->dev) { + SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context; + + if (!ctx) { return; } - if (player_index >= 0) { - SetSlotLED(device->dev, (player_index % 4)); - } + + ctx->player_index = player_index; + + UpdateSlotLED(ctx); } static SDL_bool @@ -170,6 +200,16 @@ HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys SDL_zeroa(ctx->last_state); + ctx->opened = SDL_TRUE; + + /* Initialize player index (needed for setting LEDs) */ + ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); + ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE); + UpdateSlotLED(ctx); + + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, + SDL_PlayerLEDHintChanged, ctx); + /* Initialize the joystick capabilities */ joystick->nbuttons = 15; joystick->naxes = SDL_CONTROLLER_AXIS_MAX; @@ -339,6 +379,12 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { + SDL_DriverXbox360W_Context *ctx = (SDL_DriverXbox360W_Context *)device->context; + + SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, + SDL_PlayerLEDHintChanged, ctx); + + ctx->opened = SDL_FALSE; } static void