24 #include "../../SDL_internal.h" 26 #ifdef SDL_JOYSTICK_HIDAPI 34 #include "../SDL_sysjoystick.h" 38 #ifdef SDL_JOYSTICK_HIDAPI_SWITCH 41 k_eSwitchInputReportIDs_SubcommandReply = 0x21,
42 k_eSwitchInputReportIDs_FullControllerState = 0x30,
43 k_eSwitchInputReportIDs_SimpleControllerState = 0x3F,
44 k_eSwitchInputReportIDs_CommandAck = 0x81,
45 } ESwitchInputReportIDs;
48 k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01,
49 k_eSwitchOutputReportIDs_Rumble = 0x10,
50 k_eSwitchOutputReportIDs_Proprietary = 0x80,
51 } ESwitchOutputReportIDs;
54 k_eSwitchSubcommandIDs_BluetoothManualPair = 0x01,
55 k_eSwitchSubcommandIDs_RequestDeviceInfo = 0x02,
56 k_eSwitchSubcommandIDs_SetInputReportMode = 0x03,
57 k_eSwitchSubcommandIDs_SetHCIState = 0x06,
58 k_eSwitchSubcommandIDs_SPIFlashRead = 0x10,
59 k_eSwitchSubcommandIDs_SetPlayerLights = 0x30,
60 k_eSwitchSubcommandIDs_SetHomeLight = 0x38,
61 k_eSwitchSubcommandIDs_EnableIMU = 0x40,
62 k_eSwitchSubcommandIDs_SetIMUSensitivity = 0x41,
63 k_eSwitchSubcommandIDs_EnableVibration = 0x48,
64 } ESwitchSubcommandIDs;
67 k_eSwitchProprietaryCommandIDs_Handshake = 0x02,
68 k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03,
69 k_eSwitchProprietaryCommandIDs_ForceUSB = 0x04,
70 k_eSwitchProprietaryCommandIDs_ClearUSB = 0x05,
71 k_eSwitchProprietaryCommandIDs_ResetMCU = 0x06,
72 } ESwitchProprietaryCommandIDs;
75 k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1,
76 k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2,
77 k_eSwitchDeviceInfoControllerType_ProController = 0x3,
78 } ESwitchDeviceInfoControllerType;
80 #define k_unSwitchOutputPacketDataLength 49 81 #define k_unSwitchMaxOutputPacketLength 64 82 #define k_unSwitchBluetoothPacketLength k_unSwitchOutputPacketDataLength 83 #define k_unSwitchUSBPacketLength k_unSwitchMaxOutputPacketLength 85 #define k_unSPIStickCalibrationStartOffset 0x603D 86 #define k_unSPIStickCalibrationEndOffset 0x604E 87 #define k_unSPIStickCalibrationLength (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1) 96 } SwitchSimpleStatePacket_t;
101 Uint8 ucBatteryAndConnection;
102 Uint8 rgucButtons[3];
103 Uint8 rgucJoystickLeft[3];
104 Uint8 rgucJoystickRight[3];
105 Uint8 ucVibrationCode;
106 } SwitchControllerStatePacket_t;
110 SwitchControllerStatePacket_t controllerState;
121 } SwitchStatePacket_t;
131 SwitchControllerStatePacket_t m_controllerState;
133 Uint8 ucSubcommandAck;
134 Uint8 ucSubcommandID;
136 #define k_unSubcommandDataBytes 35 138 Uint8 rgucSubcommandData[ k_unSubcommandDataBytes ];
141 SwitchSPIOpData_t opData;
142 Uint8 rgucReadData[ k_unSubcommandDataBytes -
sizeof(SwitchSPIOpData_t) ];
146 Uint8 rgucFirmwareVersion[2];
149 Uint8 rgucMACAddress[6];
151 Uint8 ucColorLocation;
154 } SwitchSubcommandInputPacket_t;
159 } SwitchRumbleData_t;
164 Uint8 ucPacketNumber;
165 SwitchRumbleData_t rumbleData[2];
166 } SwitchCommonOutputPacket_t;
170 SwitchCommonOutputPacket_t commonData;
172 Uint8 ucSubcommandID;
173 Uint8 rgucSubcommandData[ k_unSwitchOutputPacketDataLength -
sizeof(SwitchCommonOutputPacket_t) - 1 ];
174 } SwitchSubcommandOutputPacket_t;
179 Uint8 ucProprietaryID;
181 Uint8 rgucProprietaryData[ k_unSwitchOutputPacketDataLength - 1 - 1 ];
182 } SwitchProprietaryOutputPacket_t;
188 Uint8 m_nCommandNumber;
189 SwitchCommonOutputPacket_t m_RumblePacket;
190 Uint32 m_nRumbleExpiration;
191 Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
192 SwitchSimpleStatePacket_t m_lastSimpleState;
193 SwitchStatePacket_t m_lastFullState;
195 struct StickCalibrationData {
203 struct StickExtents {
209 } SDL_DriverSwitch_Context;
213 HIDAPI_DriverSwitch_IsSupportedDevice(
Uint16 vendor_id,
Uint16 product_id,
Uint16 version,
int interface_number)
219 HIDAPI_DriverSwitch_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
223 return "Nintendo Switch Pro Controller";
228 static int ReadInput(SDL_DriverSwitch_Context *
ctx)
230 return hid_read_timeout(ctx->dev, ctx->m_rgucReadBuffer,
sizeof(ctx->m_rgucReadBuffer), 0);
233 static int WriteOutput(SDL_DriverSwitch_Context *
ctx,
Uint8 *
data,
int size)
238 static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *
ctx, ESwitchSubcommandIDs expectedID)
245 while ((nRead = ReadInput(ctx)) != -1) {
247 if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) {
248 SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&ctx->m_rgucReadBuffer[ 1 ];
249 if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) {
264 static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs expectedID)
271 while ((nRead = ReadInput(ctx)) != -1) {
273 if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck && ctx->m_rgucReadBuffer[ 1 ] == expectedID) {
287 static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID,
Uint8 *pBuf,
Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
291 outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
292 outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber;
294 SDL_memcpy(&outPacket->commonData.rumbleData, &ctx->m_RumblePacket.rumbleData,
sizeof(ctx->m_RumblePacket.rumbleData));
296 outPacket->ucSubcommandID = ucCommandID;
297 SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen);
299 ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
302 static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx,
void *pBuf,
Uint8 ucLen)
304 Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
305 const size_t unWriteSize = ctx->m_bIsUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
307 if (ucLen > k_unSwitchOutputPacketDataLength) {
311 if (ucLen < unWriteSize) {
313 SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen);
315 ucLen = (
Uint8)unWriteSize;
317 return (WriteOutput(ctx, (
Uint8 *)pBuf, ucLen) >= 0);
320 static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID,
Uint8 *pBuf,
Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
323 SwitchSubcommandInputPacket_t *reply =
NULL;
325 while (!reply && nRetries--) {
326 SwitchSubcommandOutputPacket_t commandPacket;
327 ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket);
329 if (!WritePacket(ctx, &commandPacket,
sizeof(commandPacket))) {
333 reply = ReadSubcommandReply(ctx, ucCommandID);
339 return reply !=
NULL;
342 static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand,
Uint8 *pBuf,
Uint8 ucLen,
SDL_bool waitForReply)
347 SwitchProprietaryOutputPacket_t packet;
349 if ((!pBuf && ucLen > 0) || ucLen >
sizeof(packet.rgucProprietaryData)) {
353 packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
354 packet.ucProprietaryID = ucCommand;
355 SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen);
357 if (!WritePacket(ctx, &packet,
sizeof(packet))) {
361 if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) {
368 static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
370 pRumble->rgucData[0] = 0x00;
371 pRumble->rgucData[1] = 0x01;
372 pRumble->rgucData[2] = 0x40;
373 pRumble->rgucData[3] = 0x40;
376 static void EncodeRumble(SwitchRumbleData_t *pRumble,
Uint16 usHighFreq,
Uint8 ucHighFreqAmp,
Uint8 ucLowFreq,
Uint16 usLowFreqAmp)
378 if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) {
381 pRumble->rgucData[0] = usHighFreq & 0xFF;
382 pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01);
384 pRumble->rgucData[2] = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80);
385 pRumble->rgucData[3] = usLowFreqAmp & 0xFF;
388 SDL_Log(
"Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X\n",
389 usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq,
390 ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
393 SetNeutralRumble(pRumble);
397 static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
402 ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble;
403 ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber;
404 ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
406 return WritePacket(ctx, (
Uint8 *)&ctx->m_RumblePacket,
sizeof(ctx->m_RumblePacket));
409 static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
416 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake,
NULL, 0,
SDL_TRUE)) {
419 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_HighSpeed,
NULL, 0,
SDL_TRUE)) {
422 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake,
NULL, 0,
SDL_TRUE)) {
430 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableVibration, &enabled,
sizeof(enabled),
NULL);
433 static SDL_bool SetInputMode(SDL_DriverSwitch_Context *ctx,
Uint8 input_mode)
435 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1,
NULL);
438 static SDL_bool SetHomeLED(SDL_DriverSwitch_Context *ctx,
Uint8 brightness)
440 Uint8 ucLedIntensity = 0;
443 if (brightness > 0) {
444 if (brightness < 65) {
445 ucLedIntensity = (brightness + 5) / 10;
451 rgucBuffer[0] = (0x0 << 4) | 0
x1;
452 rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0;
453 rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0;
454 rgucBuffer[3] = (0x0 << 4) | 0
x0;
456 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer,
sizeof(rgucBuffer),
NULL);
459 static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx,
Uint8 slot)
461 Uint8 led_data = (1 << slot);
462 return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data,
sizeof(led_data),
NULL);
465 static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
469 SwitchSubcommandInputPacket_t *reply =
NULL;
472 SwitchSPIOpData_t readParams;
473 readParams.unAddress = k_unSPIStickCalibrationStartOffset;
474 readParams.ucLength = k_unSPIStickCalibrationLength;
476 if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (
uint8_t *)&readParams,
sizeof(readParams), &reply)) {
485 pStickCal = reply->spiReadData.rgucReadData;
488 ctx->m_StickCalData[0].axis[0].sMax = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0];
489 ctx->m_StickCalData[0].axis[1].sMax = (pStickCal[2] << 4) | (pStickCal[1] >> 4);
490 ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3];
491 ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4);
492 ctx->m_StickCalData[0].axis[0].sMin = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6];
493 ctx->m_StickCalData[0].axis[1].sMin = (pStickCal[8] << 4) | (pStickCal[7] >> 4);
496 ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9];
497 ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4);
498 ctx->m_StickCalData[1].axis[0].sMin = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12];
499 ctx->m_StickCalData[1].axis[1].sMin = (pStickCal[14] << 4) | (pStickCal[13] >> 4);
500 ctx->m_StickCalData[1].axis[0].sMax = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15];
501 ctx->m_StickCalData[1].axis[1].sMax = (pStickCal[17] << 4) | (pStickCal[16] >> 4);
504 for (stick = 0; stick < 2; ++stick) {
505 for (axis = 0; axis < 2; ++
axis) {
506 if (ctx->m_StickCalData[stick].axis[axis].sCenter == 0xFFF) {
507 ctx->m_StickCalData[stick].axis[
axis].sCenter = 0;
509 if (ctx->m_StickCalData[stick].axis[axis].sMax == 0xFFF) {
510 ctx->m_StickCalData[stick].axis[
axis].sMax = 0;
512 if (ctx->m_StickCalData[stick].axis[axis].sMin == 0xFFF) {
513 ctx->m_StickCalData[stick].axis[
axis].sMin = 0;
518 if (ctx->m_bIsUsingBluetooth) {
519 for (stick = 0; stick < 2; ++stick) {
520 for(axis = 0; axis < 2; ++
axis) {
526 for (stick = 0; stick < 2; ++stick) {
527 for(axis = 0; axis < 2; ++
axis) {
528 ctx->m_StickExtents[stick].axis[
axis].sMin = -(
Sint16)(ctx->m_StickCalData[stick].axis[axis].sMin * 0.7f);
529 ctx->m_StickExtents[stick].axis[
axis].sMax = (
Sint16)(ctx->m_StickCalData[stick].axis[axis].sMax * 0.7f);
536 static float fsel(
float fComparand,
float fValGE,
float fLT)
538 return fComparand >= 0 ? fValGE : fLT;
541 static float RemapVal(
float val,
float A,
float B,
float C,
float D)
544 return fsel(val - B , D , C);
546 return C + (D - C) * (val - A) / (B - A);
549 static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx,
int nStick,
int nAxis,
Sint16 sRawValue,
Sint16 sCenter)
551 sRawValue -= sCenter;
553 if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
554 ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
556 if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
557 ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
561 return (
Sint16)(RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0,
SDL_MAX_SINT16));
563 return (
Sint16)(RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0,
SDL_MIN_SINT16, 0));
567 static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx,
int nStick,
int nAxis,
Sint16 sRawValue)
569 return ApplyStickCalibrationCentered(ctx, nStick, nAxis, sRawValue, ctx->m_StickCalData[nStick].axis[nAxis].sCenter);
575 SDL_DriverSwitch_Context *
ctx;
578 ctx = (SDL_DriverSwitch_Context *)
SDL_calloc(1,
sizeof(*ctx));
588 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
589 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
592 if (!BTrySetupUSB(ctx)) {
593 ctx->m_bIsUsingBluetooth =
SDL_TRUE;
596 if (!LoadStickCalibration(ctx)) {
602 if (!SetVibrationEnabled(ctx, 1)) {
609 if (ctx->m_bIsUsingBluetooth) {
610 input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
612 input_mode = k_eSwitchInputReportIDs_FullControllerState;
614 if (!SetInputMode(ctx, input_mode)) {
621 if (!ctx->m_bIsUsingBluetooth) {
623 if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB,
NULL, 0,
SDL_FALSE)) {
631 SetHomeLED(ctx, 100);
632 SetSlotLED(ctx, (joystick->instance_id % 4));
643 HIDAPI_DriverSwitch_Rumble(SDL_Joystick *joystick,
hid_device *dev,
void *context,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble,
Uint32 duration_ms)
645 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
653 const Uint16 k_usHighFreq = 0x0074;
654 const Uint8 k_ucHighFreqAmp = 0xBE;
655 const Uint8 k_ucLowFreq = 0x3D;
656 const Uint16 k_usLowFreqAmp = 0x806F;
658 if (low_frequency_rumble) {
659 EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
661 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
664 if (high_frequency_rumble) {
665 EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
667 SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
670 if (!WriteRumble(ctx)) {
675 if ((low_frequency_rumble || high_frequency_rumble) && duration_ms) {
676 ctx->m_nRumbleExpiration =
SDL_GetTicks() + duration_ms;
678 ctx->m_nRumbleExpiration = 0;
683 static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchSimpleStatePacket_t *packet)
686 const Uint16 usJoystickCenter = 0x8000;
689 if (packet->rgucButtons[0] != ctx->m_lastSimpleState.rgucButtons[0]) {
698 axis = (data & 0x40) ? 32767 : -32768;
701 axis = (data & 0x80) ? 32767 : -32768;
705 if (packet->rgucButtons[1] != ctx->m_lastSimpleState.rgucButtons[1]) {
706 Uint8 data = packet->rgucButtons[1];
714 if (packet->ucStickHat != ctx->m_lastSimpleState.ucStickHat) {
720 switch (packet->ucStickHat) {
758 axis = ApplyStickCalibrationCentered(ctx, 0, 0, packet->sJoystickLeft[0], (
Sint16)usJoystickCenter);
761 axis = ApplyStickCalibrationCentered(ctx, 0, 1, packet->sJoystickLeft[1], (
Sint16)usJoystickCenter);
764 axis = ApplyStickCalibrationCentered(ctx, 1, 0, packet->sJoystickRight[0], (
Sint16)usJoystickCenter);
767 axis = ApplyStickCalibrationCentered(ctx, 1, 1, packet->sJoystickRight[1], (
Sint16)usJoystickCenter);
770 ctx->m_lastSimpleState = *packet;
773 static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
777 if (packet->controllerState.rgucButtons[0] != ctx->m_lastFullState.controllerState.rgucButtons[0]) {
778 Uint8 data = packet->controllerState.rgucButtons[0];
784 axis = (data & 0x80) ? 32767 : -32768;
788 if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) {
789 Uint8 data = packet->controllerState.rgucButtons[1];
798 if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) {
799 Uint8 data = packet->controllerState.rgucButtons[2];
805 axis = (data & 0x80) ? 32767 : -32768;
809 axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8);
810 axis = ApplyStickCalibration(ctx, 0, 0, axis);
813 axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4);
814 axis = ApplyStickCalibration(ctx, 0, 1, axis);
817 axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8);
818 axis = ApplyStickCalibration(ctx, 1, 0, axis);
821 axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4);
822 axis = ApplyStickCalibration(ctx, 1, 1, axis);
828 if (packet->controllerState.ucBatteryAndConnection & 0
x1) {
834 int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
837 }
else if (level <= 2) {
839 }
else if (level <= 6) {
846 ctx->m_lastFullState = *packet;
850 HIDAPI_DriverSwitch_Update(SDL_Joystick *joystick,
hid_device *dev,
void *context)
852 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
855 while ((size = ReadInput(ctx)) > 0) {
856 switch (ctx->m_rgucReadBuffer[0]) {
857 case k_eSwitchInputReportIDs_SimpleControllerState:
858 HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
860 case k_eSwitchInputReportIDs_FullControllerState:
861 HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
868 if (ctx->m_nRumbleExpiration) {
871 HIDAPI_DriverSwitch_Rumble(joystick, dev, context, 0, 0, 0);
879 HIDAPI_DriverSwitch_Quit(SDL_Joystick *joystick,
hid_device *dev,
void *context)
881 SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)context;
884 SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
893 HIDAPI_DriverSwitch_IsSupportedDevice,
894 HIDAPI_DriverSwitch_GetDeviceName,
895 HIDAPI_DriverSwitch_Init,
896 HIDAPI_DriverSwitch_Rumble,
897 HIDAPI_DriverSwitch_Update,
898 HIDAPI_DriverSwitch_Quit
GLuint GLfloat GLfloat GLfloat x1
#define SDL_HINT_JOYSTICK_HIDAPI_SWITCH
A variable controlling whether the HIDAPI driver for Nintendo Switch controllers should be used...
SDL_bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor, Uint16 product)
static screen_context_t context
int SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
Write an Output report to a HID device.
SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch
int SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
Read an Input report from a HID device with timeout.
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
struct hid_device_ hid_device
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define SDL_OutOfMemory()
#define SDL_MAX_SINT16
A signed 16-bit integer type.
#define SDL_TICKS_PASSED(A, B)
Compare SDL ticks values, and return true if A has passed B.