sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_hidapi_switch.c (50344B)


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