diff --git a/include/SDL_hints.h b/include/SDL_hints.h index 1af57930e..8bc4828fa 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -935,6 +935,17 @@ extern "C" { */ #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE "SDL_JOYSTICK_HIDAPI_XBOX_ONE" +/** + * \brief A variable controlling whether the Home button LED should be turned on when an Xbox One controller is opened + * + * This variable can be set to the following values: + * "0" - home button LED is turned off + * "1" - home button LED is turned on + * + * By default the Home button LED state is not changed. This hint can also be set to a floating point value between 0.0 and 1.0 which controls the brightness of the Home button LED. The default brightness is 0.4. + */ +#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED" + /** * \brief A variable controlling whether the RAWINPUT joystick drivers should be used for better handling XInput-capable devices. * diff --git a/src/joystick/hidapi/SDL_hidapi_xboxone.c b/src/joystick/hidapi/SDL_hidapi_xboxone.c index 5be605917..ea72f27ff 100644 --- a/src/joystick/hidapi/SDL_hidapi_xboxone.c +++ b/src/joystick/hidapi/SDL_hidapi_xboxone.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" @@ -98,6 +99,7 @@ typedef enum { } SDL_XboxOneInitState; typedef struct { + SDL_HIDAPI_Device *device; Uint16 vendor_id; Uint16 product_id; SDL_bool bluetooth; @@ -143,6 +145,41 @@ ControllerHasShareButton(Uint16 vendor_id, Uint16 product_id) return SDL_IsJoystickXboxSeriesX(vendor_id, product_id); } +static int GetHomeLEDBrightness(const char *hint) +{ + const int MAX_VALUE = 50; + int value = 20; + + if (hint && *hint) { + if (SDL_strchr(hint, '.') != NULL) { + value = (int)(MAX_VALUE * SDL_atof(hint)); + } else if (!SDL_GetStringBoolean(hint, SDL_TRUE)) { + value = 0; + } + } + return value; +} + +static void SetHomeLED(SDL_DriverXboxOne_Context *ctx, int value) +{ + Uint8 led_packet[] = { 0x0A, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00 }; + + if (value > 0) { + led_packet[5] = 0x01; + led_packet[6] = (Uint8)value; + } + SDL_HIDAPI_SendRumble(ctx->device, led_packet, sizeof(led_packet)); +} + +static void SDLCALL SDL_HomeLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)userdata; + + if (hint && *hint) { + SetHomeLED(ctx, GetHomeLEDBrightness(hint)); + } +} + static void SetInitState(SDL_DriverXboxOne_Context *ctx, SDL_XboxOneInitState state) { @@ -243,6 +280,12 @@ SendControllerInit(SDL_HIDAPI_Device *device, SDL_DriverXboxOne_Context *ctx) if (init_packet[0] != 0x01) { init_packet[2] = ctx->sequence++; } + if (init_packet[0] == 0x0A) { + /* Get the initial brightness value */ + int brightness = GetHomeLEDBrightness(SDL_GetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED)); + init_packet[5] = (brightness > 0) ? 0x01 : 0x00; + init_packet[6] = (Uint8)brightness; + } #ifdef DEBUG_XBOX_PROTOCOL HIDAPI_DumpPacket("Xbox One sending INIT packet: size = %d", init_packet, packet->size); #endif @@ -316,6 +359,7 @@ HIDAPI_DriverXboxOne_InitDevice(SDL_HIDAPI_Device *device) SDL_OutOfMemory(); return SDL_FALSE; } + ctx->device = device; device->context = ctx; @@ -381,6 +425,8 @@ HIDAPI_DriverXboxOne_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; } + SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED, + SDL_HomeLEDHintChanged, ctx); return SDL_TRUE; } @@ -1143,6 +1189,10 @@ HIDAPI_DriverXboxOne_UpdateDevice(SDL_HIDAPI_Device *device) static void HIDAPI_DriverXboxOne_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { + SDL_DriverXboxOne_Context *ctx = (SDL_DriverXboxOne_Context *)device->context; + + SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED, + SDL_HomeLEDHintChanged, ctx); } static void