From a0c4b56ff94d3ed11b7adb1ee6bbc4594210b4b6 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 30 Sep 2015 15:39:30 -0700 Subject: [PATCH] SDL - added new SDL_JoystickCurrentPowerLevel() API that returns the battery level of the selected joystick. Currently only implemented for XInput devices, other platforms are a TODO. CR: Sam --- include/SDL_joystick.h | 15 +++++++ src/core/windows/SDL_xinput.c | 3 ++ src/core/windows/SDL_xinput.h | 38 +++++++++++++++++ src/joystick/SDL_joystick.c | 26 ++++++++++-- src/joystick/SDL_joystick_c.h | 2 + src/joystick/SDL_sysjoystick.h | 1 + src/joystick/windows/SDL_xinputjoystick.c | 50 +++++++++++++++++++++-- 7 files changed, 127 insertions(+), 8 deletions(-) diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h index cad06a86c..a707e6c38 100644 --- a/include/SDL_joystick.h +++ b/include/SDL_joystick.h @@ -71,6 +71,16 @@ typedef struct { typedef Sint32 SDL_JoystickID; +typedef enum +{ + SDL_JOYSTICK_POWER_UNKNOWN = -1, + SDL_JOYSTICK_POWER_EMPTY, + SDL_JOYSTICK_POWER_LOW, + SDL_JOYSTICK_POWER_MEDIUM, + SDL_JOYSTICK_POWER_FULL, + SDL_JOYSTICK_POWER_WIRED, + SDL_JOYSTICK_POWER_MAX +} SDL_JoystickPowerLevel; /* Function prototypes */ /** @@ -242,6 +252,11 @@ extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick, */ extern DECLSPEC void SDLCALL SDL_JoystickClose(SDL_Joystick * joystick); +/** +* Return the battery level of this joystick +*/ +extern DECLSPEC SDL_JoystickPowerLevel SDLCALL SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/src/core/windows/SDL_xinput.c b/src/core/windows/SDL_xinput.c index f892a8d94..1e13faea6 100644 --- a/src/core/windows/SDL_xinput.c +++ b/src/core/windows/SDL_xinput.c @@ -29,6 +29,7 @@ XInputGetState_t SDL_XInputGetState = NULL; XInputSetState_t SDL_XInputSetState = NULL; XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL; +XInputGetBatteryInformation_t SDL_XInputGetBatteryInformation = NULL; DWORD SDL_XInputVersion = 0; static HANDLE s_pXInputDLL = 0; @@ -55,6 +56,7 @@ WIN_LoadXInputDLL(void) SDL_XInputGetState = (XInputGetState_t)XInputGetState; SDL_XInputSetState = (XInputSetState_t)XInputSetState; SDL_XInputGetCapabilities = (XInputGetCapabilities_t)XInputGetCapabilities; + SDL_XInputGetBatteryInformation = (XInputGetBatteryInformation_t)XInputGetBatteryInformation; /* XInput 1.4 ships with Windows 8 and 8.1: */ SDL_XInputVersion = (1 << 16) | 4; @@ -108,6 +110,7 @@ WIN_LoadXInputDLL(void) } SDL_XInputSetState = (XInputSetState_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputSetState"); SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputGetCapabilities"); + SDL_XInputGetBatteryInformation = (XInputGetBatteryInformation_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetBatteryInformation" ); if (!SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities) { WIN_UnloadXInputDLL(); return -1; diff --git a/src/core/windows/SDL_xinput.h b/src/core/windows/SDL_xinput.h index 5c5773763..664edd0c5 100644 --- a/src/core/windows/SDL_xinput.h +++ b/src/core/windows/SDL_xinput.h @@ -76,6 +76,29 @@ #define XINPUT_GAMEPAD_GUIDE 0x0400 #endif +#ifndef BATTERY_DEVTYPE_GAMEPAD +#define BATTERY_DEVTYPE_GAMEPAD 0x00 +#endif +#ifndef BATTERY_TYPE_WIRED +#define BATTERY_TYPE_WIRED 0x01 +#endif + +#ifndef BATTERY_TYPE_UNKNOWN +#define BATTERY_TYPE_UNKNOWN 0xFF +#endif +#ifndef BATTERY_LEVEL_EMPTY +#define BATTERY_LEVEL_EMPTY 0x00 +#endif +#ifndef BATTERY_LEVEL_LOW +#define BATTERY_LEVEL_LOW 0x01 +#endif +#ifndef BATTERY_LEVEL_MEDIUM +#define BATTERY_LEVEL_MEDIUM 0x02 +#endif +#ifndef BATTERY_LEVEL_FULL +#define BATTERY_LEVEL_FULL 0x03 +#endif + /* typedef's for XInput structs we use */ typedef struct { @@ -95,6 +118,12 @@ typedef struct XINPUT_GAMEPAD_EX Gamepad; } XINPUT_STATE_EX; +typedef struct _XINPUT_BATTERY_INFORMATION +{ + BYTE BatteryType; + BYTE BatteryLevel; +} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION; + /* Forward decl's for XInput API's we load dynamically and use if available */ typedef DWORD (WINAPI *XInputGetState_t) ( @@ -115,17 +144,26 @@ typedef DWORD (WINAPI *XInputGetCapabilities_t) XINPUT_CAPABILITIES* pCapabilities /* [out] Receives the capabilities */ ); +typedef DWORD (WINAPI *XInputGetBatteryInformation_t) + ( + _In_ DWORD dwUserIndex, + _In_ BYTE devType, + _Out_ XINPUT_BATTERY_INFORMATION *pBatteryInformation + ); + extern int WIN_LoadXInputDLL(void); extern void WIN_UnloadXInputDLL(void); extern XInputGetState_t SDL_XInputGetState; extern XInputSetState_t SDL_XInputSetState; extern XInputGetCapabilities_t SDL_XInputGetCapabilities; +extern XInputGetBatteryInformation_t SDL_XInputGetBatteryInformation; extern DWORD SDL_XInputVersion; /* ((major << 16) & 0xFF00) | (minor & 0xFF) */ #define XINPUTGETSTATE SDL_XInputGetState #define XINPUTSETSTATE SDL_XInputSetState #define XINPUTGETCAPABILITIES SDL_XInputGetCapabilities +#define XINPUTGETBATTERYINFORMATION SDL_XInputGetBatteryInformation #endif /* HAVE_XINPUT_H */ diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 4725a5776..532748cde 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -178,6 +178,7 @@ SDL_JoystickOpen(int device_index) if (joystick->buttons) { SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8)); } + joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; /* Add joystick to list */ ++joystick->ref_count; @@ -619,10 +620,10 @@ SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state) /* Make sure we're not getting garbage or duplicate events */ if (button >= joystick->nbuttons) { return 0; - } - if (state == joystick->buttons[button]) { - return 0; - } + } + if (state == joystick->buttons[button]) { + return 0; + } /* We ignore events if we don't have keyboard focus, except for button * release. */ @@ -825,4 +826,21 @@ 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; +} + + +/* return its power level */ +SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick) +{ + if (!SDL_PrivateJoystickValid(joystick)) { + return (SDL_JOYSTICK_POWER_UNKNOWN); + } + return joystick->epowerlevel; +} + + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index ee4a14a37..2da74bd3c 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -41,6 +41,8 @@ extern int SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value); extern int SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state); +extern void SDL_PrivateJoystickBatteryLevel( SDL_Joystick * joystick, + SDL_JoystickPowerLevel ePowerLevel ); /* Internal sanity checking functions */ extern int SDL_PrivateJoystickValid(SDL_Joystick * joystick); diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 7c104b500..f03e40429 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -54,6 +54,7 @@ struct _SDL_Joystick int ref_count; /* Reference count for multiple opens */ SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */ + SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */ struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */ }; diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index b1c22ab1f..b3a4c9e6d 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -221,8 +221,39 @@ SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde return 0; } +static void +UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION *pBatteryInformation) +{ + if ( pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN ) + { + SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN; + if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) { + ePowerLevel = SDL_JOYSTICK_POWER_WIRED; + } else { + switch ( pBatteryInformation->BatteryLevel ) + { + case BATTERY_LEVEL_EMPTY: + ePowerLevel = SDL_JOYSTICK_POWER_EMPTY; + break; + case BATTERY_LEVEL_LOW: + ePowerLevel = SDL_JOYSTICK_POWER_LOW; + break; + case BATTERY_LEVEL_MEDIUM: + ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM; + break; + default: + case BATTERY_LEVEL_FULL: + ePowerLevel = SDL_JOYSTICK_POWER_FULL; + break; + } + } + + SDL_PrivateJoystickBatteryLevel( joystick, ePowerLevel ); + } +} + static void -UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState) +UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION *pBatteryInformation) { static WORD s_XInputButtons[] = { XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, @@ -244,10 +275,12 @@ UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputS for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) { SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED); } + + UpdateXInputJoystickBatteryInformation( joystick, pBatteryInformation ); } static void -UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState) +UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION *pBatteryInformation) { static WORD s_XInputButtons[] = { XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, @@ -283,6 +316,8 @@ UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState hat |= SDL_HAT_RIGHT; } SDL_PrivateJoystickHat(joystick, 0, hat); + + UpdateXInputJoystickBatteryInformation( joystick, pBatteryInformation ); } void @@ -290,6 +325,7 @@ SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) { HRESULT result; XINPUT_STATE_EX XInputState; + XINPUT_BATTERY_INFORMATION XBatteryInformation; if (!XINPUTGETSTATE) return; @@ -301,12 +337,18 @@ SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) return; } + SDL_zero( XBatteryInformation ); + if ( XINPUTGETBATTERYINFORMATION ) + { + result = XINPUTGETBATTERYINFORMATION( joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation ); + } + /* only fire events if the data changed from last time */ if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) { if (SDL_XInputUseOldJoystickMapping()) { - UpdateXInputJoystickState_OLD(joystick, &XInputState); + UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation); } else { - UpdateXInputJoystickState(joystick, &XInputState); + UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation); } joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber; }