SDL: Added SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED

From d8f8cf3e99a0880dba538fda3ddff635ee4f4949 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 18 Nov 2024 14:42:39 -0800
Subject: [PATCH] Added SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED

---
 include/SDL3/SDL_hints.h               | 19 +++++++++++
 src/joystick/hidapi/SDL_hidapi_steam.c | 44 ++++++++++++++++++++++++++
 2 files changed, 63 insertions(+)

diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h
index f2c22f25675bd..3a7b1cfb52c55 100644
--- a/include/SDL3/SDL_hints.h
+++ b/include/SDL3/SDL_hints.h
@@ -1659,6 +1659,25 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_STEAM "SDL_JOYSTICK_HIDAPI_STEAM"
 
+/**
+ * A variable controlling whether the Steam button LED should be turned on when
+ * a Steam controller is opened.
+ *
+ * The variable can be set to the following values:
+ *
+ * - "0": Steam button LED is turned off.
+ * - "1": Steam button LED is turned on.
+ *
+ * By default the Steam button LED state is not changed. This hint can also be
+ * set to a floating point value between 0.0 and 1.0 which controls the
+ * brightness of the Steam button LED.
+ *
+ * This hint can be set anytime.
+ *
+ * \since This hint is available since SDL 3.1.8.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED "SDL_JOYSTICK_HIDAPI_STEAM_HOME_LED"
+
 /**
  * A variable controlling whether the HIDAPI driver for the Steam Deck builtin
  * controller should be used.
diff --git a/src/joystick/hidapi/SDL_hidapi_steam.c b/src/joystick/hidapi/SDL_hidapi_steam.c
index 8820787df7c00..ec93dff11055f 100644
--- a/src/joystick/hidapi/SDL_hidapi_steam.c
+++ b/src/joystick/hidapi/SDL_hidapi_steam.c
@@ -1142,6 +1142,42 @@ static void HIDAPI_DriverSteam_SetDevicePlayerIndex(SDL_HIDAPI_Device *device, S
 {
 }
 
+static bool SetHomeLED(SDL_HIDAPI_Device *device, Uint8 value)
+{
+    unsigned char buf[65];
+    int nSettings = 0;
+
+    SDL_memset(buf, 0, 65);
+    buf[1] = ID_SET_SETTINGS_VALUES;
+    ADD_SETTING(SETTING_LED_USER_BRIGHTNESS, value);
+    buf[2] = (unsigned char)(nSettings * 3);
+    if (SetFeatureReport(device, buf, 3 + nSettings * 3) < 0) {
+        return SDL_SetError("Couldn't write feature report");
+    }
+    return true;
+}
+
+static void SDLCALL SDL_HomeLEDHintChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
+{
+    SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)userdata;
+
+    if (hint && *hint) {
+        int value;
+
+        if (SDL_strchr(hint, '.') != NULL) {
+            value = (int)(100.0f * SDL_atof(hint));
+            if (value > 255) {
+                value = 255;
+            }
+        } else if (SDL_GetStringBoolean(hint, true)) {
+            value = 100;
+        } else {
+            value = 0;
+        }
+        SetHomeLED(ctx->device, (Uint8)value);
+    }
+}
+
 static bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
     SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
@@ -1176,6 +1212,9 @@ static bool HIDAPI_DriverSteam_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joyst
     SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, update_rate_in_hz);
     SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, update_rate_in_hz);
 
+    SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED,
+                        SDL_HomeLEDHintChanged, ctx);
+
     return true;
 }
 
@@ -1395,6 +1434,11 @@ static bool HIDAPI_DriverSteam_UpdateDevice(SDL_HIDAPI_Device *device)
 
 static void HIDAPI_DriverSteam_CloseJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
 {
+    SDL_DriverSteam_Context *ctx = (SDL_DriverSteam_Context *)device->context;
+
+    SDL_RemoveHintCallback(SDL_HINT_JOYSTICK_HIDAPI_STEAM_HOME_LED,
+                           SDL_HomeLEDHintChanged, ctx);
+
     CloseSteamController(device);
 }