src/joystick/hidapi/SDL_hidapi_switch.c
author Sam Lantinga
Thu, 27 Feb 2020 13:53:32 -0800
changeset 13558 ed7c27865ea7
parent 13493 9ebdd8dfc588
child 13588 668a74d2aec1
permissions -rw-r--r--
Fixed trying to handle the HORI Wireless Switch Pad when connected via USB
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 /* This driver supports the Nintendo Switch Pro controller.
    22    Code and logic contributed by Valve Corporation under the SDL zlib license.
    23 */
    24 #include "../../SDL_internal.h"
    25 
    26 #ifdef SDL_JOYSTICK_HIDAPI
    27 
    28 #include "SDL_hints.h"
    29 #include "SDL_log.h"
    30 #include "SDL_events.h"
    31 #include "SDL_timer.h"
    32 #include "SDL_joystick.h"
    33 #include "SDL_gamecontroller.h"
    34 #include "../../SDL_hints_c.h"
    35 #include "../SDL_sysjoystick.h"
    36 #include "SDL_hidapijoystick_c.h"
    37 #include "SDL_hidapi_rumble.h"
    38 
    39 
    40 #ifdef SDL_JOYSTICK_HIDAPI_SWITCH
    41 
    42 typedef enum {
    43     k_eSwitchInputReportIDs_SubcommandReply       = 0x21,
    44     k_eSwitchInputReportIDs_FullControllerState   = 0x30,
    45     k_eSwitchInputReportIDs_SimpleControllerState = 0x3F,
    46     k_eSwitchInputReportIDs_CommandAck            = 0x81,
    47 } ESwitchInputReportIDs;
    48 
    49 typedef enum {
    50     k_eSwitchOutputReportIDs_RumbleAndSubcommand = 0x01,
    51     k_eSwitchOutputReportIDs_Rumble              = 0x10,
    52     k_eSwitchOutputReportIDs_Proprietary         = 0x80,
    53 } ESwitchOutputReportIDs;
    54 
    55 typedef enum {
    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;
    67 
    68 typedef enum {
    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;
    75 
    76 typedef enum {
    77     k_eSwitchDeviceInfoControllerType_JoyConLeft     = 0x1,
    78     k_eSwitchDeviceInfoControllerType_JoyConRight    = 0x2,
    79     k_eSwitchDeviceInfoControllerType_ProController  = 0x3,
    80 } ESwitchDeviceInfoControllerType;
    81 
    82 #define k_unSwitchOutputPacketDataLength 49
    83 #define k_unSwitchMaxOutputPacketLength  64
    84 #define k_unSwitchBluetoothPacketLength  k_unSwitchOutputPacketDataLength
    85 #define k_unSwitchUSBPacketLength        k_unSwitchMaxOutputPacketLength
    86 
    87 #define k_unSPIStickCalibrationStartOffset  0x603D
    88 #define k_unSPIStickCalibrationEndOffset    0x604E
    89 #define k_unSPIStickCalibrationLength       (k_unSPIStickCalibrationEndOffset - k_unSPIStickCalibrationStartOffset + 1)
    90 
    91 #pragma pack(1)
    92 typedef struct
    93 {
    94     Uint8 rgucButtons[2];
    95     Uint8 ucStickHat;
    96     Uint8 rgucJoystickLeft[2];
    97     Uint8 rgucJoystickRight[2];
    98 } SwitchInputOnlyControllerStatePacket_t;
    99 
   100 typedef struct
   101 {
   102     Uint8 rgucButtons[2];
   103     Uint8 ucStickHat;
   104     Sint16 sJoystickLeft[2];
   105     Sint16 sJoystickRight[2];
   106 } SwitchSimpleStatePacket_t;
   107 
   108 typedef struct
   109 {
   110     Uint8 ucCounter;
   111     Uint8 ucBatteryAndConnection;
   112     Uint8 rgucButtons[3];
   113     Uint8 rgucJoystickLeft[3];
   114     Uint8 rgucJoystickRight[3];
   115     Uint8 ucVibrationCode;
   116 } SwitchControllerStatePacket_t;
   117 
   118 typedef struct
   119 {
   120     SwitchControllerStatePacket_t controllerState;
   121 
   122     struct {
   123         Sint16 sAccelX;
   124         Sint16 sAccelY;
   125         Sint16 sAccelZ;
   126 
   127         Sint16 sGyroX;
   128         Sint16 sGyroY;
   129         Sint16 sGyroZ;
   130     } imuState[3];
   131 } SwitchStatePacket_t;
   132 
   133 typedef struct
   134 {
   135     Uint32 unAddress;
   136     Uint8 ucLength;
   137 } SwitchSPIOpData_t;
   138 
   139 typedef struct
   140 {
   141     SwitchControllerStatePacket_t m_controllerState;
   142 
   143     Uint8 ucSubcommandAck;
   144     Uint8 ucSubcommandID;
   145 
   146     #define k_unSubcommandDataBytes 35
   147     union {
   148         Uint8 rgucSubcommandData[k_unSubcommandDataBytes];
   149 
   150         struct {
   151             SwitchSPIOpData_t opData;
   152             Uint8 rgucReadData[k_unSubcommandDataBytes - sizeof(SwitchSPIOpData_t)];
   153         } spiReadData;
   154 
   155         struct {
   156             Uint8 rgucFirmwareVersion[2];
   157             Uint8 ucDeviceType;
   158             Uint8 ucFiller1;
   159             Uint8 rgucMACAddress[6];
   160             Uint8 ucFiller2;
   161             Uint8 ucColorLocation;
   162         } deviceInfo;
   163     };
   164 } SwitchSubcommandInputPacket_t;
   165 
   166 typedef struct
   167 {
   168     Uint8 rgucData[4];
   169 } SwitchRumbleData_t;
   170 
   171 typedef struct
   172 {
   173     Uint8 ucPacketType;
   174     Uint8 ucPacketNumber;
   175     SwitchRumbleData_t rumbleData[2];
   176 } SwitchCommonOutputPacket_t;
   177 
   178 typedef struct
   179 {
   180     SwitchCommonOutputPacket_t commonData;
   181 
   182     Uint8 ucSubcommandID;
   183     Uint8 rgucSubcommandData[k_unSwitchOutputPacketDataLength - sizeof(SwitchCommonOutputPacket_t) - 1];
   184 } SwitchSubcommandOutputPacket_t;
   185 
   186 typedef struct
   187 {
   188     Uint8 ucPacketType;
   189     Uint8 ucProprietaryID;
   190 
   191     Uint8 rgucProprietaryData[k_unSwitchOutputPacketDataLength - 1 - 1];
   192 } SwitchProprietaryOutputPacket_t;
   193 #pragma pack()
   194 
   195 typedef struct {
   196     SDL_HIDAPI_Device *device;
   197     SDL_bool m_bInputOnly;
   198     SDL_bool m_bHasHomeLED;
   199     SDL_bool m_bUsingBluetooth;
   200     SDL_bool m_bUseButtonLabels;
   201     Uint8 m_nCommandNumber;
   202     SwitchCommonOutputPacket_t m_RumblePacket;
   203     Uint8 m_rgucReadBuffer[k_unSwitchMaxOutputPacketLength];
   204     SDL_bool m_bRumbleActive;
   205     Uint32 m_unRumbleRefresh;
   206 
   207     SwitchInputOnlyControllerStatePacket_t m_lastInputOnlyState;
   208     SwitchSimpleStatePacket_t m_lastSimpleState;
   209     SwitchStatePacket_t m_lastFullState;
   210 
   211     struct StickCalibrationData {
   212         struct {
   213             Sint16 sCenter;
   214             Sint16 sMin;
   215             Sint16 sMax;
   216         } axis[2];
   217     } m_StickCalData[2];
   218 
   219     struct StickExtents {
   220         struct {
   221             Sint16 sMin;
   222             Sint16 sMax;
   223         } axis[2];
   224     } m_StickExtents[2];
   225 } SDL_DriverSwitch_Context;
   226 
   227 
   228 static SDL_bool IsGameCubeFormFactor(int vendor_id, int product_id)
   229 {
   230     static Uint32 gamecube_formfactor[] = {
   231         MAKE_VIDPID(0x0e6f, 0x0185),    /* PDP Wired Fight Pad Pro for Nintendo Switch */
   232         MAKE_VIDPID(0x20d6, 0xa711),    /* Core (Plus) Wired Controller */
   233     };
   234     Uint32 id = MAKE_VIDPID(vendor_id, product_id);
   235     int i;
   236 
   237     for (i = 0; i < SDL_arraysize(gamecube_formfactor); ++i) {
   238         if (id == gamecube_formfactor[i]) {
   239             return SDL_TRUE;
   240         }
   241     }
   242     return SDL_FALSE;
   243 }
   244 
   245 static SDL_bool
   246 HIDAPI_DriverSwitch_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol)
   247 {
   248     /* The HORI Wireless Switch Pad enumerates as a HID device when connected via USB
   249        with the same VID/PID as when connected over Bluetooth but doesn't actually
   250        support communication over USB. The most reliable way to block this without allowing the
   251        controller to continually attempt to reconnect is to filter it out by manufactuer/product string.
   252        Note that the controller does have a different product string when connected over Bluetooth.
   253      */
   254     if (SDL_strcmp( name, "HORI Wireless Switch Pad" ) == 0) {
   255         return SDL_FALSE;
   256     }
   257     return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO);
   258 }
   259 
   260 static const char *
   261 HIDAPI_DriverSwitch_GetDeviceName(Uint16 vendor_id, Uint16 product_id)
   262 {
   263     /* Give a user friendly name for this controller */
   264     return "Nintendo Switch Pro Controller";
   265 }
   266 
   267 static int ReadInput(SDL_DriverSwitch_Context *ctx)
   268 {
   269     /* Make sure we don't try to read at the same time a write is happening */
   270     if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) {
   271         return 0;
   272     }
   273 
   274     return hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
   275 }
   276 
   277 static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size)
   278 {
   279     /* Use the rumble thread for general asynchronous writes */
   280     if (SDL_HIDAPI_LockRumble() < 0) {
   281         return -1;
   282     }
   283     return SDL_HIDAPI_SendRumbleAndUnlock(ctx->device, data, size);
   284 }
   285 
   286 static SwitchSubcommandInputPacket_t *ReadSubcommandReply(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs expectedID)
   287 {
   288     /* Average response time for messages is ~30ms */
   289     Uint32 TimeoutMs = 100;
   290     Uint32 startTicks = SDL_GetTicks();
   291 
   292     int nRead = 0;
   293     while ((nRead = ReadInput(ctx)) != -1) {
   294         if (nRead > 0) {
   295             if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_SubcommandReply) {
   296                 SwitchSubcommandInputPacket_t *reply = (SwitchSubcommandInputPacket_t *)&ctx->m_rgucReadBuffer[1];
   297                 if (reply->ucSubcommandID == expectedID && (reply->ucSubcommandAck & 0x80)) {
   298                     return reply;
   299                 }
   300             }
   301         } else {
   302             SDL_Delay(1);
   303         }
   304 
   305         if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
   306             break;
   307         }
   308     }
   309     return NULL;
   310 }
   311 
   312 static SDL_bool ReadProprietaryReply(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs expectedID)
   313 {
   314     /* Average response time for messages is ~30ms */
   315     Uint32 TimeoutMs = 100;
   316     Uint32 startTicks = SDL_GetTicks();
   317 
   318     int nRead = 0;
   319     while ((nRead = ReadInput(ctx)) != -1) {
   320         if (nRead > 0) {
   321             if (ctx->m_rgucReadBuffer[0] == k_eSwitchInputReportIDs_CommandAck && ctx->m_rgucReadBuffer[1] == expectedID) {
   322                 return SDL_TRUE;
   323             }
   324         } else {
   325             SDL_Delay(1);
   326         }
   327 
   328         if (SDL_TICKS_PASSED(SDL_GetTicks(), startTicks + TimeoutMs)) {
   329             break;
   330         }
   331     }
   332     return SDL_FALSE;
   333 }
   334 
   335 static void ConstructSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandOutputPacket_t *outPacket)
   336 {
   337     SDL_memset(outPacket, 0, sizeof(*outPacket));
   338 
   339     outPacket->commonData.ucPacketType = k_eSwitchOutputReportIDs_RumbleAndSubcommand;
   340     outPacket->commonData.ucPacketNumber = ctx->m_nCommandNumber;
   341 
   342     SDL_memcpy(&outPacket->commonData.rumbleData, &ctx->m_RumblePacket.rumbleData, sizeof(ctx->m_RumblePacket.rumbleData));
   343 
   344     outPacket->ucSubcommandID = ucCommandID;
   345     SDL_memcpy(outPacket->rgucSubcommandData, pBuf, ucLen);
   346 
   347     ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
   348 }
   349 
   350 static SDL_bool WritePacket(SDL_DriverSwitch_Context *ctx, void *pBuf, Uint8 ucLen)
   351 {
   352     Uint8 rgucBuf[k_unSwitchMaxOutputPacketLength];
   353     const size_t unWriteSize = ctx->m_bUsingBluetooth ? k_unSwitchBluetoothPacketLength : k_unSwitchUSBPacketLength;
   354 
   355     if (ucLen > k_unSwitchOutputPacketDataLength) {
   356         return SDL_FALSE;
   357     }
   358 
   359     if (ucLen < unWriteSize) {
   360         SDL_memcpy(rgucBuf, pBuf, ucLen);
   361         SDL_memset(rgucBuf+ucLen, 0, unWriteSize-ucLen);
   362         pBuf = rgucBuf;
   363         ucLen = (Uint8)unWriteSize;
   364     }
   365     return (WriteOutput(ctx, (Uint8 *)pBuf, ucLen) >= 0);
   366 }
   367 
   368 static SDL_bool WriteSubcommand(SDL_DriverSwitch_Context *ctx, ESwitchSubcommandIDs ucCommandID, Uint8 *pBuf, Uint8 ucLen, SwitchSubcommandInputPacket_t **ppReply)
   369 {
   370     int nRetries = 5;
   371     SwitchSubcommandInputPacket_t *reply = NULL;
   372 
   373     while (!reply && nRetries--) {
   374         SwitchSubcommandOutputPacket_t commandPacket;
   375         ConstructSubcommand(ctx, ucCommandID, pBuf, ucLen, &commandPacket);
   376 
   377         if (!WritePacket(ctx, &commandPacket, sizeof(commandPacket))) {
   378             continue;
   379         }
   380 
   381         reply = ReadSubcommandReply(ctx, ucCommandID);
   382     }
   383 
   384     if (ppReply) {
   385         *ppReply = reply;
   386     }
   387     return reply != NULL;
   388 }
   389 
   390 static SDL_bool WriteProprietary(SDL_DriverSwitch_Context *ctx, ESwitchProprietaryCommandIDs ucCommand, Uint8 *pBuf, Uint8 ucLen, SDL_bool waitForReply)
   391 {
   392     int nRetries = 5;
   393 
   394     while (nRetries--) {
   395         SwitchProprietaryOutputPacket_t packet;
   396 
   397         if ((!pBuf && ucLen > 0) || ucLen > sizeof(packet.rgucProprietaryData)) {
   398             return SDL_FALSE;
   399         }
   400 
   401         packet.ucPacketType = k_eSwitchOutputReportIDs_Proprietary;
   402         packet.ucProprietaryID = ucCommand;
   403         if (pBuf) {
   404             SDL_memcpy(packet.rgucProprietaryData, pBuf, ucLen);
   405         }
   406 
   407         if (!WritePacket(ctx, &packet, sizeof(packet))) {
   408             continue;
   409         }
   410 
   411         if (!waitForReply || ReadProprietaryReply(ctx, ucCommand)) {
   412             return SDL_TRUE;
   413         }
   414     }
   415     return SDL_FALSE;
   416 }
   417 
   418 static void SetNeutralRumble(SwitchRumbleData_t *pRumble)
   419 {
   420     pRumble->rgucData[0] = 0x00;
   421     pRumble->rgucData[1] = 0x01;
   422     pRumble->rgucData[2] = 0x40;
   423     pRumble->rgucData[3] = 0x40;
   424 }
   425 
   426 static void EncodeRumble(SwitchRumbleData_t *pRumble, Uint16 usHighFreq, Uint8 ucHighFreqAmp, Uint8 ucLowFreq, Uint16 usLowFreqAmp)
   427 {
   428     if (ucHighFreqAmp > 0 || usLowFreqAmp > 0) {
   429         // High-band frequency and low-band amplitude are actually nine-bits each so they
   430         // take a bit from the high-band amplitude and low-band frequency bytes respectively
   431         pRumble->rgucData[0] = usHighFreq & 0xFF;
   432         pRumble->rgucData[1] = ucHighFreqAmp | ((usHighFreq >> 8) & 0x01);
   433 
   434         pRumble->rgucData[2]  = ucLowFreq | ((usLowFreqAmp >> 8) & 0x80);
   435         pRumble->rgucData[3]  = usLowFreqAmp & 0xFF;
   436 
   437 #ifdef DEBUG_RUMBLE
   438         SDL_Log("Freq: %.2X %.2X  %.2X, Amp: %.2X  %.2X %.2X\n",
   439             usHighFreq & 0xFF, ((usHighFreq >> 8) & 0x01), ucLowFreq,
   440             ucHighFreqAmp, ((usLowFreqAmp >> 8) & 0x80), usLowFreqAmp & 0xFF);
   441 #endif
   442     } else {
   443         SetNeutralRumble(pRumble);
   444     }
   445 }
   446 
   447 static SDL_bool WriteRumble(SDL_DriverSwitch_Context *ctx)
   448 {
   449     /* Write into m_RumblePacket rather than a temporary buffer to allow the current rumble state
   450      * to be retained for subsequent rumble or subcommand packets sent to the controller
   451      */
   452     ctx->m_RumblePacket.ucPacketType = k_eSwitchOutputReportIDs_Rumble;
   453     ctx->m_RumblePacket.ucPacketNumber = ctx->m_nCommandNumber;
   454     ctx->m_nCommandNumber = (ctx->m_nCommandNumber + 1) & 0xF;
   455 
   456     /* Refresh the rumble state periodically */
   457     if (ctx->m_bRumbleActive) {
   458         ctx->m_unRumbleRefresh = SDL_GetTicks() + 1000;
   459         if (!ctx->m_unRumbleRefresh) {
   460             ctx->m_unRumbleRefresh = 1;
   461         }
   462     } else {
   463         ctx->m_unRumbleRefresh = 0;
   464     }
   465 
   466     return WritePacket(ctx, (Uint8 *)&ctx->m_RumblePacket, sizeof(ctx->m_RumblePacket));
   467 }
   468 
   469 static SDL_bool BTrySetupUSB(SDL_DriverSwitch_Context *ctx)
   470 {
   471     /* We have to send a connection handshake to the controller when communicating over USB
   472      * before we're able to send it other commands. Luckily this command is not supported
   473      * over Bluetooth, so we can use the controller's lack of response as a way to
   474      * determine if the connection is over USB or Bluetooth
   475      */
   476     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
   477         return SDL_FALSE;
   478     }
   479     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_HighSpeed, NULL, 0, SDL_TRUE)) {
   480         /* The 8BitDo M30 doesn't respond to this command, but otherwise works correctly */
   481         /*return SDL_FALSE;*/
   482     }
   483     if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_Handshake, NULL, 0, SDL_TRUE)) {
   484         return SDL_FALSE;
   485     }
   486     return SDL_TRUE;
   487 }
   488 
   489 static SDL_bool SetVibrationEnabled(SDL_DriverSwitch_Context *ctx, Uint8 enabled)
   490 {
   491     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_EnableVibration, &enabled, sizeof(enabled), NULL);
   492 
   493 }
   494 static SDL_bool SetInputMode(SDL_DriverSwitch_Context *ctx, Uint8 input_mode)
   495 {
   496     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetInputReportMode, &input_mode, 1, NULL);
   497 }
   498 
   499 static SDL_bool SetHomeLED(SDL_DriverSwitch_Context *ctx, Uint8 brightness)
   500 {
   501     Uint8 ucLedIntensity = 0;
   502     Uint8 rgucBuffer[4];
   503 
   504     if (brightness > 0) {
   505         if (brightness < 65) {
   506             ucLedIntensity = (brightness + 5) / 10;
   507         } else {
   508             ucLedIntensity = (Uint8)SDL_ceilf(0xF * SDL_powf((float)brightness / 100.f, 2.13f));
   509         }
   510     }
   511 
   512     rgucBuffer[0] = (0x0 << 4) | 0x1;  /* 0 mini cycles (besides first), cycle duration 8ms */
   513     rgucBuffer[1] = ((ucLedIntensity & 0xF) << 4) | 0x0;  /* LED start intensity (0x0-0xF), 0 cycles (LED stays on at start intensity after first cycle) */
   514     rgucBuffer[2] = ((ucLedIntensity & 0xF) << 4) | 0x0;  /* First cycle LED intensity, 0x0 intensity for second cycle */
   515     rgucBuffer[3] = (0x0 << 4) | 0x0;  /* 8ms fade transition to first cycle, 8ms first cycle LED duration */
   516 
   517     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetHomeLight, rgucBuffer, sizeof(rgucBuffer), NULL);
   518 }
   519 
   520 static SDL_bool SetSlotLED(SDL_DriverSwitch_Context *ctx, Uint8 slot)
   521 {
   522     Uint8 led_data = (1 << slot);
   523     return WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SetPlayerLights, &led_data, sizeof(led_data), NULL);
   524 }
   525 
   526 static SDL_bool LoadStickCalibration(SDL_DriverSwitch_Context *ctx)
   527 {
   528     Uint8 *pStickCal;
   529     size_t stick, axis;
   530     SwitchSubcommandInputPacket_t *reply = NULL;
   531 
   532     /* Read Calibration Info */
   533     SwitchSPIOpData_t readParams;
   534     readParams.unAddress = k_unSPIStickCalibrationStartOffset;
   535     readParams.ucLength = k_unSPIStickCalibrationLength;
   536 
   537     if (!WriteSubcommand(ctx, k_eSwitchSubcommandIDs_SPIFlashRead, (uint8_t *)&readParams, sizeof(readParams), &reply)) {
   538         return SDL_FALSE;
   539     }
   540 
   541     /* Stick calibration values are 12-bits each and are packed by bit
   542      * For whatever reason the fields are in a different order for each stick
   543      * Left:  X-Max, Y-Max, X-Center, Y-Center, X-Min, Y-Min
   544      * Right: X-Center, Y-Center, X-Min, Y-Min, X-Max, Y-Max
   545      */
   546     pStickCal = reply->spiReadData.rgucReadData;
   547 
   548     /* Left stick */
   549     ctx->m_StickCalData[0].axis[0].sMax    = ((pStickCal[1] << 8) & 0xF00) | pStickCal[0];     /* X Axis max above center */
   550     ctx->m_StickCalData[0].axis[1].sMax    = (pStickCal[2] << 4) | (pStickCal[1] >> 4);         /* Y Axis max above center */
   551     ctx->m_StickCalData[0].axis[0].sCenter = ((pStickCal[4] << 8) & 0xF00) | pStickCal[3];     /* X Axis center */
   552     ctx->m_StickCalData[0].axis[1].sCenter = (pStickCal[5] << 4) | (pStickCal[4] >> 4);        /* Y Axis center */
   553     ctx->m_StickCalData[0].axis[0].sMin    = ((pStickCal[7] << 8) & 0xF00) | pStickCal[6];      /* X Axis min below center */
   554     ctx->m_StickCalData[0].axis[1].sMin    = (pStickCal[8] << 4) | (pStickCal[7] >> 4);        /* Y Axis min below center */
   555 
   556     /* Right stick */
   557     ctx->m_StickCalData[1].axis[0].sCenter = ((pStickCal[10] << 8) & 0xF00) | pStickCal[9];     /* X Axis center */
   558     ctx->m_StickCalData[1].axis[1].sCenter = (pStickCal[11] << 4) | (pStickCal[10] >> 4);      /* Y Axis center */
   559     ctx->m_StickCalData[1].axis[0].sMin    = ((pStickCal[13] << 8) & 0xF00) | pStickCal[12];    /* X Axis min below center */
   560     ctx->m_StickCalData[1].axis[1].sMin    = (pStickCal[14] << 4) | (pStickCal[13] >> 4);      /* Y Axis min below center */
   561     ctx->m_StickCalData[1].axis[0].sMax    = ((pStickCal[16] << 8) & 0xF00) | pStickCal[15];    /* X Axis max above center */
   562     ctx->m_StickCalData[1].axis[1].sMax    = (pStickCal[17] << 4) | (pStickCal[16] >> 4);      /* Y Axis max above center */
   563 
   564     /* Filter out any values that were uninitialized (0xFFF) in the SPI read */
   565     for (stick = 0; stick < 2; ++stick) {
   566         for (axis = 0; axis < 2; ++axis) {
   567             if (ctx->m_StickCalData[stick].axis[axis].sCenter == 0xFFF) {
   568                 ctx->m_StickCalData[stick].axis[axis].sCenter = 0;
   569             }
   570             if (ctx->m_StickCalData[stick].axis[axis].sMax == 0xFFF) {
   571                 ctx->m_StickCalData[stick].axis[axis].sMax = 0;
   572             }
   573             if (ctx->m_StickCalData[stick].axis[axis].sMin == 0xFFF) {
   574                 ctx->m_StickCalData[stick].axis[axis].sMin = 0;
   575             }
   576         }
   577     }
   578 
   579     if (ctx->m_bUsingBluetooth) {
   580         for (stick = 0; stick < 2; ++stick) {
   581             for(axis = 0; axis < 2; ++axis) {
   582                 ctx->m_StickExtents[stick].axis[axis].sMin = (Sint16)(SDL_MIN_SINT16 * 0.5f);
   583                 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(SDL_MAX_SINT16 * 0.5f);
   584             }
   585         }
   586     } else {
   587         for (stick = 0; stick < 2; ++stick) {
   588             for(axis = 0; axis < 2; ++axis) {
   589                 ctx->m_StickExtents[stick].axis[axis].sMin = -(Sint16)(ctx->m_StickCalData[stick].axis[axis].sMin * 0.7f);
   590                 ctx->m_StickExtents[stick].axis[axis].sMax = (Sint16)(ctx->m_StickCalData[stick].axis[axis].sMax * 0.7f);
   591             }
   592         }
   593     }
   594     return SDL_TRUE;
   595 }
   596 
   597 static float fsel(float fComparand, float fValGE, float fLT)
   598 {
   599     return fComparand >= 0 ? fValGE : fLT;
   600 }
   601 
   602 static float RemapVal(float val, float A, float B, float C, float D)
   603 {
   604     if (A == B) {
   605         return fsel(val - B , D , C);
   606     }
   607     return C + (D - C) * (val - A) / (B - A);
   608 }
   609 
   610 static Sint16 ApplyStickCalibrationCentered(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue, Sint16 sCenter)
   611 {
   612     sRawValue -= sCenter;
   613 
   614     if (sRawValue > ctx->m_StickExtents[nStick].axis[nAxis].sMax) {
   615         ctx->m_StickExtents[nStick].axis[nAxis].sMax = sRawValue;
   616     }
   617     if (sRawValue < ctx->m_StickExtents[nStick].axis[nAxis].sMin) {
   618         ctx->m_StickExtents[nStick].axis[nAxis].sMin = sRawValue;
   619     }
   620 
   621     if (sRawValue > 0) {
   622         return (Sint16)(RemapVal(sRawValue, 0, ctx->m_StickExtents[nStick].axis[nAxis].sMax, 0, SDL_MAX_SINT16));
   623     } else {
   624         return (Sint16)(RemapVal(sRawValue, ctx->m_StickExtents[nStick].axis[nAxis].sMin, 0, SDL_MIN_SINT16, 0));
   625     }
   626 }
   627 
   628 static Sint16 ApplyStickCalibration(SDL_DriverSwitch_Context *ctx, int nStick, int nAxis, Sint16 sRawValue)
   629 {
   630     return ApplyStickCalibrationCentered(ctx, nStick, nAxis, sRawValue, ctx->m_StickCalData[nStick].axis[nAxis].sCenter);
   631 }
   632 
   633 static void SDLCALL SDL_GameControllerButtonReportingHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
   634 {
   635     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)userdata;
   636     ctx->m_bUseButtonLabels = SDL_GetStringBoolean(hint, SDL_TRUE);
   637 }
   638 
   639 static Uint8 RemapButton(SDL_DriverSwitch_Context *ctx, Uint8 button)
   640 {
   641     if (ctx->m_bUseButtonLabels) {
   642         switch (button) {
   643         case SDL_CONTROLLER_BUTTON_A:
   644             return SDL_CONTROLLER_BUTTON_B;
   645         case SDL_CONTROLLER_BUTTON_B:
   646             return SDL_CONTROLLER_BUTTON_A;
   647         case SDL_CONTROLLER_BUTTON_X:
   648             return SDL_CONTROLLER_BUTTON_Y;
   649         case SDL_CONTROLLER_BUTTON_Y:
   650             return SDL_CONTROLLER_BUTTON_X;
   651         default:
   652             break;
   653         }
   654     }
   655     return button;
   656 }
   657  
   658 static SDL_bool
   659 HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device)
   660 {
   661     return HIDAPI_JoystickConnected(device, NULL);
   662 }
   663 
   664 static int
   665 HIDAPI_DriverSwitch_GetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id)
   666 {
   667     return -1;
   668 }
   669 
   670 static void
   671 HIDAPI_DriverSwitch_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, SDL_JoystickID instance_id, int player_index)
   672 {
   673 }
   674 
   675 static SDL_bool
   676 HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
   677 {
   678     SDL_DriverSwitch_Context *ctx;
   679     Uint8 input_mode;
   680 
   681     ctx = (SDL_DriverSwitch_Context *)SDL_calloc(1, sizeof(*ctx));
   682     if (!ctx) {
   683         SDL_OutOfMemory();
   684         goto error;
   685     }
   686     ctx->device = device;
   687     device->context = ctx;
   688 
   689     device->dev = hid_open_path(device->path, 0);
   690     if (!device->dev) {
   691         SDL_SetError("Couldn't open %s", device->path);
   692         goto error;
   693     }
   694 
   695     /* Find out whether or not we can send output reports */
   696     ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id);
   697     if (!ctx->m_bInputOnly) {
   698         /* The Power A Nintendo Switch Pro controllers don't have a Home LED */
   699         ctx->m_bHasHomeLED = (device->vendor_id != 0 && device->product_id != 0) ? SDL_TRUE : SDL_FALSE;
   700 
   701         /* Initialize rumble data */
   702         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
   703         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
   704 
   705         /* Try setting up USB mode, and if that fails we're using Bluetooth */
   706         if (!BTrySetupUSB(ctx)) {
   707             ctx->m_bUsingBluetooth = SDL_TRUE;
   708         }
   709 
   710         if (!LoadStickCalibration(ctx)) {
   711             SDL_SetError("Couldn't load stick calibration");
   712             goto error;
   713         }
   714 
   715         if (!SetVibrationEnabled(ctx, 1)) {
   716             SDL_SetError("Couldn't enable vibration");
   717             goto error;
   718         }
   719 
   720         /* Set the desired input mode */
   721         if (ctx->m_bUsingBluetooth) {
   722             input_mode = k_eSwitchInputReportIDs_SimpleControllerState;
   723         } else {
   724             input_mode = k_eSwitchInputReportIDs_FullControllerState;
   725         }
   726         if (!SetInputMode(ctx, input_mode)) {
   727             SDL_SetError("Couldn't set input mode");
   728             goto error;
   729         }
   730 
   731         /* Start sending USB reports */
   732         if (!ctx->m_bUsingBluetooth) {
   733             /* ForceUSB doesn't generate an ACK, so don't wait for a reply */
   734             if (!WriteProprietary(ctx, k_eSwitchProprietaryCommandIDs_ForceUSB, NULL, 0, SDL_FALSE)) {
   735                 SDL_SetError("Couldn't start USB reports");
   736                 goto error;
   737             }
   738         }
   739 
   740         /* Set the LED state */
   741         if (ctx->m_bHasHomeLED) {
   742             SetHomeLED(ctx, 100);
   743         }
   744         SetSlotLED(ctx, (joystick->instance_id % 4));
   745     }
   746 
   747     if (IsGameCubeFormFactor(device->vendor_id, device->product_id)) {
   748         /* This is a controller shaped like a GameCube controller, with a large central A button */
   749         ctx->m_bUseButtonLabels = SDL_TRUE;
   750     } else {
   751         SDL_AddHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
   752                             SDL_GameControllerButtonReportingHintChanged, ctx);
   753     }
   754 
   755     /* Initialize the joystick capabilities */
   756     joystick->nbuttons = SDL_CONTROLLER_BUTTON_MAX;
   757     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
   758     joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
   759 
   760     return SDL_TRUE;
   761 
   762 error:
   763     if (device->dev) {
   764         hid_close(device->dev);
   765         device->dev = NULL;
   766     }
   767     if (device->context) {
   768         SDL_free(device->context);
   769         device->context = NULL;
   770     }
   771     return SDL_FALSE;
   772 }
   773 
   774 static int
   775 HIDAPI_DriverSwitch_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
   776 {
   777     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
   778 
   779     /* Experimentally determined rumble values. These will only matter on some controllers as tested ones
   780      * seem to disregard these and just use any non-zero rumble values as a binary flag for constant rumble
   781      *
   782      * More information about these values can be found here:
   783      * https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/rumble_data_table.md
   784      */
   785     const Uint16 k_usHighFreq = 0x0074;
   786     const Uint8  k_ucHighFreqAmp = 0xBE;
   787     const Uint8  k_ucLowFreq = 0x3D;
   788     const Uint16 k_usLowFreqAmp = 0x806F;
   789 
   790     if (low_frequency_rumble) {
   791         EncodeRumble(&ctx->m_RumblePacket.rumbleData[0], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
   792     } else {
   793         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[0]);
   794     }
   795 
   796     if (high_frequency_rumble) {
   797         EncodeRumble(&ctx->m_RumblePacket.rumbleData[1], k_usHighFreq, k_ucHighFreqAmp, k_ucLowFreq, k_usLowFreqAmp);
   798     } else {
   799         SetNeutralRumble(&ctx->m_RumblePacket.rumbleData[1]);
   800     }
   801 
   802     ctx->m_bRumbleActive = (low_frequency_rumble || high_frequency_rumble) ? SDL_TRUE : SDL_FALSE;
   803 
   804     if (!WriteRumble(ctx)) {
   805         SDL_SetError("Couldn't send rumble packet");
   806         return -1;
   807     }
   808     return 0;
   809 }
   810 
   811 static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchInputOnlyControllerStatePacket_t *packet)
   812 {
   813     Sint16 axis;
   814 
   815     if (packet->rgucButtons[0] != ctx->m_lastInputOnlyState.rgucButtons[0]) {
   816         Uint8 data = packet->rgucButtons[0];
   817         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   818         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   819         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   820         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   821         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   822         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   823 
   824         axis = (data & 0x40) ? 32767 : -32768;
   825         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   826 
   827         axis = (data & 0x80) ? 32767 : -32768;
   828         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   829     }
   830 
   831     if (packet->rgucButtons[1] != ctx->m_lastInputOnlyState.rgucButtons[1]) {
   832         Uint8 data = packet->rgucButtons[1];
   833         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   834         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   835         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   836         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   837         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   838     }
   839 
   840     if (packet->ucStickHat != ctx->m_lastInputOnlyState.ucStickHat) {
   841         SDL_bool dpad_up = SDL_FALSE;
   842         SDL_bool dpad_down = SDL_FALSE;
   843         SDL_bool dpad_left = SDL_FALSE;
   844         SDL_bool dpad_right = SDL_FALSE;
   845 
   846         switch (packet->ucStickHat) {
   847         case 0:
   848             dpad_up = SDL_TRUE;
   849             break;
   850         case 1:
   851             dpad_up = SDL_TRUE;
   852             dpad_right = SDL_TRUE;
   853             break;
   854         case 2:
   855             dpad_right = SDL_TRUE;
   856             break;
   857         case 3:
   858             dpad_right = SDL_TRUE;
   859             dpad_down = SDL_TRUE;
   860             break;
   861         case 4:
   862             dpad_down = SDL_TRUE;
   863             break;
   864         case 5:
   865             dpad_left = SDL_TRUE;
   866             dpad_down = SDL_TRUE;
   867             break;
   868         case 6:
   869             dpad_left = SDL_TRUE;
   870             break;
   871         case 7:
   872             dpad_up = SDL_TRUE;
   873             dpad_left = SDL_TRUE;
   874             break;
   875         default:
   876             break;
   877         }
   878         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   879         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   880         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   881         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   882     }
   883 
   884     if (packet->rgucJoystickLeft[0] != ctx->m_lastInputOnlyState.rgucJoystickLeft[0]) {
   885         axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
   886         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   887     }
   888 
   889     if (packet->rgucJoystickLeft[1] != ctx->m_lastInputOnlyState.rgucJoystickLeft[1]) {
   890         axis = (Sint16)(RemapVal(packet->rgucJoystickLeft[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
   891         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   892     }
   893 
   894     if (packet->rgucJoystickRight[0] != ctx->m_lastInputOnlyState.rgucJoystickRight[0]) {
   895         axis = (Sint16)(RemapVal(packet->rgucJoystickRight[0], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
   896         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   897     }
   898 
   899     if (packet->rgucJoystickRight[1] != ctx->m_lastInputOnlyState.rgucJoystickRight[1]) {
   900         axis = (Sint16)(RemapVal(packet->rgucJoystickRight[1], SDL_MIN_UINT8, SDL_MAX_UINT8, SDL_MIN_SINT16, SDL_MAX_SINT16));
   901         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   902     }
   903 
   904     ctx->m_lastInputOnlyState = *packet;
   905 }
   906 
   907 static void HandleSimpleControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchSimpleStatePacket_t *packet)
   908 {
   909     /* 0x8000 is the neutral value for all joystick axes */
   910     const Uint16 usJoystickCenter = 0x8000;
   911     Sint16 axis;
   912 
   913     if (packet->rgucButtons[0] != ctx->m_lastSimpleState.rgucButtons[0]) {
   914         Uint8 data = packet->rgucButtons[0];
   915         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   916         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   917         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   918         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   919         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   920         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
   921 
   922         axis = (data & 0x40) ? 32767 : -32768;
   923         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
   924 
   925         axis = (data & 0x80) ? 32767 : -32768;
   926         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
   927     }
   928 
   929     if (packet->rgucButtons[1] != ctx->m_lastSimpleState.rgucButtons[1]) {
   930         Uint8 data = packet->rgucButtons[1];
   931         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
   932         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
   933         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
   934         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
   935         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
   936     }
   937 
   938     if (packet->ucStickHat != ctx->m_lastSimpleState.ucStickHat) {
   939         SDL_bool dpad_up = SDL_FALSE;
   940         SDL_bool dpad_down = SDL_FALSE;
   941         SDL_bool dpad_left = SDL_FALSE;
   942         SDL_bool dpad_right = SDL_FALSE;
   943 
   944         switch (packet->ucStickHat) {
   945         case 0:
   946             dpad_up = SDL_TRUE;
   947             break;
   948         case 1:
   949             dpad_up = SDL_TRUE;
   950             dpad_right = SDL_TRUE;
   951             break;
   952         case 2:
   953             dpad_right = SDL_TRUE;
   954             break;
   955         case 3:
   956             dpad_right = SDL_TRUE;
   957             dpad_down = SDL_TRUE;
   958             break;
   959         case 4:
   960             dpad_down = SDL_TRUE;
   961             break;
   962         case 5:
   963             dpad_left = SDL_TRUE;
   964             dpad_down = SDL_TRUE;
   965             break;
   966         case 6:
   967             dpad_left = SDL_TRUE;
   968             break;
   969         case 7:
   970             dpad_up = SDL_TRUE;
   971             dpad_left = SDL_TRUE;
   972             break;
   973         default:
   974             break;
   975         }
   976         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down);
   977         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up);
   978         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right);
   979         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left);
   980     }
   981 
   982     axis = ApplyStickCalibrationCentered(ctx, 0, 0, packet->sJoystickLeft[0], (Sint16)usJoystickCenter);
   983     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
   984 
   985     axis = ApplyStickCalibrationCentered(ctx, 0, 1, packet->sJoystickLeft[1], (Sint16)usJoystickCenter);
   986     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis);
   987 
   988     axis = ApplyStickCalibrationCentered(ctx, 1, 0, packet->sJoystickRight[0], (Sint16)usJoystickCenter);
   989     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
   990 
   991     axis = ApplyStickCalibrationCentered(ctx, 1, 1, packet->sJoystickRight[1], (Sint16)usJoystickCenter);
   992     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis);
   993 
   994     ctx->m_lastSimpleState = *packet;
   995 }
   996 
   997 static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_Context *ctx, SwitchStatePacket_t *packet)
   998 {
   999     Sint16 axis;
  1000 
  1001     if (packet->controllerState.rgucButtons[0] != ctx->m_lastFullState.controllerState.rgucButtons[0]) {
  1002         Uint8 data = packet->controllerState.rgucButtons[0];
  1003         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_X), (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
  1004         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_Y), (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
  1005         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_A), (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
  1006         SDL_PrivateJoystickButton(joystick, RemapButton(ctx, SDL_CONTROLLER_BUTTON_B), (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
  1007         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
  1008         axis = (data & 0x80) ? 32767 : -32768;
  1009         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis);
  1010     }
  1011 
  1012     if (packet->controllerState.rgucButtons[1] != ctx->m_lastFullState.controllerState.rgucButtons[1]) {
  1013         Uint8 data = packet->controllerState.rgucButtons[1];
  1014         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
  1015         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
  1016         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
  1017         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
  1018 
  1019         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
  1020     }
  1021 
  1022     if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) {
  1023         Uint8 data = packet->controllerState.rgucButtons[2];
  1024         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
  1025         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
  1026         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
  1027         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED);
  1028         SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
  1029         axis = (data & 0x80) ? 32767 : -32768;
  1030         SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis);
  1031     }
  1032 
  1033     axis = packet->controllerState.rgucJoystickLeft[0] | ((packet->controllerState.rgucJoystickLeft[1] & 0xF) << 8);
  1034     axis = ApplyStickCalibration(ctx, 0, 0, axis);
  1035     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis);
  1036 
  1037     axis = ((packet->controllerState.rgucJoystickLeft[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickLeft[2] << 4);
  1038     axis = ApplyStickCalibration(ctx, 0, 1, axis);
  1039     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, ~axis);
  1040 
  1041     axis = packet->controllerState.rgucJoystickRight[0] | ((packet->controllerState.rgucJoystickRight[1] & 0xF) << 8);
  1042     axis = ApplyStickCalibration(ctx, 1, 0, axis);
  1043     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis);
  1044 
  1045     axis = ((packet->controllerState.rgucJoystickRight[1] & 0xF0) >> 4) | (packet->controllerState.rgucJoystickRight[2] << 4);
  1046     axis = ApplyStickCalibration(ctx, 1, 1, axis);
  1047     SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, ~axis);
  1048 
  1049     /* High nibble of battery/connection byte is battery level, low nibble is connection status
  1050      * LSB of connection nibble is USB/Switch connection status
  1051      */
  1052     if (packet->controllerState.ucBatteryAndConnection & 0x1) {
  1053         joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
  1054     } else {
  1055         /* LSB of the battery nibble is used to report charging.
  1056          * The battery level is reported from 0(empty)-8(full)
  1057          */
  1058         int level = (packet->controllerState.ucBatteryAndConnection & 0xE0) >> 4;
  1059         if (level == 0) {
  1060             joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY;
  1061         } else if (level <= 2) {
  1062             joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW;
  1063         } else if (level <= 6) {
  1064             joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM;
  1065         } else {
  1066             joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL;
  1067         }
  1068     }
  1069 
  1070     ctx->m_lastFullState = *packet;
  1071 }
  1072 
  1073 static SDL_bool
  1074 HIDAPI_DriverSwitch_UpdateDevice(SDL_HIDAPI_Device *device)
  1075 {
  1076     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
  1077     SDL_Joystick *joystick = NULL;
  1078     int size;
  1079 
  1080     if (device->num_joysticks > 0) {
  1081         joystick = SDL_JoystickFromInstanceID(device->joysticks[0]);
  1082     }
  1083     if (!joystick) {
  1084         return SDL_FALSE;
  1085     }
  1086 
  1087     while ((size = ReadInput(ctx)) > 0) {
  1088         if (ctx->m_bInputOnly) {
  1089             HandleInputOnlyControllerState(joystick, ctx, (SwitchInputOnlyControllerStatePacket_t *)&ctx->m_rgucReadBuffer[0]);
  1090         } else {
  1091             switch (ctx->m_rgucReadBuffer[0]) {
  1092             case k_eSwitchInputReportIDs_SimpleControllerState:
  1093                 HandleSimpleControllerState(joystick, ctx, (SwitchSimpleStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
  1094                 break;
  1095             case k_eSwitchInputReportIDs_FullControllerState:
  1096                 HandleFullControllerState(joystick, ctx, (SwitchStatePacket_t *)&ctx->m_rgucReadBuffer[1]);
  1097                 break;
  1098             default:
  1099                 break;
  1100             }
  1101         }
  1102     }
  1103 
  1104     if (ctx->m_bRumbleActive &&
  1105         SDL_TICKS_PASSED(SDL_GetTicks(), ctx->m_unRumbleRefresh)) {
  1106         WriteRumble(ctx);
  1107     }
  1108 
  1109     if (size < 0) {
  1110         /* Read error, device is disconnected */
  1111         HIDAPI_JoystickDisconnected(device, joystick->instance_id);
  1112     }
  1113     return (size >= 0);
  1114 }
  1115 
  1116 static void
  1117 HIDAPI_DriverSwitch_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
  1118 {
  1119     SDL_DriverSwitch_Context *ctx = (SDL_DriverSwitch_Context *)device->context;
  1120 
  1121     if (!ctx->m_bInputOnly) {
  1122         /* Restore simple input mode for other applications */
  1123         SetInputMode(ctx, k_eSwitchInputReportIDs_SimpleControllerState);
  1124     }
  1125 
  1126     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS,
  1127                         SDL_GameControllerButtonReportingHintChanged, ctx);
  1128 
  1129     hid_close(device->dev);
  1130     device->dev = NULL;
  1131 
  1132     SDL_free(device->context);
  1133     device->context = NULL;
  1134 }
  1135 
  1136 static void
  1137 HIDAPI_DriverSwitch_FreeDevice(SDL_HIDAPI_Device *device)
  1138 {
  1139 }
  1140 
  1141 SDL_HIDAPI_DeviceDriver SDL_HIDAPI_DriverSwitch =
  1142 {
  1143     SDL_HINT_JOYSTICK_HIDAPI_SWITCH,
  1144     SDL_TRUE,
  1145     HIDAPI_DriverSwitch_IsSupportedDevice,
  1146     HIDAPI_DriverSwitch_GetDeviceName,
  1147     HIDAPI_DriverSwitch_InitDevice,
  1148     HIDAPI_DriverSwitch_GetDevicePlayerIndex,
  1149     HIDAPI_DriverSwitch_SetDevicePlayerIndex,
  1150     HIDAPI_DriverSwitch_UpdateDevice,
  1151     HIDAPI_DriverSwitch_OpenJoystick,
  1152     HIDAPI_DriverSwitch_RumbleJoystick,
  1153     HIDAPI_DriverSwitch_CloseJoystick,
  1154     HIDAPI_DriverSwitch_FreeDevice
  1155 };
  1156 
  1157 #endif /* SDL_JOYSTICK_HIDAPI_SWITCH */
  1158 
  1159 #endif /* SDL_JOYSTICK_HIDAPI */
  1160 
  1161 /* vi: set ts=4 sw=4 expandtab: */