SDL: Add joystick battery event

From 3dcfe86082d94eef17518724cebf30aa3543b0e0 Mon Sep 17 00:00:00 2001
From: meyraud705 <[EMAIL REDACTED]>
Date: Wed, 2 Feb 2022 13:59:49 +0100
Subject: [PATCH] Add joystick battery event

---
 include/SDL_events.h        | 12 ++++++++++++
 src/joystick/SDL_joystick.c | 20 +++++++++++++++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/include/SDL_events.h b/include/SDL_events.h
index 7e469070ecd..c0fc9bb1aa3 100644
--- a/include/SDL_events.h
+++ b/include/SDL_events.h
@@ -118,6 +118,7 @@ typedef enum
     SDL_JOYBUTTONUP,            /**< Joystick button released */
     SDL_JOYDEVICEADDED,         /**< A new joystick has been inserted into the system */
     SDL_JOYDEVICEREMOVED,       /**< An opened joystick has been removed */
+    SDL_JOYBATTERYUPDATED,      /**< Joystick battery level change */
 
     /* Game controller events */
     SDL_CONTROLLERAXISMOTION  = 0x650, /**< Game controller axis motion */
@@ -395,6 +396,16 @@ typedef struct SDL_JoyDeviceEvent
     Sint32 which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED event */
 } SDL_JoyDeviceEvent;
 
+/**
+ *  \brief Joysick battery level change event structure (event.jbattery.*)
+ */
+typedef struct SDL_JoyBatteryEvent
+{
+    Uint32 type;        /**< ::SDL_JOYBATTERYUPDATED */
+    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    SDL_JoystickID which; /**< The joystick instance id */
+    SDL_JoystickPowerLevel level; /**< The joystick battery level */
+} SDL_JoyBatteryEvent;
 
 /**
  *  \brief Game controller axis motion event structure (event.caxis.*)
@@ -625,6 +636,7 @@ typedef union SDL_Event
     SDL_JoyHatEvent jhat;                   /**< Joystick hat event data */
     SDL_JoyButtonEvent jbutton;             /**< Joystick button event data */
     SDL_JoyDeviceEvent jdevice;             /**< Joystick device change event data */
+    SDL_JoyBatteryEvent jbattery;           /**< Joystick battery event data */
     SDL_ControllerAxisEvent caxis;          /**< Game Controller axis event data */
     SDL_ControllerButtonEvent cbutton;      /**< Game Controller button event data */
     SDL_ControllerDeviceEvent cdevice;      /**< Game Controller device event data */
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index ae459122347..65c8b77329d 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -386,6 +386,7 @@ SDL_JoystickOpen(int device_index)
     SDL_Joystick *joystick;
     SDL_Joystick *joysticklist;
     const char *joystickname = NULL;
+    SDL_JoystickPowerLevel initial_power_level;
 
     SDL_LockJoysticks();
 
@@ -478,6 +479,11 @@ SDL_JoystickOpen(int device_index)
 
     SDL_UnlockJoysticks();
 
+    /* send initial battery event */
+    initial_power_level = joystick->epowerlevel;
+    joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
+    SDL_PrivateJoystickBatteryLevel(joystick, initial_power_level);
+
     driver->Update(joystick);
 
     return joystick;
@@ -2721,7 +2727,19 @@ SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID)
 /* update the power level for this joystick */
 void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
 {
-    joystick->epowerlevel = ePowerLevel;
+    SDL_assert(joystick->ref_count); /* make sure we are calling this only for update, not for initialisation */
+    if (ePowerLevel != joystick->epowerlevel) {
+#if !SDL_EVENTS_DISABLED
+        if (SDL_GetEventState(SDL_JOYBATTERYUPDATED) == SDL_ENABLE) {
+            SDL_Event event;
+            event.type = SDL_JOYBATTERYUPDATED;
+            event.jbattery.which = joystick->instance_id;
+            event.jbattery.level = ePowerLevel;
+            SDL_PushEvent(&event);
+        }
+#endif /* !SDL_EVENTS_DISABLED */
+        joystick->epowerlevel = ePowerLevel;
+    }
 }
 
 /* return its power level */