Use WGI instead of XInput for Windows 10 UWP apps

Fixes https://github.com/libsdl-org/SDL/issues/5017
main
Sam Lantinga 2021-11-27 10:24:32 -08:00
parent e04a0221e3
commit 110e4e1334
4 changed files with 111 additions and 75 deletions

View File

@ -253,6 +253,7 @@
<ClCompile Include="..\src\joystick\virtual\SDL_virtualjoystick.c" /> <ClCompile Include="..\src\joystick\virtual\SDL_virtualjoystick.c" />
<ClCompile Include="..\src\joystick\windows\SDL_dinputjoystick.c" /> <ClCompile Include="..\src\joystick\windows\SDL_dinputjoystick.c" />
<ClCompile Include="..\src\joystick\windows\SDL_windowsjoystick.c" /> <ClCompile Include="..\src\joystick\windows\SDL_windowsjoystick.c" />
<ClCompile Include="..\src\joystick\windows\SDL_windows_gaming_input.c" />
<ClCompile Include="..\src\joystick\windows\SDL_xinputjoystick.c" /> <ClCompile Include="..\src\joystick\windows\SDL_xinputjoystick.c" />
<ClCompile Include="..\src\loadso\windows\SDL_sysloadso.c" /> <ClCompile Include="..\src\loadso\windows\SDL_sysloadso.c" />
<ClCompile Include="..\src\locale\SDL_locale.c" /> <ClCompile Include="..\src\locale\SDL_locale.c" />

View File

@ -814,4 +814,9 @@
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\joystick\windows\SDL_windows_gaming_input.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project> </Project>

View File

@ -201,8 +201,13 @@ typedef unsigned int uintptr_t;
#define SDL_HAPTIC_DISABLED 1 #define SDL_HAPTIC_DISABLED 1
#else #else
#define SDL_JOYSTICK_VIRTUAL 1 #define SDL_JOYSTICK_VIRTUAL 1
#if (NTDDI_VERSION >= NTDDI_WIN10)
#define SDL_JOYSTICK_WGI 1
#define SDL_HAPTIC_DISABLED 1
#else
#define SDL_JOYSTICK_XINPUT 1 #define SDL_JOYSTICK_XINPUT 1
#define SDL_HAPTIC_XINPUT 1 #define SDL_HAPTIC_XINPUT 1
#endif /* WIN10 */
#endif #endif
/* WinRT doesn't have HIDAPI available */ /* WinRT doesn't have HIDAPI available */

View File

