SDL: Don't report 10% battery for Xbox controllers using XInput

From 386f198622083f8b91753f3bcce75c631c3701b5 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 6 May 2026 18:12:01 -0700
Subject: [PATCH] Don't report 10% battery for Xbox controllers using XInput

---
 src/joystick/windows/SDL_rawinputjoystick.c | 32 +++++++++++---------
 src/joystick/windows/SDL_xinputjoystick.c   | 33 ++++++++++++---------
 2 files changed, 37 insertions(+), 28 deletions(-)

diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index c8cd9cd3a77b5..e67d9fd3e78cb 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -1976,20 +1976,24 @@ static void RAWINPUT_UpdateOtherAPIs(SDL_Joystick *joystick)
                 state = SDL_POWERSTATE_ON_BATTERY;
                 break;
             }
-            switch (battery_info->BatteryLevel) {
-            case BATTERY_LEVEL_EMPTY:
-                percent = 10;
-                break;
-            case BATTERY_LEVEL_LOW:
-                percent = 40;
-                break;
-            case BATTERY_LEVEL_MEDIUM:
-                percent = 70;
-                break;
-            default:
-            case BATTERY_LEVEL_FULL:
-                percent = 100;
-                break;
+            if (state == SDL_POWERSTATE_ON_BATTERY || SDL_POWERSTATE_CHARGING) {
+                switch (battery_info->BatteryLevel) {
+                case BATTERY_LEVEL_EMPTY:
+                    percent = 10;
+                    break;
+                case BATTERY_LEVEL_LOW:
+                    percent = 40;
+                    break;
+                case BATTERY_LEVEL_MEDIUM:
+                    percent = 70;
+                    break;
+                default:
+                case BATTERY_LEVEL_FULL:
+                    percent = 100;
+                    break;
+                }
+            } else {
+                percent = -1;
             }
             SDL_SendJoystickPowerInfo(joystick, state, percent);
         }
diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c
index 8f26bcd7db25e..d7a132e1d15ca 100644
--- a/src/joystick/windows/SDL_xinputjoystick.c
+++ b/src/joystick/windows/SDL_xinputjoystick.c
@@ -300,20 +300,24 @@ static void UpdateXInputJoystickBatteryInformation(SDL_Joystick *joystick, XINPU
         state = SDL_POWERSTATE_ON_BATTERY;
         break;
     }
-    switch (pBatteryInformation->BatteryLevel) {
-    case BATTERY_LEVEL_EMPTY:
-        percent = 10;
-        break;
-    case BATTERY_LEVEL_LOW:
-        percent = 40;
-        break;
-    case BATTERY_LEVEL_MEDIUM:
-        percent = 70;
-        break;
-    default:
-    case BATTERY_LEVEL_FULL:
-        percent = 100;
-        break;
+    if (state == SDL_POWERSTATE_ON_BATTERY || state == SDL_POWERSTATE_CHARGING) {
+        switch (pBatteryInformation->BatteryLevel) {
+        case BATTERY_LEVEL_EMPTY:
+            percent = 10;
+            break;
+        case BATTERY_LEVEL_LOW:
+            percent = 40;
+            break;
+        case BATTERY_LEVEL_MEDIUM:
+            percent = 70;
+            break;
+        default:
+        case BATTERY_LEVEL_FULL:
+            percent = 100;
+            break;
+        }
+    } else {
+        percent = -1;
     }
     SDL_SendJoystickPowerInfo(joystick, state, percent);
 }
@@ -391,6 +395,7 @@ void SDL_XINPUT_JoystickUpdate(SDL_Joystick *joystick)
         return;
     }
 
+    // FIXME: This does end up making a device ioctl() to query data, we shouldn't do this every update.
     SDL_zero(XBatteryInformation);
     if (XINPUTGETBATTERYINFORMATION) {
         result = XINPUTGETBATTERYINFORMATION(joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation);