From 8847b352442a7192a4275b89ba4afd2f84b5961c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 30 Mar 2024 10:55:13 -0700
Subject: [PATCH] Separate joystick power state into battery status and
percentage
This allows you to see battery percentage while the controller is charging
---
docs/README-migration.md | 4 +-
include/SDL3/SDL_events.h | 3 +-
include/SDL3/SDL_gamepad.h | 27 ++-
include/SDL3/SDL_joystick.h | 40 ++--
include/SDL3/SDL_oldnames.h | 2 -
include/SDL3/SDL_power.h | 11 +-
src/dynapi/SDL_dynapi.sym | 6 +-
src/dynapi/SDL_dynapi_overrides.h | 6 +-
src/dynapi/SDL_dynapi_procs.h | 6 +-
src/joystick/SDL_gamepad.c | 19 +-
src/joystick/SDL_joystick.c | 53 ++++--
src/joystick/SDL_joystick_c.h | 2 +-
src/joystick/SDL_sysjoystick.h | 5 +-
src/joystick/apple/SDL_mfijoystick.m | 23 +--
src/joystick/gdk/SDL_gameinputjoystick.c | 39 ++--
src/joystick/hidapi/SDL_hidapi_gamecube.c | 6 +-
src/joystick/hidapi/SDL_hidapi_luna.c | 14 +-
src/joystick/hidapi/SDL_hidapi_ps3.c | 3 -
src/joystick/hidapi/SDL_hidapi_ps4.c | 35 ++--
src/joystick/hidapi/SDL_hidapi_ps5.c | 43 +++--
src/joystick/hidapi/SDL_hidapi_shield.c | 51 ++---
src/joystick/hidapi/SDL_hidapi_stadia.c | 1 -
src/joystick/hidapi/SDL_hidapi_switch.c | 43 +++--
src/joystick/hidapi/SDL_hidapi_wii.c | 42 ++--
src/joystick/hidapi/SDL_hidapi_xbox360.c | 1 -
src/joystick/hidapi/SDL_hidapi_xbox360w.c | 14 +-
src/joystick/hidapi/SDL_hidapi_xboxone.c | 40 ++--
src/joystick/hidapi/SDL_hidapijoystick.c | 7 +
src/joystick/windows/SDL_rawinputjoystick.c | 54 +++---
.../windows/SDL_windows_gaming_input.c | 47 +++--
src/joystick/windows/SDL_xinputjoystick.c | 52 ++---
test/CMakeLists.txt | 6 +-
test/gamepad_battery.bmp | Bin 0 -> 2122 bytes
...epad_battery_empty.h => gamepad_battery.h} | 163 ++++++++--------
test/gamepad_battery_empty.bmp | Bin 2106 -> 0 bytes
test/gamepad_battery_full.bmp | Bin 2106 -> 0 bytes
test/gamepad_battery_full.h | 179 ------------------
test/gamepad_battery_low.bmp | Bin 2106 -> 0 bytes
test/gamepad_battery_low.h | 179 ------------------
test/gamepad_battery_medium.bmp | Bin 2106 -> 0 bytes
test/gamepad_battery_medium.h | 179 ------------------
test/gamepadutils.c | 54 ++++--
42 files changed, 527 insertions(+), 932 deletions(-)
create mode 100644 test/gamepad_battery.bmp
rename test/{gamepad_battery_empty.h => gamepad_battery.h} (72%)
mode change 100644 => 100755
delete mode 100644 test/gamepad_battery_empty.bmp
delete mode 100644 test/gamepad_battery_full.bmp
delete mode 100644 test/gamepad_battery_full.h
delete mode 100644 test/gamepad_battery_low.bmp
delete mode 100644 test/gamepad_battery_low.h
delete mode 100644 test/gamepad_battery_medium.bmp
delete mode 100644 test/gamepad_battery_medium.h
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 8e2c17dac30c8..b1313bbb95d54 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -333,6 +333,8 @@ The mouseX and mouseY fields of SDL_MouseWheelEvent have been renamed mouse_x an
The touchId and fingerId fields of SDL_TouchFingerEvent have been renamed touchID and fingerID.
+The level field of SDL_JoyBatteryEvent has been split into state and percent.
+
SDL_QUERY, SDL_IGNORE, SDL_ENABLE, and SDL_DISABLE have been removed. You can use the functions SDL_SetEventEnabled() and SDL_EventEnabled() to set and query event processing state.
SDL_AddEventWatch() now returns -1 if it fails because it ran out of memory and couldn't add the event watch callback.
@@ -793,7 +795,6 @@ The following functions have been renamed:
* SDL_JoystickAttachVirtual() => SDL_AttachVirtualJoystick()
* SDL_JoystickAttachVirtualEx() => SDL_AttachVirtualJoystickEx()
* SDL_JoystickClose() => SDL_CloseJoystick()
-* SDL_JoystickCurrentPowerLevel() => SDL_GetJoystickPowerLevel()
* SDL_JoystickDetachVirtual() => SDL_DetachVirtualJoystick()
* SDL_JoystickFromInstanceID() => SDL_GetJoystickFromInstanceID()
* SDL_JoystickFromPlayerIndex() => SDL_GetJoystickFromPlayerIndex()
@@ -836,6 +837,7 @@ The following symbols have been renamed:
* SDL_JOYSTICK_TYPE_GAMECONTROLLER => SDL_JOYSTICK_TYPE_GAMEPAD
The following functions have been removed:
+* SDL_JoystickCurrentPowerLevel() - replaced with SDL_GetJoystickConnectionState() and SDL_GetJoystickPowerInfo()
* SDL_JoystickEventState() - replaced with SDL_SetJoystickEventsEnabled() and SDL_JoystickEventsEnabled()
* SDL_JoystickGetDeviceGUID() - replaced with SDL_GetJoystickInstanceGUID()
* SDL_JoystickGetDeviceInstanceID()
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index cc376aa3cfd12..0fddf1f24829d 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -488,7 +488,8 @@ typedef struct SDL_JoyBatteryEvent
Uint32 reserved;
Uint64 timestamp; /**< In nanoseconds, populated using SDL_GetTicksNS() */
SDL_JoystickID which; /**< The joystick instance id */
- SDL_JoystickPowerLevel level; /**< The joystick battery level */
+ SDL_PowerState state; /**< The joystick battery state */
+ int percent; /**< The joystick battery percent charge remaining */
} SDL_JoyBatteryEvent;
/**
diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h
index 7a9b7e82603ab..71ae158053492 100644
--- a/include/SDL3/SDL_gamepad.h
+++ b/include/SDL3/SDL_gamepad.h
@@ -842,16 +842,31 @@ extern DECLSPEC const char * SDLCALL SDL_GetGamepadSerial(SDL_Gamepad *gamepad);
extern DECLSPEC Uint64 SDLCALL SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepad);
/**
- * Get the battery level of a gamepad, if available.
+ * Get the connection state of a gamepad.
*
- * \param gamepad a gamepad identifier previously returned by
- * SDL_OpenGamepad()
- * \returns the current battery level as SDL_JoystickPowerLevel on success or
- * `SDL_JOYSTICK_POWER_UNKNOWN` if it is unknown
+ * \param gamepad the gamepad object to query.
+ * \returns the connection state on success or `SDL_JOYSTICK_CONNECTION_INVALID` on failure; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetGamepadConnectionState(SDL_Gamepad *gamepad);
+
+/**
+ * Get the battery state of a gamepad.
+ *
+ * You should never take a battery status as absolute truth. Batteries
+ * (especially failing batteries) are delicate hardware, and the values
+ * reported here are best estimates based on what that hardware reports. It's
+ * not uncommon for older batteries to lose stored power much faster than it
+ * reports, or completely drain when reporting it has 20 percent left, etc.
+ *
+ * \param gamepad the gamepad object to query.
+ * \param percent a pointer filled in with the percentage of battery life left, between 0 and 100, or NULL to ignore. This will be filled in with -1 we can't determine a value or there is no battery.
+ * \returns the current battery state.
*
* \since This function is available since SDL 3.0.0.
*/
-extern DECLSPEC SDL_JoystickPowerLevel SDLCALL SDL_GetGamepadPowerLevel(SDL_Gamepad *gamepad);
+extern DECLSPEC SDL_PowerState SDLCALL SDL_GetGamepadPowerInfo(SDL_Gamepad *gamepad, int *percent);
/**
* Check if a gamepad has been opened and is currently connected.
diff --git a/include/SDL3/SDL_joystick.h b/include/SDL3/SDL_joystick.h
index 337815cb402b3..5c7ac5b05e5a3 100644
--- a/include/SDL3/SDL_joystick.h
+++ b/include/SDL3/SDL_joystick.h
@@ -42,6 +42,7 @@
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_guid.h>
#include <SDL3/SDL_mutex.h>
+#include <SDL3/SDL_power.h>
#include <SDL3/SDL_properties.h>
#include <SDL3/SDL_begin_code.h>
@@ -99,14 +100,11 @@ typedef enum
typedef enum
{
- SDL_JOYSTICK_POWER_UNKNOWN = -1,
- SDL_JOYSTICK_POWER_EMPTY, /* <= 5% */
- SDL_JOYSTICK_POWER_LOW, /* <= 20% */
- SDL_JOYSTICK_POWER_MEDIUM, /* <= 70% */
- SDL_JOYSTICK_POWER_FULL, /* <= 100% */
- SDL_JOYSTICK_POWER_WIRED,
- SDL_JOYSTICK_POWER_MAX
-} SDL_JoystickPowerLevel;
+ SDL_JOYSTICK_CONNECTION_INVALID = -1,
+ SDL_JOYSTICK_CONNECTION_UNKNOWN,
+ SDL_JOYSTICK_CONNECTION_WIRED,
+ SDL_JOYSTICK_CONNECTION_WIRELESS,
+} SDL_JoystickConnectionState;
#define SDL_JOYSTICK_AXIS_MAX 32767
#define SDL_JOYSTICK_AXIS_MIN -32768
@@ -1082,15 +1080,31 @@ extern DECLSPEC int SDLCALL SDL_SendJoystickEffect(SDL_Joystick *joystick, const
extern DECLSPEC void SDLCALL SDL_CloseJoystick(SDL_Joystick *joystick);
/**
- * Get the battery level of a joystick as SDL_JoystickPowerLevel.
+ * Get the connection state of a joystick.
*
- * \param joystick the SDL_Joystick to query
- * \returns the current battery level as SDL_JoystickPowerLevel on success or
- * `SDL_JOYSTICK_POWER_UNKNOWN` if it is unknown
+ * \param joystick The joystick to query
+ * \returns the connection state on success or `SDL_JOYSTICK_CONNECTION_INVALID` on failure; call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern DECLSPEC SDL_JoystickConnectionState SDLCALL SDL_GetJoystickConnectionState(SDL_Joystick *joystick);
+
+/**
+ * Get the battery state of a joystick.
+ *
+ * You should never take a battery status as absolute truth. Batteries
+ * (especially failing batteries) are delicate hardware, and the values
+ * reported here are best estimates based on what that hardware reports. It's
+ * not uncommon for older batteries to lose stored power much faster than it
+ * reports, or completely drain when reporting it has 20 percent left, etc.
+ *
+ * \param joystick The joystick to query
+ * \param percent a pointer filled in with the percentage of battery life left, between 0 and 100, or NULL to ignore. This will be filled in with -1 we can't determine a value or there is no battery.
+ * \returns the current battery state or `SDL_POWERSTATE_ERROR` on failure; call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
-extern DECLSPEC SDL_JoystickPowerLevel SDLCALL SDL_GetJoystickPowerLevel(SDL_Joystick *joystick);
+extern DECLSPEC SDL_PowerState SDLCALL SDL_GetJoystickPowerInfo(SDL_Joystick *joystick, int *percent);
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
diff --git a/include/SDL3/SDL_oldnames.h b/include/SDL3/SDL_oldnames.h
index 618100b9b7a56..36632a3b47e4d 100644
--- a/include/SDL3/SDL_oldnames.h
+++ b/include/SDL3/SDL_oldnames.h
@@ -297,7 +297,6 @@
#define SDL_JoystickAttachVirtual SDL_AttachVirtualJoystick
#define SDL_JoystickAttachVirtualEx SDL_AttachVirtualJoystickEx
#define SDL_JoystickClose SDL_CloseJoystick
-#define SDL_JoystickCurrentPowerLevel SDL_GetJoystickPowerLevel
#define SDL_JoystickDetachVirtual SDL_DetachVirtualJoystick
#define SDL_JoystickFromInstanceID SDL_GetJoystickFromInstanceID
#define SDL_JoystickFromPlayerIndex SDL_GetJoystickFromPlayerIndex
@@ -797,7 +796,6 @@
#define SDL_JoystickAttachVirtual SDL_JoystickAttachVirtual_renamed_SDL_AttachVirtualJoystick
#define SDL_JoystickAttachVirtualEx SDL_JoystickAttachVirtualEx_renamed_SDL_AttachVirtualJoystickEx
#define SDL_JoystickClose SDL_JoystickClose_renamed_SDL_CloseJoystick
-#define SDL_JoystickCurrentPowerLevel SDL_JoystickCurrentPowerLevel_renamed_SDL_GetJoystickPowerLevel
#define SDL_JoystickDetachVirtual SDL_JoystickDetachVirtual_renamed_SDL_DetachVirtualJoystick
#define SDL_JoystickFromInstanceID SDL_JoystickFromInstanceID_renamed_SDL_GetJoystickFromInstanceID
#define SDL_JoystickFromPlayerIndex SDL_JoystickFromPlayerIndex_renamed_SDL_GetJoystickFromPlayerIndex
diff --git a/include/SDL3/SDL_power.h b/include/SDL3/SDL_power.h
index d957f237e4412..a37bdee2a0345 100644
--- a/include/SDL3/SDL_power.h
+++ b/include/SDL3/SDL_power.h
@@ -41,6 +41,7 @@ extern "C" {
*/
typedef enum
{
+ SDL_POWERSTATE_ERROR = -1, /**< error determining power status */
SDL_POWERSTATE_UNKNOWN, /**< cannot determine power status */
SDL_POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */
SDL_POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */
@@ -64,13 +65,9 @@ typedef enum
* It's possible a platform can only report battery percentage or time left
* but not both.
*
- * \param seconds seconds of battery life left, you can pass a NULL here if
- * you don't care, will return -1 if we can't determine a
- * value, or we're not running on a battery
- * \param percent percentage of battery life left, between 0 and 100, you can
- * pass a NULL here if you don't care, will return -1 if we
- * can't determine a value, or we're not running on a battery
- * \returns an SDL_PowerState enum representing the current battery state.
+ * \param seconds a pointer filled in with the seconds of battery life left, or NULL to ignore. This will be filled in with -1 if we can't determine a value or there is no battery.
+ * \param percent a pointer filled in with the percentage of battery life left, between 0 and 100, or NULL to ignore. This will be filled in with -1 we can't determine a value or there is no battery.
+ * \returns the current battery state or `SDL_POWERSTATE_ERROR` on failure; call SDL_GetError() for more information.
*
* \since This function is available since SDL 3.0.0.
*/
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 47adfb82d6083..a63155052a3e6 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -232,6 +232,7 @@ SDL3_0.0.0 {
SDL_GetGamepadButtonFromString;
SDL_GetGamepadButtonLabel;
SDL_GetGamepadButtonLabelForType;
+ SDL_GetGamepadConnectionState;
SDL_GetGamepadFirmwareVersion;
SDL_GetGamepadFromInstanceID;
SDL_GetGamepadFromPlayerIndex;
@@ -252,7 +253,7 @@ SDL3_0.0.0 {
SDL_GetGamepadName;
SDL_GetGamepadPath;
SDL_GetGamepadPlayerIndex;
- SDL_GetGamepadPowerLevel;
+ SDL_GetGamepadPowerInfo;
SDL_GetGamepadProduct;
SDL_GetGamepadProductVersion;
SDL_GetGamepadProperties;
@@ -287,6 +288,7 @@ SDL3_0.0.0 {
SDL_GetJoystickAxisInitialState;
SDL_GetJoystickBall;
SDL_GetJoystickButton;
+ SDL_GetJoystickConnectionState;
SDL_GetJoystickFirmwareVersion;
SDL_GetJoystickFromInstanceID;
SDL_GetJoystickFromPlayerIndex;
@@ -307,7 +309,7 @@ SDL3_0.0.0 {
SDL_GetJoystickName;
SDL_GetJoystickPath;
SDL_GetJoystickPlayerIndex;
- SDL_GetJoystickPowerLevel;
+ SDL_GetJoystickPowerInfo;
SDL_GetJoystickProduct;
SDL_GetJoystickProductVersion;
SDL_GetJoystickProperties;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 41f3622269eb1..b94b0e83684e0 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -257,6 +257,7 @@
#define SDL_GetGamepadButtonFromString SDL_GetGamepadButtonFromString_REAL
#define SDL_GetGamepadButtonLabel SDL_GetGamepadButtonLabel_REAL
#define SDL_GetGamepadButtonLabelForType SDL_GetGamepadButtonLabelForType_REAL
+#define SDL_GetGamepadConnectionState SDL_GetGamepadConnectionState_REAL
#define SDL_GetGamepadFirmwareVersion SDL_GetGamepadFirmwareVersion_REAL
#define SDL_GetGamepadFromInstanceID SDL_GetGamepadFromInstanceID_REAL
#define SDL_GetGamepadFromPlayerIndex SDL_GetGamepadFromPlayerIndex_REAL
@@ -277,7 +278,7 @@
#define SDL_GetGamepadName SDL_GetGamepadName_REAL
#define SDL_GetGamepadPath SDL_GetGamepadPath_REAL
#define SDL_GetGamepadPlayerIndex SDL_GetGamepadPlayerIndex_REAL
-#define SDL_GetGamepadPowerLevel SDL_GetGamepadPowerLevel_REAL
+#define SDL_GetGamepadPowerInfo SDL_GetGamepadPowerInfo_REAL
#define SDL_GetGamepadProduct SDL_GetGamepadProduct_REAL
#define SDL_GetGamepadProductVersion SDL_GetGamepadProductVersion_REAL
#define SDL_GetGamepadProperties SDL_GetGamepadProperties_REAL
@@ -312,6 +313,7 @@
#define SDL_GetJoystickAxisInitialState SDL_GetJoystickAxisInitialState_REAL
#define SDL_GetJoystickBall SDL_GetJoystickBall_REAL
#define SDL_GetJoystickButton SDL_GetJoystickButton_REAL
+#define SDL_GetJoystickConnectionState SDL_GetJoystickConnectionState_REAL
#define SDL_GetJoystickFirmwareVersion SDL_GetJoystickFirmwareVersion_REAL
#define SDL_GetJoystickFromInstanceID SDL_GetJoystickFromInstanceID_REAL
#define SDL_GetJoystickFromPlayerIndex SDL_GetJoystickFromPlayerIndex_REAL
@@ -332,7 +334,7 @@
#define SDL_GetJoystickName SDL_GetJoystickName_REAL
#define SDL_GetJoystickPath SDL_GetJoystickPath_REAL
#define SDL_GetJoystickPlayerIndex SDL_GetJoystickPlayerIndex_REAL
-#define SDL_GetJoystickPowerLevel SDL_GetJoystickPowerLevel_REAL
+#define SDL_GetJoystickPowerInfo SDL_GetJoystickPowerInfo_REAL
#define SDL_GetJoystickProduct SDL_GetJoystickProduct_REAL
#define SDL_GetJoystickProductVersion SDL_GetJoystickProductVersion_REAL
#define SDL_GetJoystickProperties SDL_GetJoystickProperties_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 5218b1cba80cd..40ebf9bb2228d 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -295,6 +295,7 @@ SDL_DYNAPI_PROC(Uint8,SDL_GetGamepadButton,(SDL_Gamepad *a, SDL_GamepadButton b)
SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadButtonFromString,(const char *a),(a),return)
SDL_DYNAPI_PROC(SDL_GamepadButtonLabel,SDL_GetGamepadButtonLabel,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return)
SDL_DYNAPI_PROC(SDL_GamepadButtonLabel,SDL_GetGamepadButtonLabelForType,(SDL_GamepadType a, SDL_GamepadButton b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_JoystickConnectionState,SDL_GetGamepadConnectionState,(SDL_Gamepad *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_GetGamepadFirmwareVersion,(SDL_Gamepad *a),(a),return)
SDL_DYNAPI_PROC(SDL_Gamepad*,SDL_GetGamepadFromInstanceID,(SDL_JoystickID a),(a),return)
SDL_DYNAPI_PROC(SDL_Gamepad*,SDL_GetGamepadFromPlayerIndex,(int a),(a),return)
@@ -315,7 +316,7 @@ SDL_DYNAPI_PROC(char**,SDL_GetGamepadMappings,(int *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetGamepadName,(SDL_Gamepad *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetGamepadPath,(SDL_Gamepad *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetGamepadPlayerIndex,(SDL_Gamepad *a),(a),return)
-SDL_DYNAPI_PROC(SDL_JoystickPowerLevel,SDL_GetGamepadPowerLevel,(SDL_Gamepad *a),(a),return)
+SDL_DYNAPI_PROC(SDL_PowerState,SDL_GetGamepadPowerInfo,(SDL_Gamepad *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(Uint16,SDL_GetGamepadProduct,(SDL_Gamepad *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_GetGamepadProductVersion,(SDL_Gamepad *a),(a),return)
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetGamepadProperties,(SDL_Gamepad *a),(a),return)
@@ -350,6 +351,7 @@ SDL_DYNAPI_PROC(Sint16,SDL_GetJoystickAxis,(SDL_Joystick *a, int b),(a,b),return
SDL_DYNAPI_PROC(SDL_bool,SDL_GetJoystickAxisInitialState,(SDL_Joystick *a, int b, Sint16 *c),(a,b,c),return)
SDL_DYNAPI_PROC(int,SDL_GetJoystickBall,(SDL_Joystick *a, int b, int *c, int *d),(a,b,c,d),return)
SDL_DYNAPI_PROC(Uint8,SDL_GetJoystickButton,(SDL_Joystick *a, int b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_JoystickConnectionState,SDL_GetJoystickConnectionState,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_GetJoystickFirmwareVersion,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(SDL_Joystick*,SDL_GetJoystickFromInstanceID,(SDL_JoystickID a),(a),return)
SDL_DYNAPI_PROC(SDL_Joystick*,SDL_GetJoystickFromPlayerIndex,(int a),(a),return)
@@ -370,7 +372,7 @@ SDL_DYNAPI_PROC(Uint16,SDL_GetJoystickInstanceVendor,(SDL_JoystickID a),(a),retu
SDL_DYNAPI_PROC(const char*,SDL_GetJoystickName,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(const char*,SDL_GetJoystickPath,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(int,SDL_GetJoystickPlayerIndex,(SDL_Joystick *a),(a),return)
-SDL_DYNAPI_PROC(SDL_JoystickPowerLevel,SDL_GetJoystickPowerLevel,(SDL_Joystick *a),(a),return)
+SDL_DYNAPI_PROC(SDL_PowerState,SDL_GetJoystickPowerInfo,(SDL_Joystick *a, int *b),(a,b),return)
SDL_DYNAPI_PROC(Uint16,SDL_GetJoystickProduct,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(Uint16,SDL_GetJoystickProductVersion,(SDL_Joystick *a),(a),return)
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetJoystickProperties,(SDL_Joystick *a),(a),return)
diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c
index c5f56828a8bee..0136ec1e6fc6d 100644
--- a/src/joystick/SDL_gamepad.c
+++ b/src/joystick/SDL_gamepad.c
@@ -3427,14 +3427,27 @@ Uint64 SDL_GetGamepadSteamHandle(SDL_Gamepad *gamepad)
return handle;
}
-SDL_JoystickPowerLevel SDL_GetGamepadPowerLevel(SDL_Gamepad *gamepad)
+SDL_JoystickConnectionState SDL_GetGamepadConnectionState(SDL_Gamepad *gamepad)
{
SDL_Joystick *joystick = SDL_GetGamepadJoystick(gamepad);
if (!joystick) {
- return SDL_JOYSTICK_POWER_UNKNOWN;
+ return SDL_JOYSTICK_CONNECTION_INVALID;
}
- return SDL_GetJoystickPowerLevel(joystick);
+ return SDL_GetJoystickConnectionState(joystick);
+}
+
+SDL_PowerState SDL_GetGamepadPowerInfo(SDL_Gamepad *gamepad, int *percent)
+{
+ SDL_Joystick *joystick = SDL_GetGamepadJoystick(gamepad);
+
+ if (percent) {
+ *percent = -1;
+ }
+ if (!joystick) {
+ return SDL_POWERSTATE_ERROR;
+ }
+ return SDL_GetJoystickPowerInfo(joystick, percent);
}
/*
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index b0da208822a5f..f0d4ad7180a9c 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -1054,7 +1054,6 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
SDL_Joystick *joysticklist;
const char *joystickname = NULL;
const char *joystickpath = NULL;
- SDL_JoystickPowerLevel initial_power_level;
SDL_bool invert_sensors = SDL_FALSE;
const SDL_SteamVirtualGamepadInfo *info;
@@ -1089,8 +1088,8 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->driver = driver;
joystick->instance_id = instance_id;
joystick->attached = SDL_TRUE;
- joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
joystick->led_expiration = SDL_GetTicks();
+ joystick->battery_percent = -1;
if (driver->Open(joystick, device_index) < 0) {
SDL_free(joystick);
@@ -1159,11 +1158,6 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id)
joystick->next = SDL_joysticks;
SDL_joysticks = joystick;
- /* send initial battery event */
- initial_power_level = joystick->epowerlevel;
- joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
- SDL_SendJoystickBatteryLevel(joystick, initial_power_level);
-
driver->Update(joystick);
SDL_UnlockJoysticks();
@@ -3410,35 +3404,58 @@ SDL_JoystickGUID SDL_GetJoystickGUIDFromString(const char *pchGUID)
return SDL_GUIDFromString(pchGUID);
}
-/* update the power level for this joystick */
-void SDL_SendJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
+void SDL_SendJoystickPowerInfo(SDL_Joystick *joystick, SDL_PowerState state, int percent)
{
SDL_AssertJoysticksLocked();
- SDL_assert(joystick->ref_count); /* make sure we are calling this only for update, not for initialization */
- if (ePowerLevel != joystick->epowerlevel) {
+ if (state != joystick->battery_state || percent != joystick->battery_percent) {
+ joystick->battery_state = state;
+ joystick->battery_percent = percent;
+
if (SDL_EventEnabled(SDL_EVENT_JOYSTICK_BATTERY_UPDATED)) {
SDL_Event event;
event.type = SDL_EVENT_JOYSTICK_BATTERY_UPDATED;
event.common.timestamp = 0;
event.jbattery.which = joystick->instance_id;
- event.jbattery.level = ePowerLevel;
+ event.jbattery.state = state;
+ event.jbattery.percent = percent;
SDL_PushEvent(&event);
}
- joystick->epowerlevel = ePowerLevel;
}
}
-/* return its power level */
-SDL_JoystickPowerLevel SDL_GetJoystickPowerLevel(SDL_Joystick *joystick)
+SDL_JoystickConnectionState SDL_GetJoystickConnectionState(SDL_Joystick *joystick)
{
- SDL_JoystickPowerLevel retval;
+ SDL_JoystickConnectionState retval;
SDL_LockJoysticks();
{
- CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_POWER_UNKNOWN);
+ CHECK_JOYSTICK_MAGIC(joystick, SDL_JOYSTICK_CONNECTION_INVALID);
+
+ retval = joystick->connection_state;
+ }
+ SDL_UnlockJoysticks();
- retval = joystick->epowerlevel;
+ return retval;
+}
+
+SDL_PowerState SDL_GetJoystickPowerInfo(SDL_Joystick *joystick, int *percent)
+{
+ SDL_PowerState retval;
+
+ if (percent) {
+ *percent = -1;
+ }
+
+ SDL_LockJoysticks();
+ {
+ CHECK_JOYSTICK_MAGIC(joystick, SDL_POWERSTATE_ERROR);
+
+ retval = joystick->battery_state;
+
+ if (percent) {
+ *percent = joystick->battery_percent;
+ }
}
SDL_UnlockJoysticks();
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index fd50467cbedde..b45c594d5c9f4 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -167,7 +167,7 @@ extern int SDL_SendJoystickHat(Uint64 timestamp, SDL_Joystick *joystick, Uint8 h
extern int SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 button, Uint8 state);
extern int SDL_SendJoystickTouchpad(Uint64 timestamp, SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure);
extern int SDL_SendJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick, SDL_SensorType type, Uint64 sensor_timestamp, const float *data, int num_values);
-extern void SDL_SendJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel);
+extern void SDL_SendJoystickPowerInfo(SDL_Joystick *joystick, SDL_PowerState state, int percent);
/* Function to get the Steam virtual gamepad info for a joystick */
extern const struct SDL_SteamVirtualGamepadInfo *SDL_GetJoystickInstanceVirtualGamepadInfo(SDL_JoystickID instance_id);
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 68eb038e0ef90..d6c50aff6371f 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -121,8 +121,11 @@ struct SDL_Joystick
SDL_bool attached _guarded;
SDL_bool is_gamepad _guarded;
+ SDL_JoystickConnectionState connection_state _guarded;
+ SDL_PowerState battery_state _guarded;
+ int battery_percent _guarded;
+
SDL_bool delayed_guide_button _guarded; /* SDL_TRUE if this device has the guide button event delayed */
- SDL_JoystickPowerLevel epowerlevel _guarded; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
SDL_SensorID accel_sensor _guarded;
SDL_Sensor *accel _guarded;
diff --git a/src/joystick/apple/SDL_mfijoystick.m b/src/joystick/apple/SDL_mfijoystick.m
index 81626a776985e..a0c677b5cd440 100644
--- a/src/joystick/apple/SDL_mfijoystick.m
+++ b/src/joystick/apple/SDL_mfijoystick.m
@@ -1296,33 +1296,24 @@ static void IOS_MFIJoystickUpdate(SDL_Joystick *joystick)
if (@available(macOS 10.16, iOS 14.0, tvOS 14.0, *)) {
GCDeviceBattery *battery = controller.battery;
if (battery) {
- SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN;
+ SDL_PowerState state = SDL_POWERSTATE_UNKNOWN;
+ int percent = (int)SDL_roundf(battery.batteryLevel * 100.0f);
switch (battery.batteryState) {
case GCDeviceBatteryStateDischarging:
- {
- float power_level = battery.batteryLevel;
- if (power_level <= 0.05f) {
- ePowerLevel = SDL_JOYSTICK_POWER_EMPTY;
- } else if (power_level <= 0.20f) {
- ePowerLevel = SDL_JOYSTICK_POWER_LOW;
- } else if (power_level <= 0.70f) {
- ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM;
- } else {
- ePowerLevel = SDL_JOYSTICK_POWER_FULL;
- }
- } break;
+ state = SDL_POWERSTATE_ON_BATTERY;
+ break;
case GCDeviceBatteryStateCharging:
- ePowerLevel = SDL_JOYSTICK_POWER_WIRED;
+ state = SDL_POWERSTATE_CHARGING;
break;
case GCDeviceBatteryStateFull:
- ePowerLevel = SDL_JOYSTICK_POWER_FULL;
+ state = SDL_POWERSTATE_CHARGED;
break;
default:
break;
}
- SDL_SendJoystickBatteryLevel(joystick, ePowerLevel);
+ SDL_SendJoystickPowerInfo(joystick, state, percent);
}
}
#endif /* ENABLE_MFI_BATTERY */
diff --git a/src/joystick/gdk/SDL_gameinputjoystick.c b/src/joystick/gdk/SDL_gameinputjoystick.c
index c3ee5a2e776bf..6adf2ca8d586b 100644
--- a/src/joystick/gdk/SDL_gameinputjoystick.c
+++ b/src/joystick/gdk/SDL_gameinputjoystick.c
@@ -341,17 +341,36 @@ static SDL_JoystickID GAMEINPUT_JoystickGetDeviceInstanceID(int device_index)
return GAMEINPUT_InternalFindByIndex(device_index)->device_instance;
}
-static SDL_JoystickPowerLevel GAMEINPUT_InternalGetPowerLevel(IGameInputDevice *device)
+static void GAMEINPUT_UpdatePowerInfo(SDL_Joystick *joystick, IGameInputDevice *device)
{
GameInputBatteryState battery_state;
+ SDL_PowerState state;
+ int percent = 0;
SDL_zero(battery_state);
IGameInputDevice_GetBatteryState(device, &battery_state);
- if (battery_state.status == GameInputBatteryDischarging) {
- /* FIXME: What are the units for remainingCapacity? */
- }
- return SDL_JOYSTICK_POWER_UNKNOWN;
+ switch (battery_state.status) {
+ case GameInputBatteryNotPresent:
+ state = SDL_POWERSTATE_NO_BATTERY;
+ break;
+ case GameInputBatteryDischarging:
+ state = SDL_POWERSTATE_ON_BATTERY;
+ break;
+ case GameInputBatteryIdle:
+ state = SDL_POWERSTATE_CHARGED;
+ break;
+ case GameInputBatteryCharging:
+ state = SDL_POWERSTATE_CHARGING;
+ break;
+ default:
+ state = SDL_POWERSTATE_UNKNOWN;
+ break;
+ }
+ if (battery_state.fullChargeCapacity > 0.0f) {
+ percent = (int)SDL_roundf((battery_state.remainingCapacity / battery_state.fullChargeCapacity) * 100.0f);
+ }
+ SDL_SendJoystickPowerInfo(joystick, state, percent);
}
#if 0
@@ -417,9 +436,9 @@ static int GAMEINPUT_JoystickOpen(SDL_Joystick *joystick, int device_index)
}
if (info->capabilities & GameInputDeviceCapabilityWireless) {
- joystick->epowerlevel = GAMEINPUT_InternalGetPowerLevel(elem->device);
+ joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS;
} else {
- joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED;
+ joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRED;
}
return 0;
}
@@ -580,10 +599,8 @@ static void GAMEINPUT_JoystickUpdate(SDL_Joystick *joystick)
IGameInputReading_Rele
(Patch may be truncated, please check the link at the top of this post.)