early-access version 1667

This commit is contained in:
pineappleEA
2021-05-09 11:30:38 +02:00
parent 5e268d25d7
commit 5dbb928ff2
1069 changed files with 38272 additions and 14437 deletions
+245 -48
View File
@@ -1,6 +1,6 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -44,13 +44,24 @@
/* Define this to get log output for rumble logic */
/*#define DEBUG_RUMBLE*/
/* How often you can write rumble commands to the controller in Bluetooth mode
If you send commands more frequently than this, you can turn off the controller.
/* The initialization sequence doesn't appear to work correctly on Windows unless
the reads and writes are on the same thread.
... and now I can't reproduce this, so I'm leaving it in, but disabled for now.
*/
#define RUMBLE_WRITE_FREQUENCY_MS 25
/*#define SWITCH_SYNCHRONOUS_WRITES*/
/* How often you can write rumble commands to the controller.
If you send commands more frequently than this, you can turn off the controller
in Bluetooth mode, or the motors can miss the command in USB mode.
*/
#define RUMBLE_WRITE_FREQUENCY_MS 30
/* How often you have to refresh a long duration rumble to keep the motors running */
#define RUMBLE_REFRESH_FREQUENCY_MS 40
#define RUMBLE_REFRESH_FREQUENCY_MS 50
#define SWITCH_GYRO_SCALE 14.2842f
#define SWITCH_ACCEL_SCALE 4096.f
typedef enum {
k_eSwitchInputReportIDs_SubcommandReply = 0x21,
@@ -79,6 +90,7 @@ typedef enum {
} ESwitchSubcommandIDs;
typedef enum {
k_eSwitchProprietaryCommandIDs_Status = 0x01,
k_eSwitchProprietaryCommandIDs_Handshake = 0x02,
k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03,
k_eSwitchProprietaryCommandIDs_ForceUSB = 0x04,
@@ -87,6 +99,7 @@ typedef enum {
} ESwitchProprietaryCommandIDs;
typedef enum {
k_eSwitchDeviceInfoControllerType_Unknown = 0x0,
k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1,
k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2,
k_eSwitchDeviceInfoControllerType_ProController = 0x3,
@@ -176,6 +189,16 @@ typedef struct
};
} SwitchSubcommandInputPacket_t;
typedef struct
{
Uint8 ucPacketType;
Uint8 ucCommandID;
Uint8 ucFiller;
Uint8 ucDeviceType;
Uint8 rgucMACAddress[6];
} SwitchProprietaryStatusPacket_t;
typedef struct
{
Uint8 rgucData[4];
@@ -212,6 +235,8 @@ typedef struct {
SDL_bool m_bUsingBluetooth;
SDL_bool m_bIsGameCube;
SDL_bool m_bUseButtonLabels;
ESwitchDeviceInfoControllerType m_eControllerType;
Uint8 m_rgucMACAddress[6];
Uint8 m_nCommandNumber;
SwitchCommonOutputPacket_t m_RumblePacket;
Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
@@ -220,6 +245,8 @@ typedef struct {
SDL_bool m_bRumblePending;
SDL_bool m_bRumbleZeroPending;
Uint32 m_unRumblePending;
SDL_bool m_bHasSensors;
SDL_bool m_bReportSensors;
SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
SwitchSimpleStatePacket_t m_lastSimpleState;
@@ -285,7 +312,7 @@ HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, SDL_GameControllerType t
controller to continually attempt to reconnect is to filter it out by manufactuer/product string.
Note that the controller does have a different product string when connected over Bluetooth.
*/
if (SDL_strcmp( name, "HORI Wireless Switch Pad" ) == 0) {
if (SDL_strcmp(name, "HORI Wireless Switch Pad") == 0) {
return SDL_FALSE;
}
return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) ? SDL_TRUE : SDL_FALSE;
@@ -295,6 +322,16 @@ static const char *
HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
{
/* Give a user friendly name for this controller */
if (vendor_id == USB_VENDOR_NINTENDO) {
if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT) {
return "Nintendo Switch Joy-Con Left";
}
if (product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT) {
return "Nintendo Switch Joy-Con Right";
}
}
return "Nintendo Switch Pro Controller";
}
@@ -310,11 +347,15 @@ static int ReadInput(SDL_DriverSwitch_Context *ctx)
static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size)
{
#ifdef SWITCH_SYNCHRONOUS_WRITES
return hid_write(ctx->device->dev, data, size);
#else
/* Use the rumble thread for general asynchronous writes */
if (SDL_HIDAPI_LockRumble() < 0) {
return -1;
}
return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size);
#endif /* SWITCH_SYNCHRONOUS_WRITES */
}
static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
@@ -432,6 +473,7 @@ static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprieta
return SDL_FALSE;
}
SDL_zero(packet);
packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
packet.ucProprietaryID = ucCommand;
if (pBuf) {
@@ -493,6 +535,40 @@ static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
}
static SDL_bool BReadDeviceInfo(SDL_DriverSwitch_Context *ctx)
{
SwitchSubcommandInputPacket_t *reply = NULL;
ctx->m_bUsingBluetooth = SDL_FALSE;
if (WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Status, NULL, 0, SDL_TRUE)) {
SwitchProprietaryStatusPacket_t *status = (SwitchProprietaryStatusPacket_t *)&ctx->m_rgucReadBuffer[0];
size_t i;
ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)status->ucDeviceType;
for (i = 0; i < sizeof (ctx->m_rgucMACAddress); ++i)
ctx->m_rgucMACAddress[i] = status->rgucMACAddress[ sizeof(ctx->m_rgucMACAddress) - i - 1 ];
return SDL_TRUE;
}
ctx->m_bUsingBluetooth = SDL_TRUE;
if (WriteSubcommand(ctx, k_eSwitchSubcommandIDs_RequestDeviceInfo, NULL, 0, &reply)) {
// Byte 2: Controller ID (1=LJC, 2=RJC, 3=Pro)
ctx->m_eControllerType = (ESwitchDeviceInfoControllerType)reply->deviceInfo.ucDeviceType;
// Bytes 4-9: MAC address (big-endian)
memcpy(ctx->m_rgucMACAddress, reply->deviceInfo.rgucMACAddress, sizeof(ctx->m_rgucMACAddress));
return SDL_TRUE;
}
ctx->m_bUsingBluetooth = SDL_FALSE;
return SDL_FALSE;
}
static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
{
/* We have to send a connection handshake to the controller when communicating over USB
@@ -510,6 +586,9 @@ static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
return SDL_FALSE;
}
if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
return SDL_FALSE;
}
return SDL_TRUE;
}
@@ -550,6 +629,12 @@ static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot)
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
}
static SDL_bool SetIMUEnabled(SDL_DriverSwitch_Context* ctx, SDL_bool enabled)
{
Uint8 imu_data = enabled ? 1 : 0;
return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableIMU, &imu_data, sizeof(imu_data), NULL);
}
static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
{
Uint8 *pStickCal;
@@ -621,19 +706,6 @@ static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx, Uint8 input_
return SDL_TRUE;
}
static float fsel(float fComparand, float fValGE, float fLT)
{
return fComparand >= 0 ? fValGE : fLT;
}
static float RemapVal(float val, float A, float B, float C, float D)
{
if (A == B) {
return fsel(val - B , D , C);
}
return C + (D - C) * (val - A) / (B - A);
}
static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue, Sint16 sCenter)
{
sRawValue -= sCenter;
@@ -646,9 +718,9 @@ static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int n
}
if (sRawValue > 0) {
return (Sint16)(RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16));
return (Sint16)HIDAPI_RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16);
} else {
return (Sint16)(RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0));
return (Sint16)HIDAPI_RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0);
}
}
@@ -740,9 +812,16 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
/* Try setting up USB mode, and if that fails we're using Bluetooth */
if (!BTrySetupUSB(ctx)) {
ctx->m_bUsingBluetooth = SDL_TRUE;
if (!BReadDeviceInfo(ctx)) {
SDL_SetError("Couldn't read device info");
goto error;
}
if (!ctx->m_bUsingBluetooth) {
if (!BTrySetupUSB(ctx)) {
SDL_SetError("Couldn't setup USB mode");
goto error;
}
}
/* Determine the desired input mode (needed before loading stick calibration) */
@@ -758,9 +837,17 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
* level and we only care about battery level over bluetooth anyway.
*/
if (device->vendor_id == USB_VENDOR_NINTENDO &&
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO) {
(device->product_id == USB_PRODUCT_NINTENDO_SWITCH_PRO ||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_LEFT ||
device->product_id == USB_PRODUCT_NINTENDO_SWITCH_JOY_CON_RIGHT)) {
input_mode = k_eSwitchInputReportIDs_FullControllerState;
}
if (input_mode == k_eSwitchInputReportIDs_FullControllerState) {
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO);
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL);
ctx->m_bHasSensors = SDL_TRUE;
}
if (!LoadStickCalibration(ctx, input_mode)) {
SDL_SetError("Couldn't load stick calibration");
@@ -789,9 +876,27 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
/* Set the LED state */
if (ctx->m_bHasHomeLED) {
SetHomeLED(ctx, 100);
if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, SDL_TRUE)) {
SetHomeLED(ctx, 100);
} else {
SetHomeLED(ctx, 0);
}
}
SetSlotLED(ctx, (joystick->instance_id % 4));
/* Set the serial number */
{
char serial[18];
SDL_snprintf(serial, sizeof(serial), "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x",
ctx->m_rgucMACAddress[0],
ctx->m_rgucMACAddress[1],
ctx->m_rgucMACAddress[2],
ctx->m_rgucMACAddress[3],
ctx->m_rgucMACAddress[4],
ctx->m_rgucMACAddress[5]);
joystick->serial = SDL_strdup(serial);
}
}
if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) {
@@ -803,21 +908,30 @@ HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joysti
SDL_GameControllerButtonReportingHintChanged, ctx);
/* Initialize the joystick capabilities */
joystick->nbuttons = 16;
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft ||
ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
joystick->nbuttons = 20;
} else {
joystick->nbuttons = 16;
}
joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
return SDL_TRUE;
error:
if (device->dev) {
hid_close(device->dev);
device->dev = NULL;
}
if (device->context) {
SDL_free(device->context);
device->context = NULL;
SDL_LockMutex(device->dev_lock);
{
if (device->dev) {
hid_close(device->dev);
device->dev = NULL;
}
if (device->context) {
SDL_free(device->context);
device->context = NULL;
}
}
SDL_UnlockMutex(device->dev_lock);
return SDL_FALSE;
}
@@ -859,7 +973,7 @@ HIDAPI_DriverSwitch_ActuallyRumbleJoystick(SDL_DriverSwitch_Context *ctx, Uint16
static int
HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx)
{
if ((SDL_GetTicks() - ctx->m_unRumbleSent) < RUMBLE_WRITE_FREQUENCY_MS) {
if (!SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_WRITE_FREQUENCY_MS)) {
return 0;
}
@@ -868,7 +982,7 @@ HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx)
Uint16 high_frequency_rumble = (Uint16)ctx->m_unRumblePending;
#ifdef DEBUG_RUMBLE
SDL_Log("Sent pending rumble %d/%d\n", low_frequency_rumble, high_frequency_rumble);
SDL_Log("Sent pending rumble %d/%d, %d ms after previous rumble\n", low_frequency_rumble, high_frequency_rumble, SDL_GetTicks() - ctx->m_unRumbleSent);
#endif
ctx->m_bRumblePending = SDL_FALSE;
ctx->m_unRumblePending = 0;
@@ -880,7 +994,7 @@ HIDAPI_DriverSwitch_SendPendingRumble(SDL_DriverSwitch_Context *ctx)
ctx->m_bRumbleZeroPending = SDL_FALSE;
#ifdef DEBUG_RUMBLE
SDL_Log("Sent pending zero rumble\n");
SDL_Log("Sent pending zero rumble, %d ms after previous rumble\n", SDL_GetTicks() - ctx->m_unRumbleSent);
#endif
return HIDAPI_DriverSwitch_ActuallyRumbleJoystick(ctx, 0, 0);
}
@@ -899,7 +1013,7 @@ HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joys
}
}
if (ctx->m_bUsingBluetooth && (SDL_GetTicks() - ctx->m_unRumbleSent) < RUMBLE_WRITE_FREQUENCY_MS) {
if (!SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_WRITE_FREQUENCY_MS)) {
if (low_frequency_rumble || high_frequency_rumble) {
Uint32 unRumblePending = ((Uint32)low_frequency_rumble << 16) | high_frequency_rumble;
@@ -945,7 +1059,30 @@ HIDAPI_DriverSwitch_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joys
static int
HIDAPI_DriverSwitch_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, SDL_bool enabled)
{
return SDL_Unsupported();
SDL_DriverSwitch_Context* ctx = (SDL_DriverSwitch_Context*)device->context;
if (!ctx->m_bHasSensors) {
return SDL_Unsupported();
}
SetIMUEnabled(ctx, enabled);
ctx->m_bReportSensors = enabled;
return 0;
}
static float
HIDAPI_DriverSwitch_ScaleGyro(Sint16 value)
{
float result = (value / SWITCH_GYRO_SCALE) * (float)M_PI / 180.0f;
return result;
}
static float
HIDAPI_DriverSwitch_ScaleAccel(Sint16 value)
{
float result = (value / SWITCH_ACCEL_SCALE) * SDL_STANDARD_GRAVITY;
return result;
}
static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchInputOnlyControllerStatePacket_t *packet)
@@ -1023,22 +1160,22 @@ static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwi
}
if (packet->rgucJoystickLeft[0] != ctx->m_lastInputOnlyState.rgucJoystickLeft[0]) {
axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickLeft[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
}
if (packet->rgucJoystickLeft[1] != ctx->m_lastInputOnlyState.rgucJoystickLeft[1]) {
axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickLeft[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
}
if (packet->rgucJoystickRight[0] != ctx->m_lastInputOnlyState.rgucJoystickRight[0]) {
axis = (Sint16)(RemapVal(packet->rgucJoystickRight[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickRight[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
}
if (packet->rgucJoystickRight[1] != ctx->m_lastInputOnlyState.rgucJoystickRight[1]) {
axis = (Sint16)(RemapVal(packet->rgucJoystickRight[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
axis = (Sint16)HIDAPI_RemapVal(packet->rgucJoystickRight[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16);
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
}
@@ -1146,6 +1283,10 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE1, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE3, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
axis = (data & 0x80) ? 32767 : -32768;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
@@ -1168,6 +1309,10 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConLeft) {
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE4, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_PADDLE2, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
}
SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
axis = (data & 0x80) ? 32767 : -32768;
SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
@@ -1210,6 +1355,54 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C
}
}
if (ctx->m_bReportSensors) {
float data[3];
/* Note the order of components has been shuffled to match PlayStation controllers,
* since that's our de facto standard from already supporting those controllers, and
* users will want consistent axis mappings across devices.
*/
data[0] = HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[0].sGyroY);
data[1] = HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[0].sGyroZ);
data[2] = HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[0].sGyroX);
data[0] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[1].sGyroY);
data[1] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[1].sGyroZ);
data[2] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[1].sGyroX);
data[0] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[2].sGyroY);
data[1] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[2].sGyroZ);
data[2] += HIDAPI_DriverSwitch_ScaleGyro(packet->imuState[2].sGyroX);
data[0] /= -3.f;
data[1] /= 3.f;
data[2] /= -3.f;
/* Right Joy-Con flips some axes, so let's flip them back for consistency */
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
data[0] = -data[0];
data[1] = -data[1];
}
SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3);
data[0] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelY);
data[1] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelZ);
data[2] = HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[0].sAccelX);
data[0] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[1].sAccelY);
data[1] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[1].sAccelZ);
data[2] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[1].sAccelX);
data[0] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[2].sAccelY);
data[1] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[2].sAccelZ);
data[2] += HIDAPI_DriverSwitch_ScaleAccel(packet->imuState[2].sAccelX);
data[0] /= -3.f;
data[1] /= 3.f;
data[2] /= -3.f;
/* Right Joy-Con flips some axes, so let's flip them back for consistency */
if (ctx->m_eControllerType == k_eSwitchDeviceInfoControllerType_JoyConRight) {
data[0] = -data[0];
data[1] = -data[1];
}
SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3);
}
ctx->m_lastFullState = *packet;
}
@@ -1252,7 +1445,7 @@ HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
} else if (ctx->m_bRumbleActive &&
SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleSent + RUMBLE_REFRESH_FREQUENCY_MS)) {
#ifdef DEBUG_RUMBLE
SDL_Log("Sent continuing rumble\n");
SDL_Log("Sent continuing rumble, %d ms after previous rumble\n", SDL_GetTicks() - ctx->m_unRumbleSent);
#endif
WriteRumble(ctx);
}
@@ -1277,11 +1470,15 @@ HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joyst
SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
SDL_GameControllerButtonReportingHintChanged, ctx);
hid_close(device->dev);
device->dev = NULL;
SDL_LockMutex(device->dev_lock);
{
hid_close(device->dev);
device->dev = NULL;
SDL_free(device->context);
device->context = NULL;
SDL_free(device->context);
device->context = NULL;
}
SDL_UnlockMutex(device->dev_lock);
}
static void