SDL: Improved detection of Nintendo Switch Pro controller report mode

From 4c444502583e91c0513ad4bd62c9c282d57571b3 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 6 Jul 2024 05:29:12 -0700
Subject: [PATCH] Improved detection of Nintendo Switch Pro controller report
 mode

Fixes https://github.com/libsdl-org/SDL/issues/10182

(cherry picked from commit 4ba2e9f4f4557dadd59c80487122fe700e6ae283)
---
 src/joystick/hidapi/SDL_hidapi_switch.c | 30 ++++++++++++++++++-------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c
index 45a2260d1b035..ce9b15c0aeb08 100644
--- a/src/joystick/hidapi/SDL_hidapi_switch.c
+++ b/src/joystick/hidapi/SDL_hidapi_switch.c
@@ -332,12 +332,28 @@ typedef struct
 
 static int ReadInput(SDL_DriverSwitch_Context *ctx)
 {
+    int result;
+
     /* Make sure we don't try to read at the same time a write is happening */
     if (SDL_AtomicGet(&ctx->device->rumble_pending) > 0) {
         return 0;
     }
 
-    return SDL_hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
+    result = SDL_hid_read_timeout(ctx->device->dev, ctx->m_rgucReadBuffer, sizeof(ctx->m_rgucReadBuffer), 0);
+
+    /* See if we can guess the initial input mode */
+    if (result > 0 && !ctx->m_bInputOnly && !ctx->m_nInitialInputMode) {
+        switch (ctx->m_rgucReadBuffer[0]) {
+        case k_eSwitchInputReportIDs_FullControllerState:
+        case k_eSwitchInputReportIDs_FullControllerAndMcuState:
+        case k_eSwitchInputReportIDs_SimpleControllerState:
+            ctx->m_nInitialInputMode = ctx->m_rgucReadBuffer[0];
+            break;
+        default:
+            break;
+        }
+    }
+    return result;
 }
 
 static int WriteOutput(SDL_DriverSwitch_Context *ctx, const Uint8 *data, int size)
@@ -727,14 +743,12 @@ static void SDLCALL SDL_PlayerLEDHintChanged(void *userdata, const char *name, c
     }
 }
 
-static Uint8 GetInitialInputMode(SDL_DriverSwitch_Context *ctx)
+static void GetInitialInputMode(SDL_DriverSwitch_Context *ctx)
 {
-    Uint8 input_mode = 0;
-
-    if (ReadInput(ctx) > 0) {
-        input_mode = ctx->m_rgucReadBuffer[0];
+    if (!ctx->m_nInitialInputMode) {
+        /* This will set the initial input mode if it can */
+        ReadInput(ctx);
     }
-    return input_mode;
 }
 
 static Uint8 GetDefaultInputMode(SDL_DriverSwitch_Context *ctx)
@@ -1412,7 +1426,7 @@ static SDL_bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_
     ctx->m_bSyncWrite = SDL_TRUE;
 
     if (!ctx->m_bInputOnly) {
-        ctx->m_nInitialInputMode = GetInitialInputMode(ctx);
+        GetInitialInputMode(ctx);
         ctx->m_nCurrentInputMode = ctx->m_nInitialInputMode;
 
         /* Initialize rumble data */