early-access version 1667
This commit is contained in:
+245
-48
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user