Added the hint SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED to control whether the player LED is set on Xbox 360 controllers

This commit is contained in:
Sam Lantinga 2022-08-19 11:11:25 -07:00
parent 52b6899a6b
commit 5a3adbfdb2
3 changed files with 108 additions and 18 deletions

View File

@ -862,6 +862,15 @@ extern "C" {
*/ */
#define SDL_HINT_JOYSTICK_HIDAPI_XBOX_360 "SDL_JOYSTICK_HIDAPI_XBOX_360" #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. * \brief A variable controlling whether the HIDAPI driver for XBox 360 wireless controllers should be used.
* *

View File

@ -26,6 +26,7 @@
#include "SDL_timer.h" #include "SDL_timer.h"
#include "SDL_joystick.h" #include "SDL_joystick.h"
#include "SDL_gamecontroller.h" #include "SDL_gamecontroller.h"
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h" #include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h" #include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h" #include "SDL_hidapi_rumble.h"
@ -38,6 +39,9 @@
typedef struct { typedef struct {
SDL_HIDAPI_Device *device;
int player_index;
SDL_bool player_lights;
Uint8 last_state[USB_PACKET_LENGTH]; Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverXbox360_Context; } SDL_DriverXbox360_Context;
@ -110,10 +114,10 @@ HIDAPI_DriverXbox360_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 pr
return NULL; 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; 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 }; Uint8 led_packet[] = { 0x01, 0x03, 0x00 };
led_packet[2] = mode; led_packet[2] = mode;
@ -123,6 +127,27 @@ static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot)
return SDL_TRUE; 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 static SDL_bool
HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverXbox360_InitDevice(SDL_HIDAPI_Device *device)
{ {
@ -138,25 +163,28 @@ HIDAPI_DriverXbox360_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joystic
static void static void
HIDAPI_DriverXbox360_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 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; return;
} }
if (player_index >= 0) {
SetSlotLED(device->dev, (player_index % 4)); ctx->player_index = player_index;
}
UpdateSlotLED(ctx);
} }
static SDL_bool static SDL_bool
HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
{ {
SDL_DriverXbox360_Context *ctx; SDL_DriverXbox360_Context *ctx;
int player_index;
ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx)); ctx = (SDL_DriverXbox360_Context *)SDL_calloc(1, sizeof(*ctx));
if (!ctx) { if (!ctx) {
SDL_OutOfMemory(); SDL_OutOfMemory();
return SDL_FALSE; return SDL_FALSE;
} }
ctx->device = device;
device->dev = SDL_hid_open_path(device->path, 0); device->dev = SDL_hid_open_path(device->path, 0);
if (!device->dev) { if (!device->dev) {
@ -166,11 +194,13 @@ HIDAPI_DriverXbox360_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
} }
device->context = ctx; device->context = ctx;
/* Set the controller LED */ /* Initialize player index (needed for setting LEDs) */
player_index = SDL_JoystickGetPlayerIndex(joystick); ctx->player_index = SDL_JoystickGetPlayerIndex(joystick);
if (player_index >= 0) { ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED, SDL_TRUE);
SetSlotLED(device->dev, (player_index % 4)); UpdateSlotLED(ctx);
}
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_XBOX_360_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
/* Initialize the joystick capabilities */ /* Initialize the joystick capabilities */
joystick->nbuttons = 15; joystick->nbuttons = 15;
@ -337,6 +367,11 @@ HIDAPI_DriverXbox360_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverXbox360_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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); SDL_LockMutex(device->dev_lock);
{ {
if (device->dev) { if (device->dev) {

View File

@ -26,6 +26,7 @@
#include "SDL_timer.h" #include "SDL_timer.h"
#include "SDL_joystick.h" #include "SDL_joystick.h"
#include "SDL_gamecontroller.h" #include "SDL_gamecontroller.h"
#include "../../SDL_hints_c.h"
#include "../SDL_sysjoystick.h" #include "../SDL_sysjoystick.h"
#include "SDL_hidapijoystick_c.h" #include "SDL_hidapijoystick_c.h"
#include "SDL_hidapi_rumble.h" #include "SDL_hidapi_rumble.h"
@ -38,7 +39,11 @@
typedef struct { typedef struct {
SDL_HIDAPI_Device *device;
SDL_bool connected; SDL_bool connected;
SDL_bool opened;
int player_index;
SDL_bool player_lights;
Uint8 last_state[USB_PACKET_LENGTH]; Uint8 last_state[USB_PACKET_LENGTH];
} SDL_DriverXbox360W_Context; } SDL_DriverXbox360W_Context;
@ -87,10 +92,10 @@ HIDAPI_DriverXbox360W_GetDeviceName(const char *name, Uint16 vendor_id, Uint16 p
return "Xbox 360 Wireless Controller"; 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; 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 }; Uint8 led_packet[] = { 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
led_packet[3] = 0x40 + (mode % 0x0e); led_packet[3] = 0x40 + (mode % 0x0e);
@ -100,6 +105,27 @@ static SDL_bool SetSlotLED(SDL_hid_device *dev, Uint8 slot)
return SDL_TRUE; 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 static void
UpdatePowerLevel(SDL_Joystick *joystick, Uint8 level) UpdatePowerLevel(SDL_Joystick *joystick, Uint8 level)
{ {
@ -129,6 +155,7 @@ HIDAPI_DriverXbox360W_InitDevice(SDL_HIDAPI_Device *device)
SDL_OutOfMemory(); SDL_OutOfMemory();
return SDL_FALSE; return SDL_FALSE;
} }
ctx->device = device;
device->dev = SDL_hid_open_path(device->path, 0); device->dev = SDL_hid_open_path(device->path, 0);
if (!device->dev) { if (!device->dev) {
@ -155,12 +182,15 @@ HIDAPI_DriverXbox360W_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_Joysti
static void static void
HIDAPI_DriverXbox360W_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) 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; return;
} }
if (player_index >= 0) {
SetSlotLED(device->dev, (player_index % 4)); ctx->player_index = player_index;
}
UpdateSlotLED(ctx);
} }
static SDL_bool static SDL_bool
@ -170,6 +200,16 @@ HIDAPI_DriverXbox360W_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
SDL_zeroa(ctx->last_state); 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 */ /* Initialize the joystick capabilities */
joystick->nbuttons = 15; joystick->nbuttons = 15;
joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
@ -339,6 +379,12 @@ HIDAPI_DriverXbox360W_UpdateDevice(SDL_HIDAPI_Device *device)
static void static void
HIDAPI_DriverXbox360W_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) 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 static void