Added the hint SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED to control whether the player LED should be lit on the Nintendo Wii controllers

Also fixed the Y axes on the Wii U Pro controller, and various formatting cleanup
This commit is contained in:
Sam Lantinga 2022-09-01 16:23:32 -07:00
parent 0ffaf5b871
commit c887cb02af
3 changed files with 107 additions and 46 deletions

View File

@ -7,6 +7,8 @@ This is a list of major changes in SDL's version history.
General: General:
* Added SDL_GetJoystickGUIDInfo() to get device information encoded in a joystick GUID * Added SDL_GetJoystickGUIDInfo() to get device information encoded in a joystick GUID
* Added support for Nintendo Wii controllers to the HIDAPI driver, and a hint SDL_HINT_JOYSTICK_HIDAPI_WII to control whether this is used
* Added the hint SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED to control whether the player LED should be lit on the Nintendo Wii controllers
--------------------------------------------------------------------------- ---------------------------------------------------------------------------

View File

@ -865,6 +865,15 @@ extern "C" {
*/ */
#define SDL_HINT_JOYSTICK_HIDAPI_WII "SDL_JOYSTICK_HIDAPI_WII" #define SDL_HINT_JOYSTICK_HIDAPI_WII "SDL_JOYSTICK_HIDAPI_WII"
/**
* \brief A variable controlling whether the player LEDs should be lit to indicate which player is associated with a Wii 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_WII_PLAYER_LED "SDL_JOYSTICK_HIDAPI_WII_PLAYER_LED"
/** /**
* \brief A variable controlling whether the HIDAPI driver for XBox controllers should be used. * \brief A variable controlling whether the HIDAPI driver for XBox controllers should be used.
* *

View File

@ -100,10 +100,11 @@ typedef struct {
SDL_HIDAPI_Device *device; SDL_HIDAPI_Device *device;
EWiiExtensionControllerType m_eExtensionControllerType; EWiiExtensionControllerType m_eExtensionControllerType;
SDL_bool m_bUseButtonLabels; SDL_bool m_bUseButtonLabels;
SDL_bool m_bPlayerLights;
int m_nPlayerIndex;
SDL_bool m_bRumbleActive; SDL_bool m_bRumbleActive;
Uint8 m_rgucReadBuffer[k_unWiiPacketDataLength]; Uint8 m_rgucReadBuffer[k_unWiiPacketDataLength];
Uint32 m_iLastStatus; Uint32 m_iLastStatus;
int m_playerIndex;
struct StickCalibrationData { struct StickCalibrationData {
Uint16 min; Uint16 min;
@ -344,7 +345,7 @@ static void UpdatePowerLevelWiiU(SDL_Joystick *joystick, Uint8 extensionBatteryB
static SDL_bool IdentifyController(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick) static SDL_bool IdentifyController(SDL_DriverWii_Context *ctx, SDL_Joystick *joystick)
{ {
static const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 }; const Uint8 statusRequest[2] = { k_eWiiOutputReportIDs_StatusRequest, 0 };
SDL_bool hasExtension; SDL_bool hasExtension;
WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE); WriteOutput(ctx, statusRequest, sizeof(statusRequest), SDL_TRUE);
if (!ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) { if (!ReadInputSync(ctx, k_eWiiInputReportIDs_Status, NULL)) {
@ -354,12 +355,15 @@ static SDL_bool IdentifyController(SDL_DriverWii_Context *ctx, SDL_Joystick *joy
hasExtension = ctx->m_rgucReadBuffer[3] & 2 ? SDL_TRUE : SDL_FALSE; hasExtension = ctx->m_rgucReadBuffer[3] & 2 ? SDL_TRUE : SDL_FALSE;
if (hasExtension) { if (hasExtension) {
/* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */ /* http://wiibrew.org/wiki/Wiimote/Extension_Controllers#The_New_Way */
Uint8 data[2] = {0x55, 0x00}; Uint8 data_0x55 = 0x55;
SDL_bool ok = WriteRegister(ctx, 0xA400F0, &data[0], 1, SDL_TRUE) Uint8 data_0x00 = 0x00;
&& WriteRegister(ctx, 0xA400FB, &data[1], 1, SDL_TRUE) SDL_bool ok = WriteRegister(ctx, 0xA400F0, &data_0x55, sizeof(data_0x55), SDL_TRUE)
&& WriteRegister(ctx, 0xA400FB, &data_0x00, sizeof(data_0x00), SDL_TRUE)
&& ReadRegister(ctx, 0xA400FA, 6, SDL_TRUE) && ReadRegister(ctx, 0xA400FA, 6, SDL_TRUE)
&& ParseExtensionResponse(ctx); && ParseExtensionResponse(ctx);
if (!ok) { return SDL_FALSE; } if (!ok) {
return SDL_FALSE;
}
} else { } else {
ctx->m_eExtensionControllerType = k_eWiiExtensionControllerType_None; ctx->m_eExtensionControllerType = k_eWiiExtensionControllerType_None;
} }
@ -382,13 +386,14 @@ static EWiiInputReportIDs GetButtonPacketType(SDL_DriverWii_Context *ctx)
static SDL_bool RequestButtonPacketType(SDL_DriverWii_Context *ctx, EWiiInputReportIDs type) static SDL_bool RequestButtonPacketType(SDL_DriverWii_Context *ctx, EWiiInputReportIDs type)
{ {
Uint8 tt = ctx->m_bRumbleActive;
Uint8 data[3]; Uint8 data[3];
Uint8 tt = ctx->m_bRumbleActive;
/* Continuous reporting off, tt & 4 == 0 */ /* Continuous reporting off, tt & 4 == 0 */
data[0] = k_eWiiOutputReportIDs_DataReportingMode; data[0] = k_eWiiOutputReportIDs_DataReportingMode;
data[1] = tt; data[1] = tt;
data[2] = type; data[2] = type;
return WriteOutput(ctx, data, 3, SDL_FALSE); return WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
} }
static void InitStickCalibrationData(SDL_DriverWii_Context *ctx) static void InitStickCalibrationData(SDL_DriverWii_Context *ctx)
@ -428,12 +433,18 @@ static void InitStickCalibrationData(SDL_DriverWii_Context *ctx)
static const char* GetNameFromExtensionInfo(SDL_DriverWii_Context *ctx) static const char* GetNameFromExtensionInfo(SDL_DriverWii_Context *ctx)
{ {
switch (ctx->m_eExtensionControllerType) { switch (ctx->m_eExtensionControllerType) {
case k_eWiiExtensionControllerType_None: return "Nintendo Wii Remote"; case k_eWiiExtensionControllerType_None:
case k_eWiiExtensionControllerType_Nunchuck: return "Nintendo Wii Remote with Nunchuck"; return "Nintendo Wii Remote";
case k_eWiiExtensionControllerType_ClassicController: return "Nintendo Wii Remote with Classic Controller"; case k_eWiiExtensionControllerType_Nunchuck:
case k_eWiiExtensionControllerType_ClassicControllerPro: return "Nintendo Wii Remote with Classic Controller Pro"; return "Nintendo Wii Remote with Nunchuck";
case k_eWiiExtensionControllerType_WiiUPro: return "Nintendo Wii U Pro Controller"; case k_eWiiExtensionControllerType_ClassicController:
default: return "Nintendo Wii Remote with Unknown Extension"; return "Nintendo Wii Remote with Classic Controller";
case k_eWiiExtensionControllerType_ClassicControllerPro:
return "Nintendo Wii Remote with Classic Controller Pro";
case k_eWiiExtensionControllerType_WiiUPro:
return "Nintendo Wii U Pro Controller";
default:
return "Nintendo Wii Remote with Unknown Extension";
} }
} }
@ -446,6 +457,7 @@ static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata,
static Uint8 RemapButton(SDL_DriverWii_Context *ctx, Uint8 button) static Uint8 RemapButton(SDL_DriverWii_Context *ctx, Uint8 button)
{ {
if (!ctx->m_bUseButtonLabels) { if (!ctx->m_bUseButtonLabels) {
/* Use button positions */
switch (button) { switch (button) {
case SDL_CONTROLLER_BUTTON_A: case SDL_CONTROLLER_BUTTON_A:
return SDL_CONTROLLER_BUTTON_B; return SDL_CONTROLLER_BUTTON_B;
@ -462,6 +474,51 @@ static Uint8 RemapButton(SDL_DriverWii_Context *ctx, Uint8 button)
return button; return button;
} }
static void UpdateSlotLED(SDL_DriverWii_Context *ctx)
{
Uint8 leds;
Uint8 data[2];
/* The lowest bit needs to have the rumble status */
leds = ctx->m_bRumbleActive;
if (ctx->m_bPlayerLights) {
/* Use the same LED codes as Smash 8-player for 5-7 */
if (ctx->m_nPlayerIndex == 0 || ctx->m_nPlayerIndex > 3) {
leds |= k_eWiiPlayerLEDs_P1;
}
if (ctx->m_nPlayerIndex == 1 || ctx->m_nPlayerIndex == 4) {
leds |= k_eWiiPlayerLEDs_P2;
}
if (ctx->m_nPlayerIndex == 2 || ctx->m_nPlayerIndex == 5) {
leds |= k_eWiiPlayerLEDs_P3;
}
if (ctx->m_nPlayerIndex == 3 || ctx->m_nPlayerIndex == 6) {
leds |= k_eWiiPlayerLEDs_P4;
}
/* Turn on all lights for other player indexes */
if (ctx->m_nPlayerIndex < 0 || ctx->m_nPlayerIndex > 6) {
leds |= k_eWiiPlayerLEDs_P1 | k_eWiiPlayerLEDs_P2 | k_eWiiPlayerLEDs_P3 | k_eWiiPlayerLEDs_P4;
}
}
data[0] = k_eWiiOutputReportIDs_LEDs;
data[1] = leds;
WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
}
static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)userdata;
SDL_bool bPlayerLights = SDL_GetStringBoolean(hint, SDL_TRUE);
if (bPlayerLights != ctx->m_bPlayerLights) {
ctx->m_bPlayerLights = bPlayerLights;
UpdateSlotLED(ctx);
}
}
static SDL_bool static SDL_bool
HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device) HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
{ {
@ -471,9 +528,6 @@ HIDAPI_DriverWii_InitDevice(SDL_HIDAPI_Device *device)
static int static int
HIDAPI_DriverWii_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id) HIDAPI_DriverWii_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
{ {
if (device->context) {
return ((SDL_DriverWii_Context *)device->context)->m_playerIndex;
}
return -1; return -1;
} }
@ -481,37 +535,14 @@ static void
HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index) HIDAPI_DriverWii_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
{ {
SDL_DriverWii_Context *ctx = device->context; SDL_DriverWii_Context *ctx = device->context;
Uint8 leds;
Uint8 data[2];
if (!ctx) { if (!ctx) {
return; return;
} }
ctx->m_playerIndex = player_index; ctx->m_nPlayerIndex = player_index;
leds = ctx->m_bRumbleActive; UpdateSlotLED(ctx);
/* Use the same LED codes as Smash 8-player for 5-7 */
if (player_index == 1 || player_index > 4) {
leds |= k_eWiiPlayerLEDs_P1;
}
if (player_index == 2 || player_index == 5) {
leds |= k_eWiiPlayerLEDs_P2;
}
if (player_index == 3 || player_index == 6) {
leds |= k_eWiiPlayerLEDs_P3;
}
if (player_index == 4 || player_index == 7) {
leds |= k_eWiiPlayerLEDs_P4;
}
/* Turn on all lights for other player indexes */
if (player_index < 1 || player_index > 7) {
leds |= k_eWiiPlayerLEDs_P1 | k_eWiiPlayerLEDs_P2 | k_eWiiPlayerLEDs_P3 | k_eWiiPlayerLEDs_P4;
}
data[0] = k_eWiiOutputReportIDs_LEDs;
data[1] = leds;
WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
} }
static SDL_bool static SDL_bool
@ -547,6 +578,14 @@ HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
SDL_free(device->name); SDL_free(device->name);
device->name = SDL_strdup(GetNameFromExtensionInfo(ctx)); device->name = SDL_strdup(GetNameFromExtensionInfo(ctx));
/* Initialize player index (needed for setting LEDs) */
ctx->m_nPlayerIndex = SDL_JoystickGetPlayerIndex(joystick);
ctx->m_bPlayerLights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED, SDL_TRUE);
UpdateSlotLED(ctx);
SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
/* Initialize the joystick capabilities */ /* Initialize the joystick capabilities */
if (ctx->m_eExtensionControllerType == k_eWiiExtensionControllerType_WiiUPro) { if (ctx->m_eExtensionControllerType == k_eWiiExtensionControllerType_WiiUPro) {
joystick->nbuttons = 15; joystick->nbuttons = 15;
@ -556,7 +595,6 @@ HIDAPI_DriverWii_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
} }
joystick->naxes = SDL_CONTROLLER_AXIS_MAX; joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
HIDAPI_DriverWii_SetDevicePlayerIndex(device, 0, SDL_JoystickGetPlayerIndex(joystick));
RequestButtonPacketType(ctx, GetButtonPacketType(ctx)); RequestButtonPacketType(ctx, GetButtonPacketType(ctx));
return SDL_TRUE; return SDL_TRUE;
@ -653,6 +691,11 @@ static void PostStickCalibrated(SDL_Joystick *joystick, struct StickCalibrationD
float fvalue = (float)distance / (float)range; float fvalue = (float)distance / (float)range;
value = (Sint16)(fvalue * SDL_MAX_SINT16); value = (Sint16)(fvalue * SDL_MAX_SINT16);
} }
if (axis == SDL_CONTROLLER_AXIS_LEFTY || axis == SDL_CONTROLLER_AXIS_RIGHTY) {
if (value) {
value = ~value;
}
}
SDL_PrivateJoystickAxis(joystick, axis, value); SDL_PrivateJoystickAxis(joystick, axis, value);
} }
@ -817,6 +860,7 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context; SDL_DriverWii_Context *ctx = (SDL_DriverWii_Context *)device->context;
SDL_Joystick *joystick = NULL; SDL_Joystick *joystick = NULL;
int size; int size;
Uint32 now;
if (device->num_joysticks > 0) { if (device->num_joysticks > 0) {
joystick = SDL_JoystickFromInstanceID(device->joysticks[0]); joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
@ -833,12 +877,15 @@ HIDAPI_DriverWii_UpdateDevice(SDL_HIDAPI_Device *device)
} }
/* Request a status update periodically to make sure our battery value is up to date */ /* Request a status update periodically to make sure our battery value is up to date */
if (SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_iLastStatus + FIFTEEN_MINUTES_IN_MS)) { now = SDL_GetTicks();
if (SDL_TICKS_PASSED(now, ctx->m_iLastStatus + FIFTEEN_MINUTES_IN_MS)) {
Uint8 data[2]; Uint8 data[2];
ctx->m_iLastStatus = SDL_GetTicks();
data[0] = k_eWiiOutputReportIDs_StatusRequest; data[0] = k_eWiiOutputReportIDs_StatusRequest;
data[1] = ctx->m_bRumbleActive; data[1] = ctx->m_bRumbleActive;
WriteOutput(ctx, data, 2, SDL_FALSE); WriteOutput(ctx, data, sizeof(data), SDL_FALSE);
ctx->m_iLastStatus = now;
} }
if (size < 0) { if (size < 0) {
@ -856,6 +903,9 @@ HIDAPI_DriverWii_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick
SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
SDL_GameControllerButtonReportingHintChanged, ctx); SDL_GameControllerButtonReportingHintChanged, ctx);
SDL_DelHintCallback(SDL_HINT_JOYSTICK_HIDAPI_WII_PLAYER_LED,
SDL_PlayerLEDHintChanged, ctx);
SDL_LockMutex(device->dev_lock); SDL_LockMutex(device->dev_lock);
{ {
SDL_hid_close(device->dev); SDL_hid_close(device->dev);