initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
112
thirdparty/sdl/core/windows/SDL_directx.h
vendored
Normal file
112
thirdparty/sdl/core/windows/SDL_directx.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_directx_h_
|
||||
#define SDL_directx_h_
|
||||
|
||||
// Include all of the DirectX 8.0 headers and adds any necessary tweaks
|
||||
|
||||
#include "SDL_windows.h"
|
||||
#include <mmsystem.h>
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#undef WINNT
|
||||
|
||||
// Far pointers don't exist in 32-bit code
|
||||
#ifndef FAR
|
||||
#define FAR
|
||||
#endif
|
||||
|
||||
// Error codes not yet included in Win32 API header files
|
||||
#ifndef MAKE_HRESULT
|
||||
#define MAKE_HRESULT(sev, fac, code) \
|
||||
((HRESULT)(((unsigned long)(sev) << 31) | ((unsigned long)(fac) << 16) | ((unsigned long)(code))))
|
||||
#endif
|
||||
|
||||
#ifndef S_OK
|
||||
#define S_OK (HRESULT)0x00000000L
|
||||
#endif
|
||||
|
||||
#ifndef SUCCEEDED
|
||||
#define SUCCEEDED(x) ((HRESULT)(x) >= 0)
|
||||
#endif
|
||||
#ifndef FAILED
|
||||
#define FAILED(x) ((HRESULT)(x) < 0)
|
||||
#endif
|
||||
|
||||
#ifndef E_FAIL
|
||||
#define E_FAIL (HRESULT)0x80000008L
|
||||
#endif
|
||||
#ifndef E_NOINTERFACE
|
||||
#define E_NOINTERFACE (HRESULT)0x80004002L
|
||||
#endif
|
||||
#ifndef E_OUTOFMEMORY
|
||||
#define E_OUTOFMEMORY (HRESULT)0x8007000EL
|
||||
#endif
|
||||
#ifndef E_INVALIDARG
|
||||
#define E_INVALIDARG (HRESULT)0x80070057L
|
||||
#endif
|
||||
#ifndef E_NOTIMPL
|
||||
#define E_NOTIMPL (HRESULT)0x80004001L
|
||||
#endif
|
||||
#ifndef REGDB_E_CLASSNOTREG
|
||||
#define REGDB_E_CLASSNOTREG (HRESULT)0x80040154L
|
||||
#endif
|
||||
|
||||
// Severity codes
|
||||
#ifndef SEVERITY_ERROR
|
||||
#define SEVERITY_ERROR 1
|
||||
#endif
|
||||
|
||||
// Error facility codes
|
||||
#ifndef FACILITY_WIN32
|
||||
#define FACILITY_WIN32 7
|
||||
#endif
|
||||
|
||||
#ifndef FIELD_OFFSET
|
||||
#define FIELD_OFFSET(type, field) ((LONG) & (((type *)0)->field))
|
||||
#endif
|
||||
|
||||
/* DirectX headers (if it isn't included, I haven't tested it yet)
|
||||
*/
|
||||
// We need these defines to mark what version of DirectX API we use
|
||||
#define DIRECTDRAW_VERSION 0x0700
|
||||
#define DIRECTSOUND_VERSION 0x0800
|
||||
#define DIRECTINPUT_VERSION 0x0800 // Need version 7 for force feedback. Need version 8 so IDirectInput8_EnumDevices doesn't leak like a sieve...
|
||||
|
||||
#ifdef HAVE_DDRAW_H
|
||||
#include <ddraw.h>
|
||||
#endif
|
||||
#ifdef HAVE_DSOUND_H
|
||||
#include <dsound.h>
|
||||
#endif
|
||||
#ifdef HAVE_DINPUT_H
|
||||
#include <dinput.h>
|
||||
#else
|
||||
typedef struct
|
||||
{
|
||||
int unused;
|
||||
} DIDEVICEINSTANCE;
|
||||
#endif
|
||||
|
||||
#endif // SDL_directx_h_
|
98
thirdparty/sdl/core/windows/SDL_gameinput.c
vendored
Normal file
98
thirdparty/sdl/core/windows/SDL_gameinput.c
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef HAVE_GAMEINPUT_H
|
||||
|
||||
#include "SDL_windows.h"
|
||||
#include "SDL_gameinput.h"
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
#include <initguid.h>
|
||||
// {11BE2A7E-4254-445A-9C09-FFC40F006918}
|
||||
DEFINE_GUID(SDL_IID_GameInput, 0x11BE2A7E, 0x4254, 0x445A, 0x9C, 0x09, 0xFF, 0xC4, 0x0F, 0x00, 0x69, 0x18);
|
||||
#endif
|
||||
|
||||
static SDL_SharedObject *g_hGameInputDLL;
|
||||
static IGameInput *g_pGameInput;
|
||||
static int g_nGameInputRefCount;
|
||||
|
||||
bool SDL_InitGameInput(IGameInput **ppGameInput)
|
||||
{
|
||||
if (g_nGameInputRefCount == 0) {
|
||||
g_hGameInputDLL = SDL_LoadObject("gameinput.dll");
|
||||
if (!g_hGameInputDLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef HRESULT (WINAPI *GameInputCreate_t)(IGameInput * *gameInput);
|
||||
GameInputCreate_t GameInputCreateFunc = (GameInputCreate_t)SDL_LoadFunction(g_hGameInputDLL, "GameInputCreate");
|
||||
if (!GameInputCreateFunc) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
return false;
|
||||
}
|
||||
|
||||
IGameInput *pGameInput = NULL;
|
||||
HRESULT hr = GameInputCreateFunc(&pGameInput);
|
||||
if (FAILED(hr)) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
return WIN_SetErrorFromHRESULT("GameInputCreate failed", hr);
|
||||
}
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
hr = IGameInput_QueryInterface(pGameInput, &SDL_IID_GameInput, (void **)&g_pGameInput);
|
||||
IGameInput_Release(pGameInput);
|
||||
if (FAILED(hr)) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
return WIN_SetErrorFromHRESULT("GameInput QueryInterface failed", hr);
|
||||
}
|
||||
#else
|
||||
// Assume that the version we get is compatible with the current SDK
|
||||
// If that isn't the case, define the correct GUID for SDL_IID_GameInput above
|
||||
g_pGameInput = pGameInput;
|
||||
#endif
|
||||
}
|
||||
++g_nGameInputRefCount;
|
||||
|
||||
if (ppGameInput) {
|
||||
*ppGameInput = g_pGameInput;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDL_QuitGameInput(void)
|
||||
{
|
||||
SDL_assert(g_nGameInputRefCount > 0);
|
||||
|
||||
--g_nGameInputRefCount;
|
||||
if (g_nGameInputRefCount == 0) {
|
||||
if (g_pGameInput) {
|
||||
IGameInput_Release(g_pGameInput);
|
||||
g_pGameInput = NULL;
|
||||
}
|
||||
if (g_hGameInputDLL) {
|
||||
SDL_UnloadObject(g_hGameInputDLL);
|
||||
g_hGameInputDLL = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_GAMEINPUT_H
|
36
thirdparty/sdl/core/windows/SDL_gameinput.h
vendored
Normal file
36
thirdparty/sdl/core/windows/SDL_gameinput.h
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_gameinput_h_
|
||||
#define SDL_gameinput_h_
|
||||
|
||||
#ifdef HAVE_GAMEINPUT_H
|
||||
|
||||
#define COBJMACROS
|
||||
#include <gameinput.h>
|
||||
|
||||
extern bool SDL_InitGameInput(IGameInput **ppGameInput);
|
||||
extern void SDL_QuitGameInput(void);
|
||||
|
||||
#endif // HAVE_GAMEINPUT_H
|
||||
|
||||
#endif // SDL_gameinput_h_
|
254
thirdparty/sdl/core/windows/SDL_hid.c
vendored
Normal file
254
thirdparty/sdl/core/windows/SDL_hid.c
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_hid.h"
|
||||
|
||||
HidD_GetAttributes_t SDL_HidD_GetAttributes;
|
||||
HidD_GetString_t SDL_HidD_GetManufacturerString;
|
||||
HidD_GetString_t SDL_HidD_GetProductString;
|
||||
HidP_GetCaps_t SDL_HidP_GetCaps;
|
||||
HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
|
||||
HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
|
||||
HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
|
||||
HidP_GetData_t SDL_HidP_GetData;
|
||||
|
||||
static HMODULE s_pHIDDLL = 0;
|
||||
static int s_HIDDLLRefCount = 0;
|
||||
|
||||
|
||||
bool WIN_LoadHIDDLL(void)
|
||||
{
|
||||
if (s_pHIDDLL) {
|
||||
SDL_assert(s_HIDDLLRefCount > 0);
|
||||
s_HIDDLLRefCount++;
|
||||
return true; // already loaded
|
||||
}
|
||||
|
||||
s_pHIDDLL = LoadLibrary(TEXT("hid.dll"));
|
||||
if (!s_pHIDDLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_assert(s_HIDDLLRefCount == 0);
|
||||
s_HIDDLLRefCount = 1;
|
||||
|
||||
SDL_HidD_GetAttributes = (HidD_GetAttributes_t)GetProcAddress(s_pHIDDLL, "HidD_GetAttributes");
|
||||
SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");
|
||||
SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");
|
||||
SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");
|
||||
SDL_HidP_GetButtonCaps = (HidP_GetButtonCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetButtonCaps");
|
||||
SDL_HidP_GetValueCaps = (HidP_GetValueCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetValueCaps");
|
||||
SDL_HidP_MaxDataListLength = (HidP_MaxDataListLength_t)GetProcAddress(s_pHIDDLL, "HidP_MaxDataListLength");
|
||||
SDL_HidP_GetData = (HidP_GetData_t)GetProcAddress(s_pHIDDLL, "HidP_GetData");
|
||||
if (!SDL_HidD_GetManufacturerString || !SDL_HidD_GetProductString ||
|
||||
!SDL_HidP_GetCaps || !SDL_HidP_GetButtonCaps ||
|
||||
!SDL_HidP_GetValueCaps || !SDL_HidP_MaxDataListLength || !SDL_HidP_GetData) {
|
||||
WIN_UnloadHIDDLL();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WIN_UnloadHIDDLL(void)
|
||||
{
|
||||
if (s_pHIDDLL) {
|
||||
SDL_assert(s_HIDDLLRefCount > 0);
|
||||
if (--s_HIDDLLRefCount == 0) {
|
||||
FreeLibrary(s_pHIDDLL);
|
||||
s_pHIDDLL = NULL;
|
||||
}
|
||||
} else {
|
||||
SDL_assert(s_HIDDLLRefCount == 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
// CM_Register_Notification definitions
|
||||
|
||||
#define CR_SUCCESS 0
|
||||
|
||||
DECLARE_HANDLE(HCMNOTIFICATION);
|
||||
typedef HCMNOTIFICATION *PHCMNOTIFICATION;
|
||||
|
||||
typedef enum _CM_NOTIFY_FILTER_TYPE
|
||||
{
|
||||
CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE = 0,
|
||||
CM_NOTIFY_FILTER_TYPE_DEVICEHANDLE,
|
||||
CM_NOTIFY_FILTER_TYPE_DEVICEINSTANCE,
|
||||
CM_NOTIFY_FILTER_TYPE_MAX
|
||||
} CM_NOTIFY_FILTER_TYPE, *PCM_NOTIFY_FILTER_TYPE;
|
||||
|
||||
typedef struct _CM_NOTIFY_FILTER
|
||||
{
|
||||
DWORD cbSize;
|
||||
DWORD Flags;
|
||||
CM_NOTIFY_FILTER_TYPE FilterType;
|
||||
DWORD Reserved;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
GUID ClassGuid;
|
||||
} DeviceInterface;
|
||||
struct
|
||||
{
|
||||
HANDLE hTarget;
|
||||
} DeviceHandle;
|
||||
struct
|
||||
{
|
||||
WCHAR InstanceId[200];
|
||||
} DeviceInstance;
|
||||
} u;
|
||||
} CM_NOTIFY_FILTER, *PCM_NOTIFY_FILTER;
|
||||
|
||||
typedef enum _CM_NOTIFY_ACTION
|
||||
{
|
||||
CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL = 0,
|
||||
CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL,
|
||||
CM_NOTIFY_ACTION_DEVICEQUERYREMOVE,
|
||||
CM_NOTIFY_ACTION_DEVICEQUERYREMOVEFAILED,
|
||||
CM_NOTIFY_ACTION_DEVICEREMOVEPENDING,
|
||||
CM_NOTIFY_ACTION_DEVICEREMOVECOMPLETE,
|
||||
CM_NOTIFY_ACTION_DEVICECUSTOMEVENT,
|
||||
CM_NOTIFY_ACTION_DEVICEINSTANCEENUMERATED,
|
||||
CM_NOTIFY_ACTION_DEVICEINSTANCESTARTED,
|
||||
CM_NOTIFY_ACTION_DEVICEINSTANCEREMOVED,
|
||||
CM_NOTIFY_ACTION_MAX
|
||||
} CM_NOTIFY_ACTION, *PCM_NOTIFY_ACTION;
|
||||
|
||||
typedef struct _CM_NOTIFY_EVENT_DATA
|
||||
{
|
||||
CM_NOTIFY_FILTER_TYPE FilterType;
|
||||
DWORD Reserved;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
GUID ClassGuid;
|
||||
WCHAR SymbolicLink[ANYSIZE_ARRAY];
|
||||
} DeviceInterface;
|
||||
struct
|
||||
{
|
||||
GUID EventGuid;
|
||||
LONG NameOffset;
|
||||
DWORD DataSize;
|
||||
BYTE Data[ANYSIZE_ARRAY];
|
||||
} DeviceHandle;
|
||||
struct
|
||||
{
|
||||
WCHAR InstanceId[ANYSIZE_ARRAY];
|
||||
} DeviceInstance;
|
||||
} u;
|
||||
} CM_NOTIFY_EVENT_DATA, *PCM_NOTIFY_EVENT_DATA;
|
||||
|
||||
typedef DWORD (CALLBACK *PCM_NOTIFY_CALLBACK)(HCMNOTIFICATION hNotify, PVOID Context, CM_NOTIFY_ACTION Action, PCM_NOTIFY_EVENT_DATA EventData, DWORD EventDataSize);
|
||||
|
||||
typedef DWORD (WINAPI *CM_Register_NotificationFunc)(PCM_NOTIFY_FILTER pFilter, PVOID pContext, PCM_NOTIFY_CALLBACK pCallback, PHCMNOTIFICATION pNotifyContext);
|
||||
typedef DWORD (WINAPI *CM_Unregister_NotificationFunc)(HCMNOTIFICATION NotifyContext);
|
||||
|
||||
static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
|
||||
|
||||
static int s_DeviceNotificationsRequested;
|
||||
static HMODULE cfgmgr32_lib_handle;
|
||||
static CM_Register_NotificationFunc CM_Register_Notification;
|
||||
static CM_Unregister_NotificationFunc CM_Unregister_Notification;
|
||||
static HCMNOTIFICATION s_DeviceNotificationFuncHandle;
|
||||
static Uint64 s_LastDeviceNotification = 1;
|
||||
|
||||
static DWORD CALLBACK SDL_DeviceNotificationFunc(HCMNOTIFICATION hNotify, PVOID context, CM_NOTIFY_ACTION action, PCM_NOTIFY_EVENT_DATA eventData, DWORD event_data_size)
|
||||
{
|
||||
if (action == CM_NOTIFY_ACTION_DEVICEINTERFACEARRIVAL ||
|
||||
action == CM_NOTIFY_ACTION_DEVICEINTERFACEREMOVAL) {
|
||||
s_LastDeviceNotification = SDL_GetTicksNS();
|
||||
}
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void WIN_InitDeviceNotification(void)
|
||||
{
|
||||
++s_DeviceNotificationsRequested;
|
||||
if (s_DeviceNotificationsRequested > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
cfgmgr32_lib_handle = LoadLibraryA("cfgmgr32.dll");
|
||||
if (cfgmgr32_lib_handle) {
|
||||
CM_Register_Notification = (CM_Register_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Register_Notification");
|
||||
CM_Unregister_Notification = (CM_Unregister_NotificationFunc)GetProcAddress(cfgmgr32_lib_handle, "CM_Unregister_Notification");
|
||||
if (CM_Register_Notification && CM_Unregister_Notification) {
|
||||
CM_NOTIFY_FILTER notify_filter;
|
||||
|
||||
SDL_zero(notify_filter);
|
||||
notify_filter.cbSize = sizeof(notify_filter);
|
||||
notify_filter.FilterType = CM_NOTIFY_FILTER_TYPE_DEVICEINTERFACE;
|
||||
notify_filter.u.DeviceInterface.ClassGuid = GUID_DEVINTERFACE_HID;
|
||||
if (CM_Register_Notification(¬ify_filter, NULL, SDL_DeviceNotificationFunc, &s_DeviceNotificationFuncHandle) == CR_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Should we log errors?
|
||||
}
|
||||
|
||||
Uint64 WIN_GetLastDeviceNotification(void)
|
||||
{
|
||||
return s_LastDeviceNotification;
|
||||
}
|
||||
|
||||
void WIN_QuitDeviceNotification(void)
|
||||
{
|
||||
if (--s_DeviceNotificationsRequested > 0) {
|
||||
return;
|
||||
}
|
||||
// Make sure we have balanced calls to init/quit
|
||||
SDL_assert(s_DeviceNotificationsRequested == 0);
|
||||
|
||||
if (cfgmgr32_lib_handle) {
|
||||
if (s_DeviceNotificationFuncHandle && CM_Unregister_Notification) {
|
||||
CM_Unregister_Notification(s_DeviceNotificationFuncHandle);
|
||||
s_DeviceNotificationFuncHandle = NULL;
|
||||
}
|
||||
|
||||
FreeLibrary(cfgmgr32_lib_handle);
|
||||
cfgmgr32_lib_handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void WIN_InitDeviceNotification(void)
|
||||
{
|
||||
}
|
||||
|
||||
Uint64 WIN_GetLastDeviceNotification( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WIN_QuitDeviceNotification(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // !SDL_PLATFORM_XBOXONE && !SDL_PLATFORM_XBOXSERIES
|
215
thirdparty/sdl/core/windows/SDL_hid.h
vendored
Normal file
215
thirdparty/sdl/core/windows/SDL_hid.h
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_hid_h_
|
||||
#define SDL_hid_h_
|
||||
|
||||
#include "SDL_windows.h"
|
||||
|
||||
typedef LONG NTSTATUS;
|
||||
typedef USHORT USAGE;
|
||||
typedef struct _HIDP_PREPARSED_DATA *PHIDP_PREPARSED_DATA;
|
||||
|
||||
typedef struct _HIDD_ATTRIBUTES
|
||||
{
|
||||
ULONG Size;
|
||||
USHORT VendorID;
|
||||
USHORT ProductID;
|
||||
USHORT VersionNumber;
|
||||
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
HidP_Input = 0,
|
||||
HidP_Output = 1,
|
||||
HidP_Feature = 2
|
||||
} HIDP_REPORT_TYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USAGE UsagePage;
|
||||
UCHAR ReportID;
|
||||
BOOLEAN IsAlias;
|
||||
USHORT BitField;
|
||||
USHORT LinkCollection;
|
||||
USAGE LinkUsage;
|
||||
USAGE LinkUsagePage;
|
||||
BOOLEAN IsRange;
|
||||
BOOLEAN IsStringRange;
|
||||
BOOLEAN IsDesignatorRange;
|
||||
BOOLEAN IsAbsolute;
|
||||
ULONG Reserved[10];
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
USAGE UsageMin;
|
||||
USAGE UsageMax;
|
||||
USHORT StringMin;
|
||||
USHORT StringMax;
|
||||
USHORT DesignatorMin;
|
||||
USHORT DesignatorMax;
|
||||
USHORT DataIndexMin;
|
||||
USHORT DataIndexMax;
|
||||
} Range;
|
||||
struct
|
||||
{
|
||||
USAGE Usage;
|
||||
USAGE Reserved1;
|
||||
USHORT StringIndex;
|
||||
USHORT Reserved2;
|
||||
USHORT DesignatorIndex;
|
||||
USHORT Reserved3;
|
||||
USHORT DataIndex;
|
||||
USHORT Reserved4;
|
||||
} NotRange;
|
||||
};
|
||||
} HIDP_BUTTON_CAPS, *PHIDP_BUTTON_CAPS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USAGE UsagePage;
|
||||
UCHAR ReportID;
|
||||
BOOLEAN IsAlias;
|
||||
USHORT BitField;
|
||||
USHORT LinkCollection;
|
||||
USAGE LinkUsage;
|
||||
USAGE LinkUsagePage;
|
||||
BOOLEAN IsRange;
|
||||
BOOLEAN IsStringRange;
|
||||
BOOLEAN IsDesignatorRange;
|
||||
BOOLEAN IsAbsolute;
|
||||
BOOLEAN HasNull;
|
||||
UCHAR Reserved;
|
||||
USHORT BitSize;
|
||||
USHORT ReportCount;
|
||||
USHORT Reserved2[5];
|
||||
ULONG UnitsExp;
|
||||
ULONG Units;
|
||||
LONG LogicalMin;
|
||||
LONG LogicalMax;
|
||||
LONG PhysicalMin;
|
||||
LONG PhysicalMax;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
USAGE UsageMin;
|
||||
USAGE UsageMax;
|
||||
USHORT StringMin;
|
||||
USHORT StringMax;
|
||||
USHORT DesignatorMin;
|
||||
USHORT DesignatorMax;
|
||||
USHORT DataIndexMin;
|
||||
USHORT DataIndexMax;
|
||||
} Range;
|
||||
struct
|
||||
{
|
||||
USAGE Usage;
|
||||
USAGE Reserved1;
|
||||
USHORT StringIndex;
|
||||
USHORT Reserved2;
|
||||
USHORT DesignatorIndex;
|
||||
USHORT Reserved3;
|
||||
USHORT DataIndex;
|
||||
USHORT Reserved4;
|
||||
} NotRange;
|
||||
};
|
||||
} HIDP_VALUE_CAPS, *PHIDP_VALUE_CAPS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USAGE Usage;
|
||||
USAGE UsagePage;
|
||||
USHORT InputReportByteLength;
|
||||
USHORT OutputReportByteLength;
|
||||
USHORT FeatureReportByteLength;
|
||||
USHORT Reserved[17];
|
||||
USHORT NumberLinkCollectionNodes;
|
||||
USHORT NumberInputButtonCaps;
|
||||
USHORT NumberInputValueCaps;
|
||||
USHORT NumberInputDataIndices;
|
||||
USHORT NumberOutputButtonCaps;
|
||||
USHORT NumberOutputValueCaps;
|
||||
USHORT NumberOutputDataIndices;
|
||||
USHORT NumberFeatureButtonCaps;
|
||||
USHORT NumberFeatureValueCaps;
|
||||
USHORT NumberFeatureDataIndices;
|
||||
} HIDP_CAPS, *PHIDP_CAPS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USHORT DataIndex;
|
||||
USHORT Reserved;
|
||||
union
|
||||
{
|
||||
ULONG RawValue;
|
||||
BOOLEAN On;
|
||||
};
|
||||
} HIDP_DATA, *PHIDP_DATA;
|
||||
|
||||
#define HIDP_ERROR_CODES(p1, p2) ((NTSTATUS)(((p1) << 28) | (0x11 << 16) | (p2)))
|
||||
#define HIDP_STATUS_SUCCESS HIDP_ERROR_CODES(0x0, 0x0000)
|
||||
#define HIDP_STATUS_NULL HIDP_ERROR_CODES(0x8, 0x0001)
|
||||
#define HIDP_STATUS_INVALID_PREPARSED_DATA HIDP_ERROR_CODES(0xC, 0x0001)
|
||||
#define HIDP_STATUS_INVALID_REPORT_TYPE HIDP_ERROR_CODES(0xC, 0x0002)
|
||||
#define HIDP_STATUS_INVALID_REPORT_LENGTH HIDP_ERROR_CODES(0xC, 0x0003)
|
||||
#define HIDP_STATUS_USAGE_NOT_FOUND HIDP_ERROR_CODES(0xC, 0x0004)
|
||||
#define HIDP_STATUS_VALUE_OUT_OF_RANGE HIDP_ERROR_CODES(0xC, 0x0005)
|
||||
#define HIDP_STATUS_BAD_LOG_PHY_VALUES HIDP_ERROR_CODES(0xC, 0x0006)
|
||||
#define HIDP_STATUS_BUFFER_TOO_SMALL HIDP_ERROR_CODES(0xC, 0x0007)
|
||||
#define HIDP_STATUS_INTERNAL_ERROR HIDP_ERROR_CODES(0xC, 0x0008)
|
||||
#define HIDP_STATUS_I8042_TRANS_UNKNOWN HIDP_ERROR_CODES(0xC, 0x0009)
|
||||
#define HIDP_STATUS_INCOMPATIBLE_REPORT_ID HIDP_ERROR_CODES(0xC, 0x000A)
|
||||
#define HIDP_STATUS_NOT_VALUE_ARRAY HIDP_ERROR_CODES(0xC, 0x000B)
|
||||
#define HIDP_STATUS_IS_VALUE_ARRAY HIDP_ERROR_CODES(0xC, 0x000C)
|
||||
#define HIDP_STATUS_DATA_INDEX_NOT_FOUND HIDP_ERROR_CODES(0xC, 0x000D)
|
||||
#define HIDP_STATUS_DATA_INDEX_OUT_OF_RANGE HIDP_ERROR_CODES(0xC, 0x000E)
|
||||
#define HIDP_STATUS_BUTTON_NOT_PRESSED HIDP_ERROR_CODES(0xC, 0x000F)
|
||||
#define HIDP_STATUS_REPORT_DOES_NOT_EXIST HIDP_ERROR_CODES(0xC, 0x0010)
|
||||
#define HIDP_STATUS_NOT_IMPLEMENTED HIDP_ERROR_CODES(0xC, 0x0020)
|
||||
|
||||
extern bool WIN_LoadHIDDLL(void);
|
||||
extern void WIN_UnloadHIDDLL(void);
|
||||
|
||||
typedef BOOLEAN (WINAPI *HidD_GetAttributes_t)(HANDLE HidDeviceObject, PHIDD_ATTRIBUTES Attributes);
|
||||
typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
|
||||
typedef ULONG (WINAPI *HidP_MaxDataListLength_t)(HIDP_REPORT_TYPE ReportType, PHIDP_PREPARSED_DATA PreparsedData);
|
||||
typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DATA DataList, PULONG DataLength, PHIDP_PREPARSED_DATA PreparsedData, PCHAR Report, ULONG ReportLength);
|
||||
|
||||
extern HidD_GetAttributes_t SDL_HidD_GetAttributes;
|
||||
extern HidD_GetString_t SDL_HidD_GetManufacturerString;
|
||||
extern HidD_GetString_t SDL_HidD_GetProductString;
|
||||
extern HidP_GetCaps_t SDL_HidP_GetCaps;
|
||||
extern HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
|
||||
extern HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
|
||||
extern HidP_MaxDataListLength_t SDL_HidP_MaxDataListLength;
|
||||
extern HidP_GetData_t SDL_HidP_GetData;
|
||||
|
||||
void WIN_InitDeviceNotification(void);
|
||||
Uint64 WIN_GetLastDeviceNotification(void);
|
||||
void WIN_QuitDeviceNotification(void);
|
||||
|
||||
#endif // SDL_hid_h_
|
434
thirdparty/sdl/core/windows/SDL_immdevice.c
vendored
Normal file
434
thirdparty/sdl/core/windows/SDL_immdevice.c
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#if defined(SDL_PLATFORM_WINDOWS) && defined(HAVE_MMDEVICEAPI_H)
|
||||
|
||||
#include "SDL_windows.h"
|
||||
#include "SDL_immdevice.h"
|
||||
#include "../../audio/SDL_sysaudio.h"
|
||||
#include <objbase.h> // For CLSIDFromString
|
||||
|
||||
typedef struct SDL_IMMDevice_HandleData
|
||||
{
|
||||
LPWSTR immdevice_id;
|
||||
GUID directsound_guid;
|
||||
} SDL_IMMDevice_HandleData;
|
||||
|
||||
static const ERole SDL_IMMDevice_role = eConsole; // !!! FIXME: should this be eMultimedia? Should be a hint?
|
||||
|
||||
// This is global to the WASAPI target, to handle hotplug and default device lookup.
|
||||
static IMMDeviceEnumerator *enumerator = NULL;
|
||||
static SDL_IMMDevice_callbacks immcallbacks;
|
||||
|
||||
// PropVariantInit() is an inline function/macro in PropIdl.h that calls the C runtime's memset() directly. Use ours instead, to avoid dependency.
|
||||
#ifdef PropVariantInit
|
||||
#undef PropVariantInit
|
||||
#endif
|
||||
#define PropVariantInit(p) SDL_zerop(p)
|
||||
|
||||
// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
static const CLSID SDL_CLSID_MMDeviceEnumerator = { 0xbcde0395, 0xe52f, 0x467c,{ 0x8e, 0x3d, 0xc4, 0x57, 0x92, 0x91, 0x69, 0x2e } };
|
||||
static const IID SDL_IID_IMMDeviceEnumerator = { 0xa95664d2, 0x9614, 0x4f35,{ 0xa7, 0x46, 0xde, 0x8d, 0xb6, 0x36, 0x17, 0xe6 } };
|
||||
static const IID SDL_IID_IMMNotificationClient = { 0x7991eec9, 0x7e89, 0x4d85,{ 0x83, 0x90, 0x6c, 0x70, 0x3c, 0xec, 0x60, 0xc0 } };
|
||||
static const IID SDL_IID_IMMEndpoint = { 0x1be09788, 0x6894, 0x4089,{ 0x85, 0x86, 0x9a, 0x2a, 0x6c, 0x26, 0x5a, 0xc5 } };
|
||||
static const PROPERTYKEY SDL_PKEY_Device_FriendlyName = { { 0xa45c254e, 0xdf1c, 0x4efd,{ 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, } }, 14 };
|
||||
static const PROPERTYKEY SDL_PKEY_AudioEngine_DeviceFormat = { { 0xf19f064d, 0x82c, 0x4e27,{ 0xbc, 0x73, 0x68, 0x82, 0xa1, 0xbb, 0x8e, 0x4c, } }, 0 };
|
||||
static const PROPERTYKEY SDL_PKEY_AudioEndpoint_GUID = { { 0x1da5d803, 0xd492, 0x4edd,{ 0x8c, 0x23, 0xe0, 0xc0, 0xff, 0xee, 0x7f, 0x0e, } }, 4 };
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
static bool FindByDevIDCallback(SDL_AudioDevice *device, void *userdata)
|
||||
{
|
||||
LPCWSTR devid = (LPCWSTR)userdata;
|
||||
if (devid && device && device->handle) {
|
||||
const SDL_IMMDevice_HandleData *handle = (const SDL_IMMDevice_HandleData *)device->handle;
|
||||
if (handle->immdevice_id && SDL_wcscmp(handle->immdevice_id, devid) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *SDL_IMMDevice_FindByDevID(LPCWSTR devid)
|
||||
{
|
||||
return SDL_FindPhysicalAudioDeviceByCallback(FindByDevIDCallback, (void *) devid);
|
||||
}
|
||||
|
||||
LPGUID SDL_IMMDevice_GetDirectSoundGUID(SDL_AudioDevice *device)
|
||||
{
|
||||
return (device && device->handle) ? &(((SDL_IMMDevice_HandleData *) device->handle)->directsound_guid) : NULL;
|
||||
}
|
||||
|
||||
LPCWSTR SDL_IMMDevice_GetDevID(SDL_AudioDevice *device)
|
||||
{
|
||||
return (device && device->handle) ? ((const SDL_IMMDevice_HandleData *) device->handle)->immdevice_id : NULL;
|
||||
}
|
||||
|
||||
static void GetMMDeviceInfo(IMMDevice *device, char **utf8dev, WAVEFORMATEXTENSIBLE *fmt, GUID *guid)
|
||||
{
|
||||
/* PKEY_Device_FriendlyName gives you "Speakers (SoundBlaster Pro)" which drives me nuts. I'd rather it be
|
||||
"SoundBlaster Pro (Speakers)" but I guess that's developers vs users. Windows uses the FriendlyName in
|
||||
its own UIs, like Volume Control, etc. */
|
||||
IPropertyStore *props = NULL;
|
||||
*utf8dev = NULL;
|
||||
SDL_zerop(fmt);
|
||||
if (SUCCEEDED(IMMDevice_OpenPropertyStore(device, STGM_READ, &props))) {
|
||||
PROPVARIANT var;
|
||||
PropVariantInit(&var);
|
||||
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_Device_FriendlyName, &var))) {
|
||||
*utf8dev = WIN_StringToUTF8W(var.pwszVal);
|
||||
}
|
||||
PropVariantClear(&var);
|
||||
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_AudioEngine_DeviceFormat, &var))) {
|
||||
SDL_memcpy(fmt, var.blob.pBlobData, SDL_min(var.blob.cbSize, sizeof(WAVEFORMATEXTENSIBLE)));
|
||||
}
|
||||
PropVariantClear(&var);
|
||||
if (SUCCEEDED(IPropertyStore_GetValue(props, &SDL_PKEY_AudioEndpoint_GUID, &var))) {
|
||||
(void)CLSIDFromString(var.pwszVal, guid);
|
||||
}
|
||||
PropVariantClear(&var);
|
||||
IPropertyStore_Release(props);
|
||||
}
|
||||
}
|
||||
|
||||
void SDL_IMMDevice_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||
{
|
||||
if (device && device->handle) {
|
||||
SDL_IMMDevice_HandleData *handle = (SDL_IMMDevice_HandleData *) device->handle;
|
||||
SDL_free(handle->immdevice_id);
|
||||
SDL_free(handle);
|
||||
device->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static SDL_AudioDevice *SDL_IMMDevice_Add(const bool recording, const char *devname, WAVEFORMATEXTENSIBLE *fmt, LPCWSTR devid, GUID *dsoundguid)
|
||||
{
|
||||
/* You can have multiple endpoints on a device that are mutually exclusive ("Speakers" vs "Line Out" or whatever).
|
||||
In a perfect world, things that are unplugged won't be in this collection. The only gotcha is probably for
|
||||
phones and tablets, where you might have an internal speaker and a headphone jack and expect both to be
|
||||
available and switch automatically. (!!! FIXME...?) */
|
||||
|
||||
if (!devname) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// see if we already have this one first.
|
||||
SDL_AudioDevice *device = SDL_IMMDevice_FindByDevID(devid);
|
||||
if (device) {
|
||||
if (SDL_GetAtomicInt(&device->zombie)) {
|
||||
// whoa, it came back! This can happen if you unplug and replug USB headphones while we're still keeping the SDL object alive.
|
||||
// Kill this device's IMMDevice id; the device will go away when the app closes it, or maybe a new default device is chosen
|
||||
// (possibly this reconnected device), so we just want to make sure IMMDevice doesn't try to find the old device by the existing ID string.
|
||||
SDL_IMMDevice_HandleData *handle = (SDL_IMMDevice_HandleData *) device->handle;
|
||||
SDL_free(handle->immdevice_id);
|
||||
handle->immdevice_id = NULL;
|
||||
device = NULL; // add a new device, below.
|
||||
}
|
||||
}
|
||||
|
||||
if (!device) {
|
||||
// handle is freed by SDL_IMMDevice_FreeDeviceHandle!
|
||||
SDL_IMMDevice_HandleData *handle = (SDL_IMMDevice_HandleData *)SDL_malloc(sizeof(SDL_IMMDevice_HandleData));
|
||||
if (!handle) {
|
||||
return NULL;
|
||||
}
|
||||
handle->immdevice_id = SDL_wcsdup(devid);
|
||||
if (!handle->immdevice_id) {
|
||||
SDL_free(handle);
|
||||
return NULL;
|
||||
}
|
||||
SDL_memcpy(&handle->directsound_guid, dsoundguid, sizeof(GUID));
|
||||
|
||||
SDL_AudioSpec spec;
|
||||
SDL_zero(spec);
|
||||
spec.channels = (Uint8)fmt->Format.nChannels;
|
||||
spec.freq = fmt->Format.nSamplesPerSec;
|
||||
spec.format = SDL_WaveFormatExToSDLFormat((WAVEFORMATEX *)fmt);
|
||||
|
||||
device = SDL_AddAudioDevice(recording, devname, &spec, handle);
|
||||
if (!device) {
|
||||
SDL_free(handle->immdevice_id);
|
||||
SDL_free(handle);
|
||||
}
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
/* We need a COM subclass of IMMNotificationClient for hotplug support, which is
|
||||
easy in C++, but we have to tapdance more to make work in C.
|
||||
Thanks to this page for coaching on how to make this work:
|
||||
https://www.codeproject.com/Articles/13601/COM-in-plain-C */
|
||||
|
||||
typedef struct SDLMMNotificationClient
|
||||
{
|
||||
const IMMNotificationClientVtbl *lpVtbl;
|
||||
SDL_AtomicInt refcount;
|
||||
} SDLMMNotificationClient;
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_QueryInterface(IMMNotificationClient *client, REFIID iid, void **ppv)
|
||||
{
|
||||
if ((WIN_IsEqualIID(iid, &IID_IUnknown)) || (WIN_IsEqualIID(iid, &SDL_IID_IMMNotificationClient))) {
|
||||
*ppv = client;
|
||||
client->lpVtbl->AddRef(client);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*ppv = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE SDLMMNotificationClient_AddRef(IMMNotificationClient *iclient)
|
||||
{
|
||||
SDLMMNotificationClient *client = (SDLMMNotificationClient *)iclient;
|
||||
return (ULONG)(SDL_AtomicIncRef(&client->refcount) + 1);
|
||||
}
|
||||
|
||||
static ULONG STDMETHODCALLTYPE SDLMMNotificationClient_Release(IMMNotificationClient *iclient)
|
||||
{
|
||||
// client is a static object; we don't ever free it.
|
||||
SDLMMNotificationClient *client = (SDLMMNotificationClient *)iclient;
|
||||
const ULONG rc = SDL_AtomicDecRef(&client->refcount);
|
||||
if (rc == 0) {
|
||||
SDL_SetAtomicInt(&client->refcount, 0); // uhh...
|
||||
return 0;
|
||||
}
|
||||
return rc - 1;
|
||||
}
|
||||
|
||||
// These are the entry points called when WASAPI device endpoints change.
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDefaultDeviceChanged(IMMNotificationClient *iclient, EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
if (role == SDL_IMMDevice_role) {
|
||||
immcallbacks.default_audio_device_changed(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceAdded(IMMNotificationClient *iclient, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
/* we ignore this; devices added here then progress to ACTIVE, if appropriate, in
|
||||
OnDeviceStateChange, making that a better place to deal with device adds. More
|
||||
importantly: the first time you plug in a USB audio device, this callback will
|
||||
fire, but when you unplug it, it isn't removed (it's state changes to NOTPRESENT).
|
||||
Plugging it back in won't fire this callback again. */
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceRemoved(IMMNotificationClient *iclient, LPCWSTR pwstrDeviceId)
|
||||
{
|
||||
return S_OK; // See notes in OnDeviceAdded handler about why we ignore this.
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnDeviceStateChanged(IMMNotificationClient *iclient, LPCWSTR pwstrDeviceId, DWORD dwNewState)
|
||||
{
|
||||
IMMDevice *device = NULL;
|
||||
|
||||
if (SUCCEEDED(IMMDeviceEnumerator_GetDevice(enumerator, pwstrDeviceId, &device))) {
|
||||
IMMEndpoint *endpoint = NULL;
|
||||
if (SUCCEEDED(IMMDevice_QueryInterface(device, &SDL_IID_IMMEndpoint, (void **)&endpoint))) {
|
||||
EDataFlow flow;
|
||||
if (SUCCEEDED(IMMEndpoint_GetDataFlow(endpoint, &flow))) {
|
||||
const bool recording = (flow == eCapture);
|
||||
if (dwNewState == DEVICE_STATE_ACTIVE) {
|
||||
char *utf8dev;
|
||||
WAVEFORMATEXTENSIBLE fmt;
|
||||
GUID dsoundguid;
|
||||
GetMMDeviceInfo(device, &utf8dev, &fmt, &dsoundguid);
|
||||
if (utf8dev) {
|
||||
SDL_IMMDevice_Add(recording, utf8dev, &fmt, pwstrDeviceId, &dsoundguid);
|
||||
SDL_free(utf8dev);
|
||||
}
|
||||
} else {
|
||||
immcallbacks.audio_device_disconnected(SDL_IMMDevice_FindByDevID(pwstrDeviceId));
|
||||
}
|
||||
}
|
||||
IMMEndpoint_Release(endpoint);
|
||||
}
|
||||
IMMDevice_Release(device);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE SDLMMNotificationClient_OnPropertyValueChanged(IMMNotificationClient *client, LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
|
||||
{
|
||||
return S_OK; // we don't care about these.
|
||||
}
|
||||
|
||||
static const IMMNotificationClientVtbl notification_client_vtbl = {
|
||||
SDLMMNotificationClient_QueryInterface,
|
||||
SDLMMNotificationClient_AddRef,
|
||||
SDLMMNotificationClient_Release,
|
||||
SDLMMNotificationClient_OnDeviceStateChanged,
|
||||
SDLMMNotificationClient_OnDeviceAdded,
|
||||
SDLMMNotificationClient_OnDeviceRemoved,
|
||||
SDLMMNotificationClient_OnDefaultDeviceChanged,
|
||||
SDLMMNotificationClient_OnPropertyValueChanged
|
||||
};
|
||||
|
||||
static SDLMMNotificationClient notification_client = { ¬ification_client_vtbl, { 1 } };
|
||||
|
||||
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks)
|
||||
{
|
||||
HRESULT ret;
|
||||
|
||||
// just skip the discussion with COM here.
|
||||
if (!WIN_IsWindowsVistaOrGreater()) {
|
||||
return SDL_SetError("IMMDevice support requires Windows Vista or later");
|
||||
}
|
||||
|
||||
if (FAILED(WIN_CoInitialize())) {
|
||||
return SDL_SetError("IMMDevice: CoInitialize() failed");
|
||||
}
|
||||
|
||||
ret = CoCreateInstance(&SDL_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &SDL_IID_IMMDeviceEnumerator, (LPVOID *)&enumerator);
|
||||
if (FAILED(ret)) {
|
||||
WIN_CoUninitialize();
|
||||
return WIN_SetErrorFromHRESULT("IMMDevice CoCreateInstance(MMDeviceEnumerator)", ret);
|
||||
}
|
||||
|
||||
if (callbacks) {
|
||||
SDL_copyp(&immcallbacks, callbacks);
|
||||
} else {
|
||||
SDL_zero(immcallbacks);
|
||||
}
|
||||
|
||||
if (!immcallbacks.audio_device_disconnected) {
|
||||
immcallbacks.audio_device_disconnected = SDL_AudioDeviceDisconnected;
|
||||
}
|
||||
if (!immcallbacks.default_audio_device_changed) {
|
||||
immcallbacks.default_audio_device_changed = SDL_DefaultAudioDeviceChanged;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDL_IMMDevice_Quit(void)
|
||||
{
|
||||
if (enumerator) {
|
||||
IMMDeviceEnumerator_UnregisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)¬ification_client);
|
||||
IMMDeviceEnumerator_Release(enumerator);
|
||||
enumerator = NULL;
|
||||
}
|
||||
|
||||
SDL_zero(immcallbacks);
|
||||
|
||||
WIN_CoUninitialize();
|
||||
}
|
||||
|
||||
bool SDL_IMMDevice_Get(SDL_AudioDevice *device, IMMDevice **immdevice, bool recording)
|
||||
{
|
||||
const Uint64 timeout = SDL_GetTicks() + 8000; // intel's audio drivers can fail for up to EIGHT SECONDS after a device is connected or we wake from sleep.
|
||||
|
||||
SDL_assert(device != NULL);
|
||||
SDL_assert(immdevice != NULL);
|
||||
|
||||
LPCWSTR devid = SDL_IMMDevice_GetDevID(device);
|
||||
SDL_assert(devid != NULL);
|
||||
|
||||
HRESULT ret;
|
||||
while ((ret = IMMDeviceEnumerator_GetDevice(enumerator, devid, immdevice)) == E_NOTFOUND) {
|
||||
const Uint64 now = SDL_GetTicks();
|
||||
if (timeout > now) {
|
||||
const Uint64 ticksleft = timeout - now;
|
||||
SDL_Delay((Uint32)SDL_min(ticksleft, 300)); // wait awhile and try again.
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(ret)) {
|
||||
return WIN_SetErrorFromHRESULT("WASAPI can't find requested audio endpoint", ret);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void EnumerateEndpointsForFlow(const bool recording, SDL_AudioDevice **default_device)
|
||||
{
|
||||
/* Note that WASAPI separates "adapter devices" from "audio endpoint devices"
|
||||
...one adapter device ("SoundBlaster Pro") might have multiple endpoint devices ("Speakers", "Line-Out"). */
|
||||
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
if (FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(enumerator, recording ? eCapture : eRender, DEVICE_STATE_ACTIVE, &collection))) {
|
||||
return;
|
||||
}
|
||||
|
||||
UINT total = 0;
|
||||
if (FAILED(IMMDeviceCollection_GetCount(collection, &total))) {
|
||||
IMMDeviceCollection_Release(collection);
|
||||
return;
|
||||
}
|
||||
|
||||
LPWSTR default_devid = NULL;
|
||||
if (default_device) {
|
||||
IMMDevice *default_immdevice = NULL;
|
||||
const EDataFlow dataflow = recording ? eCapture : eRender;
|
||||
if (SUCCEEDED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(enumerator, dataflow, SDL_IMMDevice_role, &default_immdevice))) {
|
||||
LPWSTR devid = NULL;
|
||||
if (SUCCEEDED(IMMDevice_GetId(default_immdevice, &devid))) {
|
||||
default_devid = SDL_wcsdup(devid); // if this fails, oh well.
|
||||
CoTaskMemFree(devid);
|
||||
}
|
||||
IMMDevice_Release(default_immdevice);
|
||||
}
|
||||
}
|
||||
|
||||
for (UINT i = 0; i < total; i++) {
|
||||
IMMDevice *immdevice = NULL;
|
||||
if (SUCCEEDED(IMMDeviceCollection_Item(collection, i, &immdevice))) {
|
||||
LPWSTR devid = NULL;
|
||||
if (SUCCEEDED(IMMDevice_GetId(immdevice, &devid))) {
|
||||
char *devname = NULL;
|
||||
WAVEFORMATEXTENSIBLE fmt;
|
||||
GUID dsoundguid;
|
||||
SDL_zero(fmt);
|
||||
SDL_zero(dsoundguid);
|
||||
GetMMDeviceInfo(immdevice, &devname, &fmt, &dsoundguid);
|
||||
if (devname) {
|
||||
SDL_AudioDevice *sdldevice = SDL_IMMDevice_Add(recording, devname, &fmt, devid, &dsoundguid);
|
||||
if (default_device && default_devid && SDL_wcscmp(default_devid, devid) == 0) {
|
||||
*default_device = sdldevice;
|
||||
}
|
||||
SDL_free(devname);
|
||||
}
|
||||
CoTaskMemFree(devid);
|
||||
}
|
||||
IMMDevice_Release(immdevice);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_free(default_devid);
|
||||
|
||||
IMMDeviceCollection_Release(collection);
|
||||
}
|
||||
|
||||
void SDL_IMMDevice_EnumerateEndpoints(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
|
||||
{
|
||||
EnumerateEndpointsForFlow(false, default_playback);
|
||||
EnumerateEndpointsForFlow(true, default_recording);
|
||||
|
||||
// if this fails, we just won't get hotplug events. Carry on anyhow.
|
||||
IMMDeviceEnumerator_RegisterEndpointNotificationCallback(enumerator, (IMMNotificationClient *)¬ification_client);
|
||||
}
|
||||
|
||||
#endif // defined(SDL_PLATFORM_WINDOWS) && defined(HAVE_MMDEVICEAPI_H)
|
45
thirdparty/sdl/core/windows/SDL_immdevice.h
vendored
Normal file
45
thirdparty/sdl/core/windows/SDL_immdevice.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_IMMDEVICE_H
|
||||
#define SDL_IMMDEVICE_H
|
||||
|
||||
#define COBJMACROS
|
||||
#include <mmdeviceapi.h>
|
||||
#include <mmreg.h>
|
||||
|
||||
struct SDL_AudioDevice; // defined in src/audio/SDL_sysaudio.h
|
||||
|
||||
typedef struct SDL_IMMDevice_callbacks
|
||||
{
|
||||
void (*audio_device_disconnected)(struct SDL_AudioDevice *device);
|
||||
void (*default_audio_device_changed)(struct SDL_AudioDevice *new_default_device);
|
||||
} SDL_IMMDevice_callbacks;
|
||||
|
||||
bool SDL_IMMDevice_Init(const SDL_IMMDevice_callbacks *callbacks);
|
||||
void SDL_IMMDevice_Quit(void);
|
||||
bool SDL_IMMDevice_Get(struct SDL_AudioDevice *device, IMMDevice **immdevice, bool recording);
|
||||
void SDL_IMMDevice_EnumerateEndpoints(struct SDL_AudioDevice **default_playback, struct SDL_AudioDevice **default_recording);
|
||||
LPGUID SDL_IMMDevice_GetDirectSoundGUID(struct SDL_AudioDevice *device);
|
||||
LPCWSTR SDL_IMMDevice_GetDevID(struct SDL_AudioDevice *device);
|
||||
void SDL_IMMDevice_FreeDeviceHandle(struct SDL_AudioDevice *device);
|
||||
|
||||
#endif // SDL_IMMDEVICE_H
|
375
thirdparty/sdl/core/windows/SDL_windows.c
vendored
Normal file
375
thirdparty/sdl/core/windows/SDL_windows.c
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
|
||||
#include "SDL_windows.h"
|
||||
|
||||
#include <objbase.h> // for CoInitialize/CoUninitialize (Win32 only)
|
||||
#ifdef HAVE_ROAPI_H
|
||||
#include <roapi.h> // For RoInitialize/RoUninitialize (Win32 only)
|
||||
#else
|
||||
typedef enum RO_INIT_TYPE
|
||||
{
|
||||
RO_INIT_SINGLETHREADED = 0,
|
||||
RO_INIT_MULTITHREADED = 1
|
||||
} RO_INIT_TYPE;
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_WINNT_VISTA
|
||||
#define _WIN32_WINNT_VISTA 0x0600
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT_WIN7
|
||||
#define _WIN32_WINNT_WIN7 0x0601
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT_WIN8
|
||||
#define _WIN32_WINNT_WIN8 0x0602
|
||||
#endif
|
||||
|
||||
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
|
||||
#endif
|
||||
|
||||
#ifndef WC_ERR_INVALID_CHARS
|
||||
#define WC_ERR_INVALID_CHARS 0x00000080
|
||||
#endif
|
||||
|
||||
// Sets an error message based on an HRESULT
|
||||
bool WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
|
||||
{
|
||||
TCHAR buffer[1024];
|
||||
char *message;
|
||||
TCHAR *p = buffer;
|
||||
DWORD c = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0,
|
||||
buffer, SDL_arraysize(buffer), NULL);
|
||||
buffer[c] = 0;
|
||||
// kill CR/LF that FormatMessage() sticks at the end
|
||||
while (*p) {
|
||||
if (*p == '\r') {
|
||||
*p = 0;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
message = WIN_StringToUTF8(buffer);
|
||||
SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message);
|
||||
SDL_free(message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sets an error message based on GetLastError()
|
||||
bool WIN_SetError(const char *prefix)
|
||||
{
|
||||
return WIN_SetErrorFromHRESULT(prefix, GetLastError());
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WIN_CoInitialize(void)
|
||||
{
|
||||
/* SDL handles any threading model, so initialize with the default, which
|
||||
is compatible with OLE and if that doesn't work, try multi-threaded mode.
|
||||
|
||||
If you need multi-threaded mode, call CoInitializeEx() before SDL_Init()
|
||||
*/
|
||||
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
// On Xbox, there's no need to call CoInitializeEx (and it's not implemented)
|
||||
return S_OK;
|
||||
#else
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
if (hr == RPC_E_CHANGED_MODE) {
|
||||
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
// S_FALSE means success, but someone else already initialized.
|
||||
// You still need to call CoUninitialize in this case!
|
||||
if (hr == S_FALSE) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return hr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void WIN_CoUninitialize(void)
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
FARPROC WIN_LoadComBaseFunction(const char *name)
|
||||
{
|
||||
static bool s_bLoaded;
|
||||
static HMODULE s_hComBase;
|
||||
|
||||
if (!s_bLoaded) {
|
||||
s_hComBase = LoadLibraryEx(TEXT("combase.dll"), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
s_bLoaded = true;
|
||||
}
|
||||
if (s_hComBase) {
|
||||
return GetProcAddress(s_hComBase, name);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT
|
||||
WIN_RoInitialize(void)
|
||||
{
|
||||
typedef HRESULT(WINAPI * RoInitialize_t)(RO_INIT_TYPE initType);
|
||||
RoInitialize_t RoInitializeFunc = (RoInitialize_t)WIN_LoadComBaseFunction("RoInitialize");
|
||||
if (RoInitializeFunc) {
|
||||
// RO_INIT_SINGLETHREADED is equivalent to COINIT_APARTMENTTHREADED
|
||||
HRESULT hr = RoInitializeFunc(RO_INIT_SINGLETHREADED);
|
||||
if (hr == RPC_E_CHANGED_MODE) {
|
||||
hr = RoInitializeFunc(RO_INIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
// S_FALSE means success, but someone else already initialized.
|
||||
// You still need to call RoUninitialize in this case!
|
||||
if (hr == S_FALSE) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return hr;
|
||||
} else {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
void WIN_RoUninitialize(void)
|
||||
{
|
||||
typedef void(WINAPI * RoUninitialize_t)(void);
|
||||
RoUninitialize_t RoUninitializeFunc = (RoUninitialize_t)WIN_LoadComBaseFunction("RoUninitialize");
|
||||
if (RoUninitializeFunc) {
|
||||
RoUninitializeFunc();
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||
static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
|
||||
{
|
||||
OSVERSIONINFOEXW osvi;
|
||||
DWORDLONG const dwlConditionMask = VerSetConditionMask(
|
||||
VerSetConditionMask(
|
||||
VerSetConditionMask(
|
||||
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
|
||||
VER_MINORVERSION, VER_GREATER_EQUAL),
|
||||
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
|
||||
|
||||
SDL_zero(osvi);
|
||||
osvi.dwOSVersionInfoSize = sizeof(osvi);
|
||||
osvi.dwMajorVersion = wMajorVersion;
|
||||
osvi.dwMinorVersion = wMinorVersion;
|
||||
osvi.wServicePackMajor = wServicePackMajor;
|
||||
|
||||
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
// apply some static variables so we only call into the Win32 API once per process for each check.
|
||||
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
#define CHECKWINVER(notdesktop_platform_result, test) return (notdesktop_platform_result);
|
||||
#else
|
||||
#define CHECKWINVER(notdesktop_platform_result, test) \
|
||||
static bool checked = false; \
|
||||
static BOOL result = FALSE; \
|
||||
if (!checked) { \
|
||||
result = (test); \
|
||||
checked = true; \
|
||||
} \
|
||||
return result;
|
||||
#endif
|
||||
|
||||
// this is the oldest thing we run on (and we may lose support for this in SDL3 at any time!),
|
||||
// so there's no "OrGreater" as that would always be TRUE. The other functions are here to
|
||||
// ask "can we support a specific feature?" but this function is here to ask "do we need to do
|
||||
// something different for an OS version we probably should abandon?" :)
|
||||
BOOL WIN_IsWindowsXP(void)
|
||||
{
|
||||
CHECKWINVER(FALSE, !WIN_IsWindowsVistaOrGreater() && IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0));
|
||||
}
|
||||
|
||||
BOOL WIN_IsWindowsVistaOrGreater(void)
|
||||
{
|
||||
CHECKWINVER(TRUE, IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0));
|
||||
}
|
||||
|
||||
BOOL WIN_IsWindows7OrGreater(void)
|
||||
{
|
||||
CHECKWINVER(TRUE, IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0));
|
||||
}
|
||||
|
||||
BOOL WIN_IsWindows8OrGreater(void)
|
||||
{
|
||||
CHECKWINVER(TRUE, IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0));
|
||||
}
|
||||
|
||||
#undef CHECKWINVER
|
||||
|
||||
|
||||
/*
|
||||
WAVExxxCAPS gives you 31 bytes for the device name, and just truncates if it's
|
||||
longer. However, since WinXP, you can use the WAVExxxCAPS2 structure, which
|
||||
will give you a name GUID. The full name is in the Windows Registry under
|
||||
that GUID, located here: HKLM\System\CurrentControlSet\Control\MediaCategories
|
||||
|
||||
Note that drivers can report GUID_NULL for the name GUID, in which case,
|
||||
Windows makes a best effort to fill in those 31 bytes in the usual place.
|
||||
This info summarized from MSDN:
|
||||
|
||||
http://web.archive.org/web/20131027093034/http://msdn.microsoft.com/en-us/library/windows/hardware/ff536382(v=vs.85).aspx
|
||||
|
||||
Always look this up in the registry if possible, because the strings are
|
||||
different! At least on Win10, I see "Yeti Stereo Microphone" in the
|
||||
Registry, and a unhelpful "Microphone(Yeti Stereo Microph" in winmm. Sigh.
|
||||
|
||||
(Also, DirectSound shouldn't be limited to 32 chars, but its device enum
|
||||
has the same problem.)
|
||||
|
||||
WASAPI doesn't need this. This is just for DirectSound/WinMM.
|
||||
*/
|
||||
char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid)
|
||||
{
|
||||
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
return WIN_StringToUTF8W(name); // No registry access on Xbox, go with what we've got.
|
||||
#else
|
||||
static const GUID nullguid = { 0 };
|
||||
const unsigned char *ptr;
|
||||
char keystr[128];
|
||||
WCHAR *strw = NULL;
|
||||
bool rc;
|
||||
HKEY hkey;
|
||||
DWORD len = 0;
|
||||
char *result = NULL;
|
||||
|
||||
if (WIN_IsEqualGUID(guid, &nullguid)) {
|
||||
return WIN_StringToUTF8(name); // No GUID, go with what we've got.
|
||||
}
|
||||
|
||||
ptr = (const unsigned char *)guid;
|
||||
(void)SDL_snprintf(keystr, sizeof(keystr),
|
||||
"System\\CurrentControlSet\\Control\\MediaCategories\\{%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
||||
ptr[3], ptr[2], ptr[1], ptr[0], ptr[5], ptr[4], ptr[7], ptr[6],
|
||||
ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15]);
|
||||
|
||||
strw = WIN_UTF8ToString(keystr);
|
||||
rc = (RegOpenKeyExW(HKEY_LOCAL_MACHINE, strw, 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS);
|
||||
SDL_free(strw);
|
||||
if (!rc) {
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
}
|
||||
|
||||
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, NULL, &len) == ERROR_SUCCESS);
|
||||
if (!rc) {
|
||||
RegCloseKey(hkey);
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
}
|
||||
|
||||
strw = (WCHAR *)SDL_malloc(len + sizeof(WCHAR));
|
||||
if (!strw) {
|
||||
RegCloseKey(hkey);
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
}
|
||||
|
||||
rc = (RegQueryValueExW(hkey, L"Name", NULL, NULL, (LPBYTE)strw, &len) == ERROR_SUCCESS);
|
||||
RegCloseKey(hkey);
|
||||
if (!rc) {
|
||||
SDL_free(strw);
|
||||
return WIN_StringToUTF8(name); // oh well.
|
||||
}
|
||||
|
||||
strw[len / 2] = 0; // make sure it's null-terminated.
|
||||
|
||||
result = WIN_StringToUTF8(strw);
|
||||
SDL_free(strw);
|
||||
return result ? result : WIN_StringToUTF8(name);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL WIN_IsEqualGUID(const GUID *a, const GUID *b)
|
||||
{
|
||||
return (SDL_memcmp(a, b, sizeof(*a)) == 0);
|
||||
}
|
||||
|
||||
BOOL WIN_IsEqualIID(REFIID a, REFIID b)
|
||||
{
|
||||
return (SDL_memcmp(a, b, sizeof(*a)) == 0);
|
||||
}
|
||||
|
||||
void WIN_RECTToRect(const RECT *winrect, SDL_Rect *sdlrect)
|
||||
{
|
||||
sdlrect->x = winrect->left;
|
||||
sdlrect->w = (winrect->right - winrect->left) + 1;
|
||||
sdlrect->y = winrect->top;
|
||||
sdlrect->h = (winrect->bottom - winrect->top) + 1;
|
||||
}
|
||||
|
||||
void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect)
|
||||
{
|
||||
winrect->left = sdlrect->x;
|
||||
winrect->right = sdlrect->x + sdlrect->w - 1;
|
||||
winrect->top = sdlrect->y;
|
||||
winrect->bottom = sdlrect->y + sdlrect->h - 1;
|
||||
}
|
||||
|
||||
bool WIN_WindowRectValid(const RECT *rect)
|
||||
{
|
||||
// A window can be resized to zero height, but not zero width
|
||||
return (rect->right > 0);
|
||||
}
|
||||
|
||||
// Some GUIDs we need to know without linking to libraries that aren't available before Vista.
|
||||
/* *INDENT-OFF* */ // clang-format off
|
||||
static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
|
||||
static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010,{ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } };
|
||||
/* *INDENT-ON* */ // clang-format on
|
||||
|
||||
SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat)
|
||||
{
|
||||
if ((waveformat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_F32;
|
||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 16)) {
|
||||
return SDL_AUDIO_S16;
|
||||
} else if ((waveformat->wFormatTag == WAVE_FORMAT_PCM) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_S32;
|
||||
} else if (waveformat->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
||||
const WAVEFORMATEXTENSIBLE *ext = (const WAVEFORMATEXTENSIBLE *)waveformat;
|
||||
if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_F32;
|
||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 16)) {
|
||||
return SDL_AUDIO_S16;
|
||||
} else if ((SDL_memcmp(&ext->SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)) == 0) && (waveformat->wBitsPerSample == 32)) {
|
||||
return SDL_AUDIO_S32;
|
||||
}
|
||||
}
|
||||
return SDL_AUDIO_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar)
|
||||
{
|
||||
if (WIN_IsWindowsXP()) {
|
||||
dwFlags &= ~WC_ERR_INVALID_CHARS; // not supported before Vista. Without this flag, it will just replace bogus chars with U+FFFD. You're on your own, WinXP.
|
||||
}
|
||||
return WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
|
||||
}
|
||||
|
||||
#endif // defined(SDL_PLATFORM_WINDOWS)
|
172
thirdparty/sdl/core/windows/SDL_windows.h
vendored
Normal file
172
thirdparty/sdl/core/windows/SDL_windows.h
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// This is an include file for windows.h with the SDL build settings
|
||||
|
||||
#ifndef _INCLUDED_WINDOWS_H
|
||||
#define _INCLUDED_WINDOWS_H
|
||||
|
||||
#ifdef SDL_PLATFORM_WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#ifndef STRICT
|
||||
#define STRICT 1
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE 1
|
||||
#endif
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#if defined(SDL_VIDEO_RENDER_D3D12) || defined(HAVE_DXGI1_6_H)
|
||||
#define _WIN32_WINNT 0xA00 // For D3D12, 0xA00 is required
|
||||
#elif defined(HAVE_SHELLSCALINGAPI_H)
|
||||
#define _WIN32_WINNT 0x603 // For DPI support
|
||||
#else
|
||||
#define _WIN32_WINNT 0x501 // Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input
|
||||
#endif
|
||||
#define WINVER _WIN32_WINNT
|
||||
|
||||
#elif defined(SDL_PLATFORM_WINGDK)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#ifndef STRICT
|
||||
#define STRICT 1
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE 1
|
||||
#endif
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0xA00
|
||||
#define WINVER _WIN32_WINNT
|
||||
|
||||
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#endif
|
||||
#ifndef STRICT
|
||||
#define STRICT 1
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE 1
|
||||
#endif
|
||||
#undef WINVER
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0xA00
|
||||
#define WINVER _WIN32_WINNT
|
||||
#endif
|
||||
|
||||
// See https://github.com/libsdl-org/SDL/pull/7607
|
||||
// force_align_arg_pointer attribute requires gcc >= 4.2.x.
|
||||
#if defined(__clang__)
|
||||
#define HAVE_FORCE_ALIGN_ARG_POINTER
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2))
|
||||
#define HAVE_FORCE_ALIGN_ARG_POINTER
|
||||
#endif
|
||||
#if defined(__GNUC__) && defined(__i386__) && defined(HAVE_FORCE_ALIGN_ARG_POINTER)
|
||||
#define MINGW32_FORCEALIGN __attribute__((force_align_arg_pointer))
|
||||
#else
|
||||
#define MINGW32_FORCEALIGN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <basetyps.h> // for REFIID with broken mingw.org headers
|
||||
#include <mmreg.h>
|
||||
|
||||
// Routines to convert from UTF8 to native Windows text
|
||||
#define WIN_StringToUTF8W(S) SDL_iconv_string("UTF-8", "UTF-16LE", (const char *)(S), (SDL_wcslen(S) + 1) * sizeof(WCHAR))
|
||||
#define WIN_UTF8ToStringW(S) (WCHAR *)SDL_iconv_string("UTF-16LE", "UTF-8", (const char *)(S), SDL_strlen(S) + 1)
|
||||
// !!! FIXME: UTF8ToString() can just be a SDL_strdup() here.
|
||||
#define WIN_StringToUTF8A(S) SDL_iconv_string("UTF-8", "ASCII", (const char *)(S), (SDL_strlen(S) + 1))
|
||||
#define WIN_UTF8ToStringA(S) SDL_iconv_string("ASCII", "UTF-8", (const char *)(S), SDL_strlen(S) + 1)
|
||||
#if UNICODE
|
||||
#define WIN_StringToUTF8 WIN_StringToUTF8W
|
||||
#define WIN_UTF8ToString WIN_UTF8ToStringW
|
||||
#define SDL_tcslen SDL_wcslen
|
||||
#define SDL_tcsstr SDL_wcsstr
|
||||
#else
|
||||
#define WIN_StringToUTF8 WIN_StringToUTF8A
|
||||
#define WIN_UTF8ToString WIN_UTF8ToStringA
|
||||
#define SDL_tcslen SDL_strlen
|
||||
#define SDL_tcsstr SDL_strstr
|
||||
#endif
|
||||
|
||||
// Set up for C function definitions, even when using C++
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Sets an error message based on a given HRESULT
|
||||
extern bool WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
|
||||
|
||||
// Sets an error message based on GetLastError(). Always returns false.
|
||||
extern bool WIN_SetError(const char *prefix);
|
||||
|
||||
// Load a function from combase.dll
|
||||
FARPROC WIN_LoadComBaseFunction(const char *name);
|
||||
|
||||
// Wrap up the oddities of CoInitialize() into a common function.
|
||||
extern HRESULT WIN_CoInitialize(void);
|
||||
extern void WIN_CoUninitialize(void);
|
||||
|
||||
// Wrap up the oddities of RoInitialize() into a common function.
|
||||
extern HRESULT WIN_RoInitialize(void);
|
||||
extern void WIN_RoUninitialize(void);
|
||||
|
||||
// Returns true if we're running on Windows XP (any service pack). DOES NOT CHECK XP "OR GREATER"!
|
||||
extern BOOL WIN_IsWindowsXP(void);
|
||||
|
||||
// Returns true if we're running on Windows Vista and newer
|
||||
extern BOOL WIN_IsWindowsVistaOrGreater(void);
|
||||
|
||||
// Returns true if we're running on Windows 7 and newer
|
||||
extern BOOL WIN_IsWindows7OrGreater(void);
|
||||
|
||||
// Returns true if we're running on Windows 8 and newer
|
||||
extern BOOL WIN_IsWindows8OrGreater(void);
|
||||
|
||||
// You need to SDL_free() the result of this call.
|
||||
extern char *WIN_LookupAudioDeviceName(const WCHAR *name, const GUID *guid);
|
||||
|
||||
// Checks to see if two GUID are the same.
|
||||
extern BOOL WIN_IsEqualGUID(const GUID *a, const GUID *b);
|
||||
extern BOOL WIN_IsEqualIID(REFIID a, REFIID b);
|
||||
|
||||
// Convert between SDL_rect and RECT
|
||||
extern void WIN_RECTToRect(const RECT *winrect, SDL_Rect *sdlrect);
|
||||
extern void WIN_RectToRECT(const SDL_Rect *sdlrect, RECT *winrect);
|
||||
|
||||
// Returns false if a window client rect is not valid
|
||||
bool WIN_WindowRectValid(const RECT *rect);
|
||||
|
||||
extern SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat);
|
||||
|
||||
// WideCharToMultiByte, but with some WinXP management.
|
||||
extern int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
|
||||
|
||||
// Ends C function definitions when using C++
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _INCLUDED_WINDOWS_H
|
140
thirdparty/sdl/core/windows/SDL_xinput.c
vendored
Normal file
140
thirdparty/sdl/core/windows/SDL_xinput.c
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#include "SDL_xinput.h"
|
||||
|
||||
// Set up for C function definitions, even when using C++
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
XInputGetState_t SDL_XInputGetState = NULL;
|
||||
XInputSetState_t SDL_XInputSetState = NULL;
|
||||
XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL;
|
||||
XInputGetCapabilitiesEx_t SDL_XInputGetCapabilitiesEx = NULL;
|
||||
XInputGetBatteryInformation_t SDL_XInputGetBatteryInformation = NULL;
|
||||
DWORD SDL_XInputVersion = 0;
|
||||
|
||||
static HMODULE s_pXInputDLL = NULL;
|
||||
static int s_XInputDLLRefCount = 0;
|
||||
|
||||
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
bool WIN_LoadXInputDLL(void)
|
||||
{
|
||||
/* Getting handles to system dlls (via LoadLibrary and its variants) is not
|
||||
* supported on Xbox, thus, pointers to XInput's functions can't be
|
||||
* retrieved via GetProcAddress.
|
||||
*
|
||||
* When on Xbox, assume that XInput is already loaded, and directly map
|
||||
* its XInput.h-declared functions to the SDL_XInput* set of function
|
||||
* pointers.
|
||||
*/
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WIN_UnloadXInputDLL(void)
|
||||
{
|
||||
}
|
||||
|
||||
#else // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
|
||||
|
||||
bool WIN_LoadXInputDLL(void)
|
||||
{
|
||||
DWORD version = 0;
|
||||
|
||||
if (s_pXInputDLL) {
|
||||
SDL_assert(s_XInputDLLRefCount > 0);
|
||||
s_XInputDLLRefCount++;
|
||||
return true; // already loaded
|
||||
}
|
||||
|
||||
/* NOTE: Don't load XinputUap.dll
|
||||
* This is XInput emulation over Windows.Gaming.Input, and has all the
|
||||
* limitations of that API (no devices at startup, no background input, etc.)
|
||||
*/
|
||||
version = (1 << 16) | 4;
|
||||
s_pXInputDLL = LoadLibrary(TEXT("XInput1_4.dll")); // 1.4 Ships with Windows 8.
|
||||
if (!s_pXInputDLL) {
|
||||
version = (1 << 16) | 3;
|
||||
s_pXInputDLL = LoadLibrary(TEXT("XInput1_3.dll")); // 1.3 can be installed as a redistributable component.
|
||||
}
|
||||
if (!s_pXInputDLL) {
|
||||
s_pXInputDLL = LoadLibrary(TEXT("bin\\XInput1_3.dll"));
|
||||
}
|
||||
if (!s_pXInputDLL) {
|
||||
// "9.1.0" Ships with Vista and Win7, and is more limited than 1.3+ (e.g. XInputGetStateEx is not available.)
|
||||
s_pXInputDLL = LoadLibrary(TEXT("XInput9_1_0.dll"));
|
||||
}
|
||||
if (!s_pXInputDLL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_assert(s_XInputDLLRefCount == 0);
|
||||
SDL_XInputVersion = version;
|
||||
s_XInputDLLRefCount = 1;
|
||||
|
||||
// 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think...
|
||||
SDL_XInputGetState = (XInputGetState_t)GetProcAddress(s_pXInputDLL, (LPCSTR)100);
|
||||
if (!SDL_XInputGetState) {
|
||||
SDL_XInputGetState = (XInputGetState_t)GetProcAddress(s_pXInputDLL, "XInputGetState");
|
||||
}
|
||||
SDL_XInputSetState = (XInputSetState_t)GetProcAddress(s_pXInputDLL, "XInputSetState");
|
||||
SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress(s_pXInputDLL, "XInputGetCapabilities");
|
||||
// 108 is the ordinal for _XInputGetCapabilitiesEx, which additionally returns VID/PID of the controller.
|
||||
SDL_XInputGetCapabilitiesEx = (XInputGetCapabilitiesEx_t)GetProcAddress(s_pXInputDLL, (LPCSTR)108);
|
||||
SDL_XInputGetBatteryInformation = (XInputGetBatteryInformation_t)GetProcAddress(s_pXInputDLL, "XInputGetBatteryInformation");
|
||||
if (!SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities) {
|
||||
WIN_UnloadXInputDLL();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WIN_UnloadXInputDLL(void)
|
||||
{
|
||||
if (s_pXInputDLL) {
|
||||
SDL_assert(s_XInputDLLRefCount > 0);
|
||||
if (--s_XInputDLLRefCount == 0) {
|
||||
FreeLibrary(s_pXInputDLL);
|
||||
s_pXInputDLL = NULL;
|
||||
}
|
||||
} else {
|
||||
SDL_assert(s_XInputDLLRefCount == 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Ends C function definitions when using C++
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
276
thirdparty/sdl/core/windows/SDL_xinput.h
vendored
Normal file
276
thirdparty/sdl/core/windows/SDL_xinput.h
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef SDL_xinput_h_
|
||||
#define SDL_xinput_h_
|
||||
|
||||
#include "SDL_windows.h"
|
||||
|
||||
#ifdef HAVE_XINPUT_H
|
||||
#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
// Xbox supports an XInput wrapper which is a C++-only header...
|
||||
#include <math.h> // Required to compile with recent MSVC...
|
||||
#include <XInputOnGameInput.h>
|
||||
using namespace XInputOnGameInput;
|
||||
#else
|
||||
#include <xinput.h>
|
||||
#endif
|
||||
#endif // HAVE_XINPUT_H
|
||||
|
||||
#ifndef XUSER_MAX_COUNT
|
||||
#define XUSER_MAX_COUNT 4
|
||||
#endif
|
||||
#ifndef XUSER_INDEX_ANY
|
||||
#define XUSER_INDEX_ANY 0x000000FF
|
||||
#endif
|
||||
#ifndef XINPUT_CAPS_FFB_SUPPORTED
|
||||
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
|
||||
#endif
|
||||
#ifndef XINPUT_CAPS_WIRELESS
|
||||
#define XINPUT_CAPS_WIRELESS 0x0002
|
||||
#endif
|
||||
|
||||
#ifndef XINPUT_DEVSUBTYPE_UNKNOWN
|
||||
#define XINPUT_DEVSUBTYPE_UNKNOWN 0x00
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_GAMEPAD
|
||||
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_WHEEL
|
||||
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_ARCADE_STICK
|
||||
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_FLIGHT_STICK
|
||||
#define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_DANCE_PAD
|
||||
#define XINPUT_DEVSUBTYPE_DANCE_PAD 0x05
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_GUITAR
|
||||
#define XINPUT_DEVSUBTYPE_GUITAR 0x06
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE
|
||||
#define XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE 0x07
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_DRUM_KIT
|
||||
#define XINPUT_DEVSUBTYPE_DRUM_KIT 0x08
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_GUITAR_BASS
|
||||
#define XINPUT_DEVSUBTYPE_GUITAR_BASS 0x0B
|
||||
#endif
|
||||
#ifndef XINPUT_DEVSUBTYPE_ARCADE_PAD
|
||||
#define XINPUT_DEVSUBTYPE_ARCADE_PAD 0x13
|
||||
#endif
|
||||
|
||||
#ifndef XINPUT_FLAG_GAMEPAD
|
||||
#define XINPUT_FLAG_GAMEPAD 0x01
|
||||
#endif
|
||||
|
||||
#ifndef XINPUT_GAMEPAD_DPAD_UP
|
||||
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_DPAD_DOWN
|
||||
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_DPAD_LEFT
|
||||
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_DPAD_RIGHT
|
||||
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_START
|
||||
#define XINPUT_GAMEPAD_START 0x0010
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_BACK
|
||||
#define XINPUT_GAMEPAD_BACK 0x0020
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_LEFT_THUMB
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_RIGHT_THUMB
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_LEFT_SHOULDER
|
||||
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_RIGHT_SHOULDER
|
||||
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_A
|
||||
#define XINPUT_GAMEPAD_A 0x1000
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_B
|
||||
#define XINPUT_GAMEPAD_B 0x2000
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_X
|
||||
#define XINPUT_GAMEPAD_X 0x4000
|
||||
#endif
|
||||
#ifndef XINPUT_GAMEPAD_Y
|
||||
#define XINPUT_GAMEPAD_Y 0x8000
|
||||
#endif
|
||||
|
||||
#ifndef XINPUT_GAMEPAD_GUIDE
|
||||
#define XINPUT_GAMEPAD_GUIDE 0x0400
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_DEVTYPE_GAMEPAD
|
||||
#define BATTERY_DEVTYPE_GAMEPAD 0x00
|
||||
#endif
|
||||
|
||||
#ifndef BATTERY_TYPE_DISCONNECTED
|
||||
#define BATTERY_TYPE_DISCONNECTED 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
|
||||
|
||||
// Set up for C function definitions, even when using C++
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// typedef's for XInput structs we use
|
||||
|
||||
|
||||
// This is the same as XINPUT_BATTERY_INFORMATION, but always defined instead of just if WIN32_WINNT >= _WIN32_WINNT_WIN8
|
||||
typedef struct
|
||||
{
|
||||
BYTE BatteryType;
|
||||
BYTE BatteryLevel;
|
||||
} XINPUT_BATTERY_INFORMATION_EX;
|
||||
|
||||
#ifndef HAVE_XINPUT_H
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wButtons;
|
||||
BYTE bLeftTrigger;
|
||||
BYTE bRightTrigger;
|
||||
SHORT sThumbLX;
|
||||
SHORT sThumbLY;
|
||||
SHORT sThumbRX;
|
||||
SHORT sThumbRY;
|
||||
} XINPUT_GAMEPAD;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD dwPacketNumber;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
} XINPUT_STATE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD wLeftMotorSpeed;
|
||||
WORD wRightMotorSpeed;
|
||||
} XINPUT_VIBRATION;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BYTE Type;
|
||||
BYTE SubType;
|
||||
WORD Flags;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
XINPUT_VIBRATION Vibration;
|
||||
} XINPUT_CAPABILITIES;
|
||||
|
||||
#endif // HAVE_XINPUT_H
|
||||
|
||||
// This struct is not defined in XInput headers.
|
||||
typedef struct
|
||||
{
|
||||
XINPUT_CAPABILITIES Capabilities;
|
||||
WORD VendorId;
|
||||
WORD ProductId;
|
||||
WORD ProductVersion;
|
||||
WORD unk1;
|
||||
DWORD unk2;
|
||||
} SDL_XINPUT_CAPABILITIES_EX;
|
||||
|
||||
// Forward decl's for XInput API's we load dynamically and use if available
|
||||
typedef DWORD(WINAPI *XInputGetState_t)(
|
||||
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
|
||||
XINPUT_STATE *pState // [out] Receives the current state
|
||||
);
|
||||
|
||||
typedef DWORD(WINAPI *XInputSetState_t)(
|
||||
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
|
||||
XINPUT_VIBRATION *pVibration // [in, out] The vibration information to send to the controller
|
||||
);
|
||||
|
||||
typedef DWORD(WINAPI *XInputGetCapabilities_t)(
|
||||
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
|
||||
DWORD dwFlags, // [in] Input flags that identify the device type
|
||||
XINPUT_CAPABILITIES *pCapabilities // [out] Receives the capabilities
|
||||
);
|
||||
|
||||
// Only available in XInput 1.4 that is shipped with Windows 8 and newer.
|
||||
typedef DWORD(WINAPI *XInputGetCapabilitiesEx_t)(
|
||||
DWORD dwReserved, // [in] Must be 1
|
||||
DWORD dwUserIndex, // [in] Index of the gamer associated with the device
|
||||
DWORD dwFlags, // [in] Input flags that identify the device type
|
||||
SDL_XINPUT_CAPABILITIES_EX *pCapabilitiesEx // [out] Receives the capabilities
|
||||
);
|
||||
|
||||
typedef DWORD(WINAPI *XInputGetBatteryInformation_t)(
|
||||
DWORD dwUserIndex,
|
||||
BYTE devType,
|
||||
XINPUT_BATTERY_INFORMATION_EX *pBatteryInformation);
|
||||
|
||||
extern bool WIN_LoadXInputDLL(void);
|
||||
extern void WIN_UnloadXInputDLL(void);
|
||||
|
||||
extern XInputGetState_t SDL_XInputGetState;
|
||||
extern XInputSetState_t SDL_XInputSetState;
|
||||
extern XInputGetCapabilities_t SDL_XInputGetCapabilities;
|
||||
extern XInputGetCapabilitiesEx_t SDL_XInputGetCapabilitiesEx;
|
||||
extern XInputGetBatteryInformation_t SDL_XInputGetBatteryInformation;
|
||||
extern DWORD SDL_XInputVersion; // ((major << 16) & 0xFF00) | (minor & 0xFF)
|
||||
|
||||
// Ends C function definitions when using C++
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define XINPUTGETSTATE SDL_XInputGetState
|
||||
#define XINPUTSETSTATE SDL_XInputSetState
|
||||
#define XINPUTGETCAPABILITIES SDL_XInputGetCapabilities
|
||||
#define XINPUTGETCAPABILITIESEX SDL_XInputGetCapabilitiesEx
|
||||
#define XINPUTGETBATTERYINFORMATION SDL_XInputGetBatteryInformation
|
||||
|
||||
#endif // SDL_xinput_h_
|
21
thirdparty/sdl/core/windows/pch.c
vendored
Normal file
21
thirdparty/sdl/core/windows/pch.c
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
21
thirdparty/sdl/core/windows/pch_cpp.cpp
vendored
Normal file
21
thirdparty/sdl/core/windows/pch_cpp.cpp
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
Reference in New Issue
Block a user