@ -32,6 +32,7 @@
#define COBJMACROS #define COBJMACROS
#include "windows.gaming.input.h" #include "windows.gaming.input.h"
#include <cfgmgr32.h> #include <cfgmgr32.h>
#include <roapi.h>
struct joystick_hwdata struct joystick_hwdata
@ -94,6 +95,7 @@ extern SDL_bool SDL_DINPUT_JoystickPresent(Uint16 vendor, Uint16 product, Uint16
static SDL_bool static SDL_bool
SDL_IsXInputDevice(Uint16 vendor, Uint16 product) SDL_IsXInputDevice(Uint16 vendor, Uint16 product)
{ {
#ifdef SDL_JOYSTICK_XINPUT
PRAWINPUTDEVICELIST raw_devices = NULL; PRAWINPUTDEVICELIST raw_devices = NULL;
UINT i, raw_device_count = 0; UINT i, raw_device_count = 0;
LONG vidpid = MAKELONG(vendor, product); LONG vidpid = MAKELONG(vendor, product);
@ -191,6 +193,8 @@ SDL_IsXInputDevice(Uint16 vendor, Uint16 product)
} }
SDL_free(raw_devices); SDL_free(raw_devices);
#endif /* SDL_JOYSTICK_XINPUT */
return SDL_FALSE; return SDL_FALSE;
} }
@ -229,7 +233,7 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
return S_OK; return S_OK;
} }
hr = IUnknown_QueryInterface((IUnknown *)e, &IID_IRawGameController, (void **)&controller); hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(e, &IID_IRawGameController, (void **)&controller);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
char *name = NULL; char *name = NULL;
SDL_JoystickGUID guid; SDL_JoystickGUID guid;
@ -247,26 +251,37 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeAdde
hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IRawGameController2, (void **)&controller2); hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(controller, &IID_IRawGameController2, (void **)&controller2);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
typedef PCWSTR (WINAPI *WindowsGetStringRawBuffer_t)(HSTRING string, UINT32 *length);
typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string);
WindowsGetStringRawBuffer_t WindowsGetStringRawBufferFunc = NULL;
WindowsDeleteString_t WindowsDeleteStringFunc = NULL;
#ifdef __WINRT__
WindowsGetStringRawBufferFunc = WindowsGetStringRawBuffer;
WindowsDeleteStringFunc = WindowsDeleteString;
#else
HMODULE hModule = LoadLibraryA("combase.dll"); HMODULE hModule = LoadLibraryA("combase.dll");
if (hModule != NULL) { if (hModule != NULL) {
typedef PCWSTR (WINAPI *WindowsGetStringRawBuffer_t)(HSTRING string, UINT32 *length); WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)GetProcAddress(hModule, "WindowsGetStringRawBuffer");
typedef HRESULT (WINAPI *WindowsDeleteString_t)(HSTRING string); WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString");
}
WindowsGetStringRawBuffer_t WindowsGetStringRawBufferFunc = (WindowsGetStringRawBuffer_t)GetProcAddress(hModule, "WindowsGetStringRawBuffer"); #endif /* __WINRT__ */
WindowsDeleteString_t WindowsDeleteStringFunc = (WindowsDeleteString_t)GetProcAddress(hModule, "WindowsDeleteString"); if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) {
if (WindowsGetStringRawBufferFunc && WindowsDeleteStringFunc) { HSTRING hString;
HSTRING hString; hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_get_DisplayName(controller2, &hString);
hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_get_DisplayName(controller2, &hString); if (SUCCEEDED(hr)) {
if (SUCCEEDED(hr)) { PCWSTR string = WindowsGetStringRawBufferFunc(hString, NULL);
PCWSTR string = WindowsGetStringRawBufferFunc(hString, NULL); if (string) {
if (string) { name = WIN_StringToUTF8W(string);
name = WIN_StringToUTF8W(string);
}
WindowsDeleteStringFunc(hString);
} }
WindowsDeleteStringFunc(hString);
} }
}
#ifndef __WINRT__
if (hModule != NULL) {
FreeLibrary(hModule); FreeLibrary(hModule);
} }
#endif
__x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2); __x_ABI_CWindows_CGaming_CInput_CIRawGameController2_Release(controller2);
} }
if (!name) { if (!name) {
@ -373,7 +388,7 @@ static HRESULT STDMETHODCALLTYPE IEventHandler_CRawGameControllerVtbl_InvokeRemo
HRESULT hr; HRESULT hr;
__x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL; __x_ABI_CWindows_CGaming_CInput_CIRawGameController *controller = NULL;
hr = IUnknown_QueryInterface((IUnknown *)e, &IID_IRawGameController, (void **)&controller); hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameController_QueryInterface(e, &IID_IRawGameController, (void **)&controller);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
int i; int i;
@ -424,78 +439,88 @@ static __FIEventHandler_1_Windows__CGaming__CInput__CRawGameController controlle
static int static int
WGI_JoystickInit(void) WGI_JoystickInit(void)
{ {
HMODULE hModule;
HRESULT hr; HRESULT hr;
if (FAILED(WIN_CoInitialize())) { if (FAILED(WIN_CoInitialize())) {
return SDL_SetError("CoInitialize() failed"); return SDL_SetError("CoInitialize() failed");
} }
hModule = LoadLibraryA("combase.dll"); typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string);
if (hModule != NULL) { typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
typedef HRESULT (WINAPI *WindowsCreateStringReference_t)(PCWSTR sourceString, UINT32 length, HSTRING_HEADER *hstringHeader, HSTRING* string);
typedef HRESULT (WINAPI *RoGetActivationFactory_t)(HSTRING activatableClassId, REFIID iid, void** factory);
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = NULL;
RoGetActivationFactory_t RoGetActivationFactoryFunc = NULL;
#ifdef __WINRT__
WindowsCreateStringReferenceFunc = WindowsCreateStringReference;
RoGetActivationFactoryFunc = RoGetActivationFactory;
#else
HMODULE hModule = LoadLibraryA("combase.dll");
if (hModule != NULL) {
WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference"); WindowsCreateStringReference_t WindowsCreateStringReferenceFunc = (WindowsCreateStringReference_t)GetProcAddress(hModule, "WindowsCreateStringReference");
RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory"); RoGetActivationFactory_t RoGetActivationFactoryFunc = (RoGetActivationFactory_t)GetProcAddress(hModule, "RoGetActivationFactory");
if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) { }
PCWSTR pNamespace; #endif /* __WINRT__ */
HSTRING_HEADER hNamespaceStringHeader; if (WindowsCreateStringReferenceFunc && RoGetActivationFactoryFunc) {
HSTRING hNamespaceString; PCWSTR pNamespace;
HSTRING_HEADER hNamespaceStringHeader;
HSTRING hNamespaceString;
pNamespace = L"Windows.Gaming.Input.RawGameController"; pNamespace = L"Windows.Gaming.Input.RawGameController";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString); hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, (void **)&wgi.statics); hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRawGameControllerStatics, (void **)&wgi.statics);
if (!SUCCEEDED(hr)) { if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%lx", hr); SDL_SetError("Couldn't find IRawGameControllerStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.ArcadeStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, (void **)&wgi.arcade_stick_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2);
} else {
SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.FlightStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, (void **)&wgi.flight_stick_statics);
if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.Gamepad";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, (void **)&wgi.gamepad_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, (void **)&wgi.gamepad_statics2);
} else {
SDL_SetError("Couldn't find IGamepadStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.RacingWheel";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, (void **)&wgi.racing_wheel_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2);
} else {
SDL_SetError("Couldn't find IRacingWheelStatics: 0x%lx", hr);
}
} }
} }
pNamespace = L"Windows.Gaming.Input.ArcadeStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IArcadeStickStatics, (void **)&wgi.arcade_stick_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIArcadeStickStatics_QueryInterface(wgi.arcade_stick_statics, &IID_IArcadeStickStatics2, (void **)&wgi.arcade_stick_statics2);
} else {
SDL_SetError("Couldn't find IID_IArcadeStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.FlightStick";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IFlightStickStatics, (void **)&wgi.flight_stick_statics);
if (!SUCCEEDED(hr)) {
SDL_SetError("Couldn't find IID_IFlightStickStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.Gamepad";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IGamepadStatics, (void **)&wgi.gamepad_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIGamepadStatics_QueryInterface(wgi.gamepad_statics, &IID_IGamepadStatics2, (void **)&wgi.gamepad_statics2);
} else {
SDL_SetError("Couldn't find IGamepadStatics: 0x%lx", hr);
}
}
pNamespace = L"Windows.Gaming.Input.RacingWheel";
hr = WindowsCreateStringReferenceFunc(pNamespace, (UINT32)SDL_wcslen(pNamespace), &hNamespaceStringHeader, &hNamespaceString);
if (SUCCEEDED(hr)) {
hr = RoGetActivationFactoryFunc(hNamespaceString, &IID_IRacingWheelStatics, (void **)&wgi.racing_wheel_statics);
if (SUCCEEDED(hr)) {
__x_ABI_CWindows_CGaming_CInput_CIRacingWheelStatics_QueryInterface(wgi.racing_wheel_statics, &IID_IRacingWheelStatics2, (void **)&wgi.racing_wheel_statics2);
} else {
SDL_SetError("Couldn't find IRacingWheelStatics: 0x%lx", hr);
}
}
}
#ifndef __WINRT__
if (hModule != NULL) {
FreeLibrary(hModule); FreeLibrary(hModule);
} }
#endif
if (wgi.statics) { if (wgi.statics) {
hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_add_RawGameControllerAdded(wgi.statics, &controller_added, &wgi.controller_added_token); hr = __x_ABI_CWindows_CGaming_CInput_CIRawGameControllerStatics_add_RawGameControllerAdded(wgi.statics, &controller_added, &wgi.controller_added_token);