24 #include "../../SDL_internal.h"
26 #ifdef SDL_JOYSTICK_HIDAPI
34 #include "../../SDL_hints_c.h"
35 #include "../SDL_sysjoystick.h"
40 #ifdef SDL_JOYSTICK_HIDAPI_SWITCH
43 k_eSwitchInputReportIDs_SubcommandReply = 0x21,
44 k_eSwitchInputReportIDs_FullControllerState = 0x30,
45 k_eSwitchInputReportIDs_SimpleControllerState = 0x3F,
46 k_eSwitchInputReportIDs_CommandAck = 0x81,
47 } ESwitchInputReportIDs;
50 k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01,
51 k_eSwitchOutputReportIDs_Rumble = 0x10,
52 k_eSwitchOutputReportIDs_Proprietary = 0x80,
53 } ESwitchOutputReportIDs;
56 k_eSwitchSubcommandIDs_BluetoothManualPair = 0x01,
57 k_eSwitchSubcommandIDs_RequestDeviceInfo = 0x02,
58 k_eSwitchSubcommandIDs_SetInputReportMode = 0x03,
59 k_eSwitchSubcommandIDs_SetHCIState = 0x06,
60 k_eSwitchSubcommandIDs_SPIFlashRead = 0x10,
61 k_eSwitchSubcommandIDs_SetPlayerLights = 0x30,
62 k_eSwitchSubcommandIDs_SetHomeLight = 0x38,
63 k_eSwitchSubcommandIDs_EnableIMU = 0x40,
64 k_eSwitchSubcommandIDs_SetIMUSensitivity = 0x41,
65 k_eSwitchSubcommandIDs_EnableVibration = 0x48,
66 } ESwitchSubcommandIDs;
69 k_eSwitchProprietaryCommandIDs_Handshake = 0x02,
70 k_eSwitchProprietaryCommandIDs_HighSpeed = 0x03,
71 k_eSwitchProprietaryCommandIDs_ForceUSB = 0x04,
72 k_eSwitchProprietaryCommandIDs_ClearUSB = 0x05,
73 k_eSwitchProprietaryCommandIDs_ResetMCU = 0x06,
74 } ESwitchProprietaryCommandIDs;
77 k_eSwitchDeviceInfoControllerType_JoyConLeft = 0x1,
78 k_eSwitchDeviceInfoControllerType_JoyConRight = 0x2,
79 k_eSwitchDeviceInfoControllerType_ProController = 0x3,
80 } ESwitchDeviceInfoControllerType;
82 #define k_unSwitchOutputPacketDataLength 49
83 #define k_unSwitchMaxOutputPacketLength 64
84 #define k_unSwitchBluetoothPacketLength k_unSwitchOutputPacketDataLength
85 #define k_unSwitchUSBPacketLength k_unSwitchMaxOutputPacketLength
87 #define k_unSPIStickCalibrationStartOffset 0x603D
88 #define k_unSPIStickCalibrationEndOffset 0x604E
89 #define k_unSPIStickCalibrationLength (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1)
96 Uint8 rgucJoystickLeft[2];
97 Uint8 rgucJoystickRight[2];
98 } SwitchInputOnlyControllerStatePacket_t;
102 Uint8 rgucButtons[2];
106 } SwitchSimpleStatePacket_t;
111 Uint8 ucBatteryAndConnection;
112 Uint8 rgucButtons[3];
113 Uint8 rgucJoystickLeft[3];
114 Uint8 rgucJoystickRight[3];
115 Uint8 ucVibrationCode;
116 } SwitchControllerStatePacket_t;
120 SwitchControllerStatePacket_t controllerState;
131 } SwitchStatePacket_t;
141 SwitchControllerStatePacket_t m_controllerState;
143 Uint8 ucSubcommandAck;
144 Uint8 ucSubcommandID;
146 #define k_unSubcommandDataBytes 35
148 Uint8 rgucSubcommandData[k_unSubcommandDataBytes];
151 SwitchSPIOpData_t opData;
152 Uint8 rgucReadData[k_unSubcommandDataBytes -
sizeof(SwitchSPIOpData_t)];
156 Uint8 rgucFirmwareVersion[2];
159 Uint8 rgucMACAddress[6];
161 Uint8 ucColorLocation;
164 } SwitchSubcommandInputPacket_t;
169 } SwitchRumbleData_t;
174 Uint8 ucPacketNumber;
175 SwitchRumbleData_t rumbleData[2];
176 } SwitchCommonOutputPacket_t;
180 SwitchCommonOutputPacket_t commonData;
182 Uint8 ucSubcommandID;
183 Uint8 rgucSubcommandData[k_unSwitchOutputPacketDataLength -
sizeof(SwitchCommonOutputPacket_t) - 1];
184 } SwitchSubcommandOutputPacket_t;
189 Uint8 ucProprietaryID;
191 Uint8 rgucProprietaryData[k_unSwitchOutputPacketDataLength - 1 - 1];
192 } SwitchProprietaryOutputPacket_t;
196 SDL_HIDAPI_Device *
device;
202 Uint8 m_nCommandNumber;
203 SwitchCommonOutputPacket_t m_RumblePacket;
204 Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
208 SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
209 SwitchSimpleStatePacket_t m_lastSimpleState;
210 SwitchStatePacket_t m_lastFullState;
212 struct StickCalibrationData {
220 struct StickExtents {
226 } SDL_DriverSwitch_Context;
229 static SDL_bool IsGameCubeFormFactor(
int vendor_id,
int product_id)
231 static Uint32 gamecube_formfactor[] = {
239 if (
id == gamecube_formfactor[
i]) {
262 HIDAPI_DriverSwitch_GetDeviceName(
Uint16 vendor_id,
Uint16 product_id)
265 return "Nintendo Switch Pro Controller";
268 static int ReadInput(SDL_DriverSwitch_Context *
ctx)
278 static int WriteOutput(SDL_DriverSwitch_Context *
ctx,
const Uint8 *
data,
int size)
281 if (SDL_HIDAPI_LockRumble() < 0) {
284 return SDL_HIDAPI_SendRumbleAndUnlock(
ctx->device,
data,
size);
287 static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *
ctx, ESwitchSubcommandIDs expectedID)
294 while ((nRead = ReadInput(
ctx)) != -1) {
296 if (
ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) {
297 SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&
ctx->m_rgucReadBuffer[1];
298 if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) {
313 static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *
ctx, ESwitchProprietaryCommandIDs expectedID)
320 while ((nRead = ReadInput(
ctx)) != -1) {
322 if (
ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck &&
ctx->m_rgucReadBuffer[1] == expectedID) {
336 static void ConstructSubcommand(SDL_DriverSwitch_Context *
ctx, ESwitchSubcommandIDs ucCommandID,
Uint8 *pBuf,
Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
340 outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
341 outPacket->commonData.ucPacketNumber =
ctx->m_nCommandNumber;
343 SDL_memcpy(&outPacket->commonData.rumbleData, &
ctx->m_RumblePacket.rumbleData,
sizeof(
ctx->m_RumblePacket.rumbleData));
345 outPacket->ucSubcommandID = ucCommandID;
346 SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen);
348 ctx->m_nCommandNumber = (
ctx->m_nCommandNumber + 1) & 0xF;
351 static SDL_bool WritePacket(SDL_DriverSwitch_Context *
ctx,
void *pBuf,
Uint8 ucLen)
353 Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
354 const size_t unWriteSize =
ctx->m_bUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
356 if (ucLen > k_unSwitchOutputPacketDataLength) {
360 if (ucLen < unWriteSize) {
362 SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen);
364 ucLen = (
Uint8)unWriteSize;
366 return (WriteOutput(
ctx, (
Uint8 *)pBuf, ucLen) >= 0);
369 static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *
ctx, ESwitchSubcommandIDs ucCommandID,
Uint8 *pBuf,
Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
372 SwitchSubcommandInputPacket_t *reply =
NULL;
374 while (!reply && nRetries--) {
375 SwitchSubcommandOutputPacket_t commandPacket;
376 ConstructSubcommand(
ctx, ucCommandID, pBuf, ucLen, &commandPacket);
378 if (!WritePacket(
ctx, &commandPacket,
sizeof(commandPacket))) {
382 reply = ReadSubcommandReply(
ctx, ucCommandID);
388 return reply !=
NULL;
391 static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *
ctx, ESwitchProprietaryCommandIDs ucCommand,
Uint8 *pBuf,
Uint8 ucLen,
SDL_bool waitForReply)
396 SwitchProprietaryOutputPacket_t packet;
398 if ((!pBuf && ucLen > 0) || ucLen >
sizeof(packet.rgucProprietaryData)) {
402 packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
403 packet.ucProprietaryID = ucCommand;
405 SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen);
408 if (!WritePacket(
ctx, &packet,
sizeof(packet))) {
412 if (!waitForReply || ReadProprietaryReply(
ctx, ucCommand)) {
419 static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
421 pRumble->rgucData[0] = 0x00;
422 pRumble->rgucData[1] = 0x01;
423 pRumble->rgucData[2] = 0x40;
424 pRumble->rgucData[3] = 0x40;
427 static void EncodeRumble(SwitchRumbleData_t *pRumble,
Uint16 usHighFreq,
Uint8 ucHighFreqAmp,
Uint8 ucLowFreq,
Uint16 usLowFreqAmp)
429 if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) {
432 pRumble->rgucData[0] = usHighFreq & 0xFF;
433 pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01);
435 pRumble->rgucData[2] = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80);
436 pRumble->rgucData[3] = usLowFreqAmp & 0xFF;
439 SDL_Log(
"Freq: %.2X %.2X %.2X, Amp: %.2X %.2X %.2X\n",
440 usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq,
441 ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
444 SetNeutralRumble(pRumble);
448 static SDL_bool WriteRumble(SDL_DriverSwitch_Context *
ctx)
453 ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble;
454 ctx->m_RumblePacket.ucPacketNumber =
ctx->m_nCommandNumber;
455 ctx->m_nCommandNumber = (
ctx->m_nCommandNumber + 1) & 0xF;
458 if (
ctx->m_bRumbleActive) {
460 if (!
ctx->m_unRumbleRefresh) {
461 ctx->m_unRumbleRefresh = 1;
464 ctx->m_unRumbleRefresh = 0;
467 return WritePacket(
ctx, (
Uint8 *)&
ctx->m_RumblePacket,
sizeof(
ctx->m_RumblePacket));
470 static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *
ctx)
477 if (!WriteProprietary(
ctx, k_eSwitchProprietaryCommandIDs_Handshake,
NULL, 0,
SDL_TRUE)) {
480 if (!WriteProprietary(
ctx, k_eSwitchProprietaryCommandIDs_HighSpeed,
NULL, 0,
SDL_TRUE)) {
484 if (!WriteProprietary(
ctx, k_eSwitchProprietaryCommandIDs_Handshake,
NULL, 0,
SDL_TRUE)) {
492 return WriteSubcommand(
ctx, k_eSwitchSubcommandIDs_EnableVibration, &
enabled,
sizeof(
enabled),
NULL);
495 static SDL_bool SetInputMode(SDL_DriverSwitch_Context *
ctx,
Uint8 input_mode)
497 return WriteSubcommand(
ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1,
NULL);
502 Uint8 ucLedIntensity = 0;
505 if (brightness > 0) {
506 if (brightness < 65) {
507 ucLedIntensity = (brightness + 5) / 10;
513 rgucBuffer[0] = (0x0 << 4) | 0
x1;
514 rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0;
515 rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0;
516 rgucBuffer[3] = (0x0 << 4) | 0
x0;
518 return WriteSubcommand(
ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer,
sizeof(rgucBuffer),
NULL);
523 Uint8 led_data = (1 << slot);
524 return WriteSubcommand(
ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data,
sizeof(led_data),
NULL);
527 static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *
ctx)
531 SwitchSubcommandInputPacket_t *reply =
NULL;
534 SwitchSPIOpData_t readParams;
535 readParams.unAddress = k_unSPIStickCalibrationStartOffset;
536 readParams.ucLength = k_unSPIStickCalibrationLength;
538 if (!WriteSubcommand(
ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (
uint8_t *)&readParams,
sizeof(readParams), &reply)) {
547 pStickCal = reply->spiReadData.rgucReadData;
550 ctx->m_StickCalData[0].axis[0].sMax = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0];
551 ctx->m_StickCalData[0].axis[1].sMax = (pStickCal[2] << 4) | (pStickCal[1] >> 4);
552 ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3];
553 ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4);
554 ctx->m_StickCalData[0].axis[0].sMin = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6];
555 ctx->m_StickCalData[0].axis[1].sMin = (pStickCal[8] << 4) | (pStickCal[7] >> 4);
558 ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9];
559 ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4);
560 ctx->m_StickCalData[1].axis[0].sMin = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12];
561 ctx->m_StickCalData[1].axis[1].sMin = (pStickCal[14] << 4) | (pStickCal[13] >> 4);
562 ctx->m_StickCalData[1].axis[0].sMax = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15];
563 ctx->m_StickCalData[1].axis[1].sMax = (pStickCal[17] << 4) | (pStickCal[16] >> 4);
566 for (stick = 0; stick < 2; ++stick) {
568 if (
ctx->m_StickCalData[stick].axis[
axis].sCenter == 0xFFF) {
569 ctx->m_StickCalData[stick].axis[
axis].sCenter = 0;
571 if (
ctx->m_StickCalData[stick].axis[
axis].sMax == 0xFFF) {
572 ctx->m_StickCalData[stick].axis[
axis].sMax = 0;
574 if (
ctx->m_StickCalData[stick].axis[
axis].sMin == 0xFFF) {
575 ctx->m_StickCalData[stick].axis[
axis].sMin = 0;
580 if (
ctx->m_bUsingBluetooth) {
581 for (stick = 0; stick < 2; ++stick) {
588 for (stick = 0; stick < 2; ++stick) {
590 ctx->m_StickExtents[stick].axis[
axis].sMin = -(
Sint16)(
ctx->m_StickCalData[stick].axis[
axis].sMin * 0.7f);
591 ctx->m_StickExtents[stick].axis[
axis].sMax = (
Sint16)(
ctx->m_StickCalData[stick].axis[
axis].sMax * 0.7f);
598 static float fsel(
float fComparand,
float fValGE,
float fLT)
600 return fComparand >= 0 ? fValGE : fLT;
603 static float RemapVal(
float val,
float A,
float B,
float C,
float D)
606 return fsel(
val - B , D , C);
608 return C + (D - C) * (
val - A) / (B - A);
611 static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *
ctx,
int nStick,
int nAxis,
Sint16 sRawValue,
Sint16 sCenter)
613 sRawValue -= sCenter;
615 if (sRawValue >
ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
616 ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
618 if (sRawValue < ctx->m_StickExtents[nStick].
axis[nAxis].sMin) {
619 ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
629 static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *
ctx,
int nStick,
int nAxis,
Sint16 sRawValue)
631 return ApplyStickCalibrationCentered(
ctx, nStick, nAxis, sRawValue,
ctx->m_StickCalData[nStick].axis[nAxis].sCenter);
634 static void SDLCALL SDL_GameControllerButtonReportingHintChanged(
void *userdata,
const char *
name,
const char *oldValue,
const char *hint)
636 SDL_DriverSwitch_Context *
ctx = (SDL_DriverSwitch_Context *)userdata;
642 if (!
ctx->m_bUseButtonLabels) {
644 if (
ctx->m_bIsGameCube) {
672 HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *
device)
684 HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *
device,
SDL_JoystickID instance_id,
int player_index)
689 HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *
device, SDL_Joystick *joystick)
691 SDL_DriverSwitch_Context *
ctx;
710 if (!
ctx->m_bInputOnly) {
715 SetNeutralRumble(&
ctx->m_RumblePacket.rumbleData[0]);
716 SetNeutralRumble(&
ctx->m_RumblePacket.rumbleData[1]);
719 if (!BTrySetupUSB(
ctx)) {
723 if (!LoadStickCalibration(
ctx)) {
728 if (!SetVibrationEnabled(
ctx, 1)) {
734 if (
ctx->m_bUsingBluetooth) {
735 input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
737 input_mode = k_eSwitchInputReportIDs_FullControllerState;
739 if (!SetInputMode(
ctx, input_mode)) {
745 if (!
ctx->m_bUsingBluetooth) {
747 if (!WriteProprietary(
ctx, k_eSwitchProprietaryCommandIDs_ForceUSB,
NULL, 0,
SDL_FALSE)) {
754 if (
ctx->m_bHasHomeLED) {
755 SetHomeLED(
ctx, 100);
757 SetSlotLED(
ctx, (joystick->instance_id % 4));
760 if (IsGameCubeFormFactor(
device->vendor_id,
device->product_id)) {
766 SDL_GameControllerButtonReportingHintChanged,
ctx);
788 HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *
device, SDL_Joystick *joystick,
Uint16 low_frequency_rumble,
Uint16 high_frequency_rumble)
790 SDL_DriverSwitch_Context *
ctx = (SDL_DriverSwitch_Context *)
device->context;
798 const Uint16 k_usHighFreq = 0x0074;
799 const Uint8 k_ucHighFreqAmp = 0xBE;
800 const Uint8 k_ucLowFreq = 0x3D;
801 const Uint16 k_usLowFreqAmp = 0x806F;
803 if (low_frequency_rumble) {
804 EncodeRumble(&
ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
806 SetNeutralRumble(&
ctx->m_RumblePacket.rumbleData[0]);
809 if (high_frequency_rumble) {
810 EncodeRumble(&
ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
812 SetNeutralRumble(&
ctx->m_RumblePacket.rumbleData[1]);
817 if (!WriteRumble(
ctx)) {
824 static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *
ctx, SwitchInputOnlyControllerStatePacket_t *packet)
828 if (packet->rgucButtons[0] !=
ctx->m_lastInputOnlyState.rgucButtons[0]) {
837 axis = (
data & 0x40) ? 32767 : -32768;
840 axis = (
data & 0x80) ? 32767 : -32768;
844 if (packet->rgucButtons[1] !=
ctx->m_lastInputOnlyState.rgucButtons[1]) {
853 if (packet->ucStickHat !=
ctx->m_lastInputOnlyState.ucStickHat) {
859 switch (packet->ucStickHat) {
897 if (packet->rgucJoystickLeft[0] !=
ctx->m_lastInputOnlyState.rgucJoystickLeft[0]) {
902 if (packet->rgucJoystickLeft[1] !=
ctx->m_lastInputOnlyState.rgucJoystickLeft[1]) {
907 if (packet->rgucJoystickRight[0] !=
ctx->m_lastInputOnlyState.rgucJoystickRight[0]) {
912 if (packet->rgucJoystickRight[1] !=
ctx->m_lastInputOnlyState.rgucJoystickRight[1]) {
917 ctx->m_lastInputOnlyState = *packet;
920 static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *
ctx, SwitchSimpleStatePacket_t *packet)
923 const Uint16 usJoystickCenter = 0x8000;
926 if (packet->rgucButtons[0] !=
ctx->m_lastSimpleState.rgucButtons[0]) {
935 axis = (
data & 0x40) ? 32767 : -32768;
938 axis = (
data & 0x80) ? 32767 : -32768;
942 if (packet->rgucButtons[1] !=
ctx->m_lastSimpleState.rgucButtons[1]) {
951 if (packet->ucStickHat !=
ctx->m_lastSimpleState.ucStickHat) {
957 switch (packet->ucStickHat) {
995 axis = ApplyStickCalibrationCentered(
ctx, 0, 0, packet->sJoystickLeft[0], (
Sint16)usJoystickCenter);
998 axis = ApplyStickCalibrationCentered(
ctx, 0, 1, packet->sJoystickLeft[1], (
Sint16)usJoystickCenter);
1001 axis = ApplyStickCalibrationCentered(
ctx, 1, 0, packet->sJoystickRight[0], (
Sint16)usJoystickCenter);
1004 axis = ApplyStickCalibrationCentered(
ctx, 1, 1, packet->sJoystickRight[1], (
Sint16)usJoystickCenter);
1007 ctx->m_lastSimpleState = *packet;
1010 static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *
ctx, SwitchStatePacket_t *packet)
1014 if (packet->controllerState.rgucButtons[0] !=
ctx->m_lastFullState.controllerState.rgucButtons[0]) {
1015 Uint8 data = packet->controllerState.rgucButtons[0];
1021 axis = (
data & 0x80) ? 32767 : -32768;
1025 if (packet->controllerState.rgucButtons[1] !=
ctx->m_lastFullState.controllerState.rgucButtons[1]) {
1026 Uint8 data = packet->controllerState.rgucButtons[1];
1035 if (packet->controllerState.rgucButtons[2] !=
ctx->m_lastFullState.controllerState.rgucButtons[2]) {
1036 Uint8 data = packet->controllerState.rgucButtons[2];
1042 axis = (
data & 0x80) ? 32767 : -32768;
1046 axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8);
1050 axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4);
1054 axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8);
1058 axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4);
1065 if (packet->controllerState.ucBatteryAndConnection & 0
x1) {
1071 int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
1074 }
else if (
level <= 2) {
1076 }
else if (
level <= 6) {
1083 ctx->m_lastFullState = *packet;
1087 HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *
device)
1089 SDL_DriverSwitch_Context *
ctx = (SDL_DriverSwitch_Context *)
device->context;
1090 SDL_Joystick *joystick =
NULL;
1100 while ((
size = ReadInput(
ctx)) > 0) {
1101 if (
ctx->m_bInputOnly) {
1102 HandleInputOnlyControllerState(joystick,
ctx, (SwitchInputOnlyControllerStatePacket_t *)&
ctx->m_rgucReadBuffer[0]);
1104 switch (
ctx->m_rgucReadBuffer[0]) {
1105 case k_eSwitchInputReportIDs_SimpleControllerState:
1106 HandleSimpleControllerState(joystick,
ctx, (SwitchSimpleStatePacket_t *)&
ctx->m_rgucReadBuffer[1]);
1108 case k_eSwitchInputReportIDs_FullControllerState:
1109 HandleFullControllerState(joystick,
ctx, (SwitchStatePacket_t *)&
ctx->m_rgucReadBuffer[1]);
1117 if (
ctx->m_bRumbleActive &&
1130 HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *
device, SDL_Joystick *joystick)
1132 SDL_DriverSwitch_Context *
ctx = (SDL_DriverSwitch_Context *)
device->context;
1134 if (!
ctx->m_bInputOnly) {
1136 SetInputMode(
ctx, k_eSwitchInputReportIDs_SimpleControllerState);
1140 SDL_GameControllerButtonReportingHintChanged,
ctx);
1150 HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device *
device)
1158 HIDAPI_DriverSwitch_IsSupportedDevice,
1159 HIDAPI_DriverSwitch_GetDeviceName,
1160 HIDAPI_DriverSwitch_InitDevice,
1161 HIDAPI_DriverSwitch_GetDevicePlayerIndex,
1162 HIDAPI_DriverSwitch_SetDevicePlayerIndex,
1163 HIDAPI_DriverSwitch_UpdateDevice,
1164 HIDAPI_DriverSwitch_OpenJoystick,
1165 HIDAPI_DriverSwitch_RumbleJoystick,
1166 HIDAPI_DriverSwitch_CloseJoystick,
1167 HIDAPI_DriverSwitch_FreeDevice