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
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d ®2 endm macro vzip8 reg2 vzip d d ®2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld [DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp local skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
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.