Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/Makefile.in | 2 +- dlls/dinput/tests/hotplug.c | 42 +++++++++++++++++++++++------- dlls/dinput/tests/joystick8.c | 49 +++++++++++++++++++++++++++-------- 3 files changed, 71 insertions(+), 22 deletions(-)
diff --git a/dlls/dinput/tests/Makefile.in b/dlls/dinput/tests/Makefile.in index d32092ca03b..5ba0e5be4d7 100644 --- a/dlls/dinput/tests/Makefile.in +++ b/dlls/dinput/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dinput.dll -IMPORTS = dinput dinput8 ole32 version user32 advapi32 hid uuid crypt32 newdev setupapi wintrust winmm combase +IMPORTS = dinput dinput8 ole32 version user32 advapi32 hid uuid crypt32 newdev setupapi wintrust winmm
driver_hid_IMPORTS = winecrt0 ntoskrnl hal hidclass driver_hid_EXTRADLLFLAGS = -nodefaultlibs -nostartfiles -Wl,--subsystem,native diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 49cc5423807..4dc635932ab 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -47,6 +47,31 @@ #define WIDL_using_Windows_Gaming_Input #include "windows.gaming.input.h"
+#define MAKE_FUNC(f) static typeof(f) *p ## f +MAKE_FUNC( RoGetActivationFactory ); +MAKE_FUNC( RoInitialize ); +MAKE_FUNC( WindowsCreateString ); +MAKE_FUNC( WindowsDeleteString ); +#undef MAKE_FUNC + +static BOOL load_combase_functions(void) +{ + HMODULE combase = GetModuleHandleW( L"combase.dll" ); + +#define LOAD_FUNC(m, f) if (!(p ## f = (void *)GetProcAddress( m, #f ))) goto failed; + LOAD_FUNC( combase, RoGetActivationFactory ); + LOAD_FUNC( combase, RoInitialize ); + LOAD_FUNC( combase, WindowsCreateString ); + LOAD_FUNC( combase, WindowsDeleteString ); +#undef LOAD_FUNC + + return TRUE; + +failed: + win_skip("Failed to load combase.dll functions, skipping tests\n"); + return FALSE; +} + static BOOL test_input_lost( DWORD version ) { #include "psh_hid_macros.h" @@ -529,20 +554,20 @@ static void test_windows_gaming_input(void) HRESULT hr; MSG msg;
- hr = RoInitialize( RO_INIT_MULTITHREADED ); + if (!load_combase_functions()) return; + + hr = pRoInitialize( RO_INIT_MULTITHREADED ); ok( hr == RPC_E_CHANGED_MODE, "RoInitialize failed, hr %#lx\n", hr );
- hr = WindowsCreateString( class_name, wcslen( class_name ), &str ); + hr = pWindowsCreateString( class_name, wcslen( class_name ), &str ); ok( hr == S_OK, "WindowsCreateString failed, hr %#lx\n", hr ); - - hr = RoGetActivationFactory( str, &IID_IRawGameControllerStatics, (void **)&statics ); + hr = pRoGetActivationFactory( str, &IID_IRawGameControllerStatics, (void **)&statics ); ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "RoGetActivationFactory failed, hr %#lx\n", hr ); - WindowsDeleteString( str ); + pWindowsDeleteString( str );
if (hr == REGDB_E_CLASSNOTREG) { win_skip( "%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w( class_name ) ); - RoUninitialize(); return; }
@@ -551,7 +576,7 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "add_RawGameControllerAdded returned %#lx\n", hr ); todo_wine ok( controller_added_token.value, "got token %I64u\n", controller_added_token.value ); - if (!controller_added_token.value) goto done; + if (!controller_added_token.value) return;
hr = IRawGameControllerStatics_add_RawGameControllerRemoved( statics, &controller_removed.IEventHandler_RawGameController_iface, &controller_removed_token ); @@ -642,9 +667,6 @@ static void test_windows_gaming_input(void)
DestroyWindow( hwnd ); UnregisterClassW( class.lpszClassName, class.hInstance ); - -done: - RoUninitialize(); }
START_TEST( hotplug ) diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index f01bed08030..e65e3ca9970 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -46,6 +46,33 @@ #define WIDL_using_Windows_Gaming_Input #include "windows.gaming.input.h"
+#define MAKE_FUNC(f) static typeof(f) *p ## f +MAKE_FUNC( RoGetActivationFactory ); +MAKE_FUNC( RoInitialize ); +MAKE_FUNC( WindowsCreateString ); +MAKE_FUNC( WindowsDeleteString ); +MAKE_FUNC( WindowsGetStringRawBuffer ); +#undef MAKE_FUNC + +static BOOL load_combase_functions(void) +{ + HMODULE combase = GetModuleHandleW( L"combase.dll" ); + +#define LOAD_FUNC(m, f) if (!(p ## f = (void *)GetProcAddress( m, #f ))) goto failed; + LOAD_FUNC( combase, RoGetActivationFactory ); + LOAD_FUNC( combase, RoInitialize ); + LOAD_FUNC( combase, WindowsCreateString ); + LOAD_FUNC( combase, WindowsDeleteString ); + LOAD_FUNC( combase, WindowsGetStringRawBuffer ); +#undef LOAD_FUNC + + return TRUE; + +failed: + win_skip("Failed to load combase.dll functions, skipping tests\n"); + return FALSE; +} + struct check_objects_todos { BOOL type; @@ -3214,9 +3241,9 @@ static void check_runtimeclass_( int line, IInspectable *inspectable, const WCHA
hr = IInspectable_GetRuntimeClassName( inspectable, &str ); ok_ (__FILE__, line)( hr == S_OK, "GetRuntimeClassName returned %#lx\n", hr ); - buffer = WindowsGetStringRawBuffer( str, &length ); + buffer = pWindowsGetStringRawBuffer( str, &length ); ok_ (__FILE__, line)( !wcscmp( buffer, class_name ), "got class name %s\n", debugstr_w(buffer) ); - WindowsDeleteString( str ); + pWindowsDeleteString( str ); }
static void test_windows_gaming_input(void) @@ -3284,20 +3311,22 @@ static void test_windows_gaming_input(void) HSTRING str; HRESULT hr;
+ if (!load_combase_functions()) return; + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); SetCurrentDirectoryW( tempdir );
cleanup_registry_keys();
- hr = RoInitialize( RO_INIT_MULTITHREADED ); + hr = pRoInitialize( RO_INIT_MULTITHREADED ); ok( hr == RPC_E_CHANGED_MODE, "RoInitialize returned %#lx\n", hr );
- hr = WindowsCreateString( controller_class_name, wcslen( controller_class_name ), &str ); + hr = pWindowsCreateString( controller_class_name, wcslen( controller_class_name ), &str ); ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); - hr = RoGetActivationFactory( str, &IID_IRawGameControllerStatics, (void **)&controller_statics ); + hr = pRoGetActivationFactory( str, &IID_IRawGameControllerStatics, (void **)&controller_statics ); ok( hr == S_OK || broken( hr == REGDB_E_CLASSNOTREG ), "RoGetActivationFactory returned %#lx\n", hr ); - WindowsDeleteString( str ); + pWindowsDeleteString( str );
if (hr == REGDB_E_CLASSNOTREG) { @@ -3336,11 +3365,11 @@ static void test_windows_gaming_input(void)
/* HID gamepads aren't exposed as WGI gamepads on Windows */
- hr = WindowsCreateString( gamepad_class_name, wcslen( gamepad_class_name ), &str ); + hr = pWindowsCreateString( gamepad_class_name, wcslen( gamepad_class_name ), &str ); ok( hr == S_OK, "WindowsCreateString returned %#lx\n", hr ); - hr = RoGetActivationFactory( str, &IID_IGamepadStatics, (void **)&gamepad_statics ); + hr = pRoGetActivationFactory( str, &IID_IGamepadStatics, (void **)&gamepad_statics ); ok( hr == S_OK, "RoGetActivationFactory returned %#lx\n", hr ); - WindowsDeleteString( str ); + pWindowsDeleteString( str ); hr = IGamepadStatics_get_Gamepads( gamepad_statics, &gamepads_view ); ok( hr == S_OK, "get_Gamepads returned %#lx\n", hr ); hr = IVectorView_Gamepad_get_Size( gamepads_view, &size ); @@ -3384,8 +3413,6 @@ done: pnp_driver_stop(); cleanup_registry_keys(); SetCurrentDirectoryW( cwd ); - - RoUninitialize(); }
START_TEST( joystick8 )
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/hotplug.c | 76 +++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 29 deletions(-)
diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 4dc635932ab..2f30cc19d9d 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -72,6 +72,28 @@ failed: return FALSE; }
+static DWORD wait_for_events( DWORD count, HANDLE *events, DWORD timeout ) +{ + DWORD ret, end = GetTickCount() + timeout; + MSG msg; + + while ((ret = MsgWaitForMultipleObjects( count, events, FALSE, timeout, QS_ALLINPUT )) <= count) + { + while (PeekMessageW( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageW( &msg ); + } + if (ret < count) return ret; + if (timeout == INFINITE) continue; + if (end <= GetTickCount()) timeout = 0; + else timeout = end - GetTickCount(); + } + + ok( ret == WAIT_TIMEOUT, "MsgWaitForMultipleObjects returned %#lx\n", ret ); + return ret; +} + static BOOL test_input_lost( DWORD version ) { #include "psh_hid_macros.h" @@ -445,6 +467,7 @@ static void test_RegisterDeviceNotification(void) struct controller_handler { IEventHandler_RawGameController IEventHandler_RawGameController_iface; + HANDLE event; BOOL invoked; };
@@ -487,6 +510,7 @@ static HRESULT WINAPI controller_handler_Invoke( IEventHandler_RawGameController trace( "iface %p, sender %p, controller %p\n", iface, sender, controller );
ok( sender == NULL, "got sender %p\n", sender ); + SetEvent( impl->event ); impl->invoked = TRUE;
return S_OK; @@ -548,7 +572,6 @@ static void test_windows_gaming_input(void) IRawGameControllerStatics *statics; HANDLE hwnd, thread, stop_event; HDEVNOTIFY devnotify; - BOOL removed; HSTRING str; UINT32 size; HRESULT hr; @@ -571,6 +594,11 @@ static void test_windows_gaming_input(void) return; }
+ controller_added.event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!controller_added.event, "CreateEventW failed, error %lu\n", GetLastError() ); + controller_removed.event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!controller_removed.event, "CreateEventW failed, error %lu\n", GetLastError() ); + hr = IRawGameControllerStatics_add_RawGameControllerAdded( statics, &controller_added.IEventHandler_RawGameController_iface, &controller_added_token ); ok( hr == S_OK, "add_RawGameControllerAdded returned %#lx\n", hr ); @@ -596,43 +624,30 @@ static void test_windows_gaming_input(void)
device_change_count = 0; device_change_expect = 2; - device_change_hwnd = hwnd; - device_change_all = FALSE; stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); ok( !!stop_event, "CreateEventW failed, error %lu\n", GetLastError() ); thread = CreateThread( NULL, 0, dinput_test_device_thread, stop_event, 0, NULL ); ok( !!thread, "CreateThread failed, error %lu\n", GetLastError() );
- removed = FALSE; - while (device_change_count < device_change_expect) - { - MsgWaitForMultipleObjects( 0, NULL, FALSE, 50, QS_ALLINPUT ); - while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) - { - TranslateMessage( &msg ); - ok( msg.message != WM_DEVICECHANGE, "got WM_DEVICECHANGE\n" ); - DispatchMessageW( &msg ); - } - if (controller_added.invoked && !removed) - { - ok( !controller_removed.invoked, "controller removed handler invoked\n" ); - removed = TRUE; + wait_for_events( 1, &controller_added.event, INFINITE );
- hr = IVectorView_RawGameController_get_Size( controller_view, &size ); - ok( hr == S_OK, "get_Size returned %#lx\n", hr ); - ok( size == 0, "got size %u\n", size ); + ok( controller_added.invoked, "controller added handler not invoked\n" ); + ok( !controller_removed.invoked, "controller removed handler invoked\n" );
- IVectorView_RawGameController_Release( controller_view ); - hr = IRawGameControllerStatics_get_RawGameControllers( statics, &controller_view ); - ok( hr == S_OK, "get_RawGameControllers returned %#lx\n", hr ); + hr = IVectorView_RawGameController_get_Size( controller_view, &size ); + ok( hr == S_OK, "get_Size returned %#lx\n", hr ); + ok( size == 0, "got size %u\n", size );
- hr = IVectorView_RawGameController_get_Size( controller_view, &size ); - ok( hr == S_OK, "get_Size returned %#lx\n", hr ); - ok( size == 1, "got size %u\n", size ); + IVectorView_RawGameController_Release( controller_view ); + hr = IRawGameControllerStatics_get_RawGameControllers( statics, &controller_view ); + ok( hr == S_OK, "get_RawGameControllers returned %#lx\n", hr );
- SetEvent( stop_event ); - } - } + hr = IVectorView_RawGameController_get_Size( controller_view, &size ); + ok( hr == S_OK, "get_Size returned %#lx\n", hr ); + ok( size == 1, "got size %u\n", size ); + + SetEvent( stop_event ); + wait_for_events( 1, &controller_removed.event, INFINITE );
ok( controller_added.invoked, "controller added handler not invoked\n" ); ok( controller_removed.invoked, "controller removed handler not invoked\n" ); @@ -667,6 +682,9 @@ static void test_windows_gaming_input(void)
DestroyWindow( hwnd ); UnregisterClassW( class.lpszClassName, class.hInstance ); + + CloseHandle( controller_added.event ); + CloseHandle( controller_removed.event ); }
START_TEST( hotplug )
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/Makefile.in | 1 + include/windows.gaming.input.custom.idl | 56 +++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 include/windows.gaming.input.custom.idl
diff --git a/include/Makefile.in b/include/Makefile.in index 8a8fddddada..2bb8cd672a7 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -779,6 +779,7 @@ SOURCES = \ windows.devices.haptics.idl \ windows.foundation.collections.idl \ windows.foundation.idl \ + windows.gaming.input.custom.idl \ windows.gaming.input.forcefeedback.idl \ windows.gaming.input.idl \ windows.globalization.idl \ diff --git a/include/windows.gaming.input.custom.idl b/include/windows.gaming.input.custom.idl new file mode 100644 index 00000000000..d24f07f02e1 --- /dev/null +++ b/include/windows.gaming.input.custom.idl @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef __WIDL__ +#pragma winrt ns_prefix +#endif + +import "inspectable.idl"; +import "asyncinfo.idl"; +import "eventtoken.idl"; +import "windowscontracts.idl"; +import "windows.foundation.idl"; +import "windows.gaming.input.idl"; +import "windows.storage.streams.idl"; + +namespace Windows.Gaming.Input.Custom { + typedef struct GameControllerVersionInfo GameControllerVersionInfo; + interface IGameControllerProvider; + + [contract(Windows.Foundation.UniversalApiContract, 3.0)] + struct GameControllerVersionInfo + { + UINT16 Major; + UINT16 Minor; + UINT16 Build; + UINT16 Revision; + }; + + [ + contract(Windows.Foundation.UniversalApiContract, 3.0), + uuid(e6d73982-2996-4559-b16c-3e57d46e58d6) + ] + interface IGameControllerProvider : IInspectable + { + [propget] HRESULT FirmwareVersionInfo([out, retval] Windows.Gaming.Input.Custom.GameControllerVersionInfo *value); + [propget] HRESULT HardwareProductId([out, retval] UINT16 *value); + [propget] HRESULT HardwareVendorId([out, retval] UINT16 *value); + [propget] HRESULT HardwareVersionInfo([out, retval] Windows.Gaming.Input.Custom.GameControllerVersionInfo *value); + [propget] HRESULT IsConnected([out, retval] boolean *value); + } +}
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/windows.gaming.input.custom.idl | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/include/windows.gaming.input.custom.idl b/include/windows.gaming.input.custom.idl index d24f07f02e1..2338e3be166 100644 --- a/include/windows.gaming.input.custom.idl +++ b/include/windows.gaming.input.custom.idl @@ -31,6 +31,7 @@ import "windows.storage.streams.idl"; namespace Windows.Gaming.Input.Custom { typedef struct GameControllerVersionInfo GameControllerVersionInfo; interface IGameControllerProvider; + interface ICustomGameControllerFactory;
[contract(Windows.Foundation.UniversalApiContract, 3.0)] struct GameControllerVersionInfo @@ -53,4 +54,16 @@ namespace Windows.Gaming.Input.Custom { [propget] HRESULT HardwareVersionInfo([out, retval] Windows.Gaming.Input.Custom.GameControllerVersionInfo *value); [propget] HRESULT IsConnected([out, retval] boolean *value); } + + [ + contract(Windows.Foundation.UniversalApiContract, 3.0), + uuid(69a0ae5e-758e-4cbe-ace6-62155fe9126f) + ] + interface ICustomGameControllerFactory : IInspectable + { + HRESULT CreateGameController([in] Windows.Gaming.Input.Custom.IGameControllerProvider *provider, + [out, retval] IInspectable **value); + HRESULT OnGameControllerAdded([in] Windows.Gaming.Input.IGameController *value); + HRESULT OnGameControllerRemoved([in] Windows.Gaming.Input.IGameController *value); + } }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/windows.gaming.input.custom.idl | 68 +++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/include/windows.gaming.input.custom.idl b/include/windows.gaming.input.custom.idl index 2338e3be166..a95ec9db482 100644 --- a/include/windows.gaming.input.custom.idl +++ b/include/windows.gaming.input.custom.idl @@ -29,9 +29,37 @@ import "windows.gaming.input.idl"; import "windows.storage.streams.idl";
namespace Windows.Gaming.Input.Custom { + typedef enum XusbDeviceSubtype XusbDeviceSubtype; + typedef enum XusbDeviceType XusbDeviceType; typedef struct GameControllerVersionInfo GameControllerVersionInfo; interface IGameControllerProvider; interface ICustomGameControllerFactory; + interface IGameControllerFactoryManagerStatics; + interface IGameControllerFactoryManagerStatics2; + runtimeclass GameControllerFactoryManager; + + [contract(Windows.Foundation.UniversalApiContract, 3.0)] + enum XusbDeviceSubtype + { + Unknown = 0, + Gamepad = 1, + ArcadePad = 2, + ArcadeStick = 3, + FlightStick = 4, + Wheel = 5, + Guitar = 6, + GuitarAlternate = 7, + GuitarBass = 8, + DrumKit = 9, + DancePad = 10, + }; + + [contract(Windows.Foundation.UniversalApiContract, 3.0)] + enum XusbDeviceType + { + Unknown = 0, + Gamepad = 1, + };
[contract(Windows.Foundation.UniversalApiContract, 3.0)] struct GameControllerVersionInfo @@ -66,4 +94,44 @@ namespace Windows.Gaming.Input.Custom { HRESULT OnGameControllerAdded([in] Windows.Gaming.Input.IGameController *value); HRESULT OnGameControllerRemoved([in] Windows.Gaming.Input.IGameController *value); } + + [ + contract(Windows.Foundation.UniversalApiContract, 3.0), + exclusiveto(Windows.Gaming.Input.Custom.GameControllerFactoryManager), + uuid(36cb66e3-d0a1-4986-a24c-40b137deba9e) + ] + interface IGameControllerFactoryManagerStatics : IInspectable + { + HRESULT RegisterCustomFactoryForGipInterface([in] Windows.Gaming.Input.Custom.ICustomGameControllerFactory *factory, + [in] GUID interfaceId); + HRESULT RegisterCustomFactoryForHardwareId([in] Windows.Gaming.Input.Custom.ICustomGameControllerFactory *factory, + [in] UINT16 vendor_id, [in] UINT16 product_id); + HRESULT RegisterCustomFactoryForXusbType([in] Windows.Gaming.Input.Custom.ICustomGameControllerFactory *factory, + [in] Windows.Gaming.Input.Custom.XusbDeviceType type, + [in] Windows.Gaming.Input.Custom.XusbDeviceSubtype subtype); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 4.0), + exclusiveto(Windows.Gaming.Input.Custom.GameControllerFactoryManager), + uuid(eace5644-19df-4115-b32a-2793e2aea3bb) + ] + interface IGameControllerFactoryManagerStatics2 : IInspectable + requires Windows.Gaming.Input.Custom.IGameControllerFactoryManagerStatics + { + HRESULT TryGetFactoryControllerFromGameController([in] Windows.Gaming.Input.Custom.ICustomGameControllerFactory *factory, + [in] Windows.Gaming.Input.IGameController *controller, + [out, retval] Windows.Gaming.Input.IGameController **value); + } + + [ + contract(Windows.Foundation.UniversalApiContract, 3.0), + marshaling_behavior(agile), + static(Windows.Gaming.Input.Custom.IGameControllerFactoryManagerStatics, Windows.Foundation.UniversalApiContract, 3.0), + static(Windows.Gaming.Input.Custom.IGameControllerFactoryManagerStatics2, Windows.Foundation.UniversalApiContract, 4.0), + threading(both) + ] + runtimeclass GameControllerFactoryManager + { + } }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/hotplug.c | 140 +++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 2f30cc19d9d..dd1a31c559e 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -45,7 +45,8 @@ #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" #define WIDL_using_Windows_Gaming_Input -#include "windows.gaming.input.h" +#define WIDL_using_Windows_Gaming_Input_Custom +#include "windows.gaming.input.custom.h"
#define MAKE_FUNC(f) static typeof(f) *p ## f MAKE_FUNC( RoGetActivationFactory ); @@ -527,6 +528,104 @@ static const IEventHandler_RawGameControllerVtbl controller_handler_vtbl = static struct controller_handler controller_removed = {{&controller_handler_vtbl}}; static struct controller_handler controller_added = {{&controller_handler_vtbl}};
+struct custom_factory +{ + ICustomGameControllerFactory ICustomGameControllerFactory_iface; + BOOL create_controller_called; +}; + +static inline struct custom_factory *impl_from_ICustomGameControllerFactory( ICustomGameControllerFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct custom_factory, ICustomGameControllerFactory_iface ); +} + +static HRESULT WINAPI custom_factory_QueryInterface( ICustomGameControllerFactory *iface, REFIID iid, void **out ) +{ + struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_ICustomGameControllerFactory )) + { + IInspectable_AddRef( (*out = &impl->ICustomGameControllerFactory_iface) ); + return S_OK; + } + + ok( 0, "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI custom_factory_AddRef( ICustomGameControllerFactory *iface ) +{ + return 2; +} + +static ULONG WINAPI custom_factory_Release( ICustomGameControllerFactory *iface ) +{ + return 1; +} + +static HRESULT WINAPI custom_factory_GetIids( ICustomGameControllerFactory *iface, ULONG *iid_count, IID **iids ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_GetRuntimeClassName( ICustomGameControllerFactory *iface, HSTRING *class_name ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_GetTrustLevel( ICustomGameControllerFactory *iface, TrustLevel *trust_level ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_CreateGameController( ICustomGameControllerFactory *iface, IGameControllerProvider *provider, + IInspectable **value ) +{ + struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface ); + + ok( !controller_added.invoked, "controller added handler invoked\n" ); + ok( !impl->create_controller_called, "unexpected call\n" ); + impl->create_controller_called = TRUE; + + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI custom_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static const struct ICustomGameControllerFactoryVtbl custom_factory_vtbl = +{ + custom_factory_QueryInterface, + custom_factory_AddRef, + custom_factory_Release, + /* IInspectable methods */ + custom_factory_GetIids, + custom_factory_GetRuntimeClassName, + custom_factory_GetTrustLevel, + /* ICustomGameControllerFactory methods */ + custom_factory_CreateGameController, + custom_factory_OnGameControllerAdded, + custom_factory_OnGameControllerRemoved, +}; + +static struct custom_factory custom_factory = {{&custom_factory_vtbl}}; + static LRESULT CALLBACK windows_gaming_input_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { if (msg == WM_DEVICECHANGE) @@ -552,6 +651,7 @@ static LRESULT CALLBACK windows_gaming_input_wndproc( HWND hwnd, UINT msg, WPARA
static void test_windows_gaming_input(void) { + static const WCHAR *manager_class_name = RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager; static const WCHAR *class_name = RuntimeClass_Windows_Gaming_Input_RawGameController; DEV_BROADCAST_DEVICEINTERFACE_A iface_filter_a = { @@ -566,6 +666,10 @@ static void test_windows_gaming_input(void) .lpszClassName = L"devnotify", .lpfnWndProc = windows_gaming_input_wndproc, }; + IGameControllerFactoryManagerStatics2 *manager_statics2; + IRawGameController *raw_controller, *tmp_raw_controller; + IGameController *game_controller, *tmp_game_controller; + IGameControllerFactoryManagerStatics *manager_statics; EventRegistrationToken controller_removed_token; IVectorView_RawGameController *controller_view; EventRegistrationToken controller_added_token; @@ -594,11 +698,23 @@ static void test_windows_gaming_input(void) return; }
+ hr = pWindowsCreateString( manager_class_name, wcslen( manager_class_name ), &str ); + ok( hr == S_OK, "WindowsCreateString failed, hr %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IGameControllerFactoryManagerStatics, (void **)&manager_statics ); + ok( hr == S_OK, "RoGetActivationFactory failed, hr %#lx\n", hr ); + hr = pRoGetActivationFactory( str, &IID_IGameControllerFactoryManagerStatics2, (void **)&manager_statics2 ); + ok( hr == S_OK, "RoGetActivationFactory failed, hr %#lx\n", hr ); + pWindowsDeleteString( str ); + controller_added.event = CreateEventW( NULL, FALSE, FALSE, NULL ); ok( !!controller_added.event, "CreateEventW failed, error %lu\n", GetLastError() ); controller_removed.event = CreateEventW( NULL, FALSE, FALSE, NULL ); ok( !!controller_removed.event, "CreateEventW failed, error %lu\n", GetLastError() );
+ hr = IGameControllerFactoryManagerStatics_RegisterCustomFactoryForHardwareId( manager_statics, &custom_factory.ICustomGameControllerFactory_iface, + LOWORD(EXPECT_VIDPID), HIWORD(EXPECT_VIDPID) ); + ok( hr == S_OK, "RegisterCustomFactoryForHardwareId returned %#lx\n", hr ); + hr = IRawGameControllerStatics_add_RawGameControllerAdded( statics, &controller_added.IEventHandler_RawGameController_iface, &controller_added_token ); ok( hr == S_OK, "add_RawGameControllerAdded returned %#lx\n", hr ); @@ -633,6 +749,7 @@ static void test_windows_gaming_input(void)
ok( controller_added.invoked, "controller added handler not invoked\n" ); ok( !controller_removed.invoked, "controller removed handler invoked\n" ); + ok( custom_factory.create_controller_called, "CreateGameController not called\n" );
hr = IVectorView_RawGameController_get_Size( controller_view, &size ); ok( hr == S_OK, "get_Size returned %#lx\n", hr ); @@ -645,6 +762,23 @@ static void test_windows_gaming_input(void) hr = IVectorView_RawGameController_get_Size( controller_view, &size ); ok( hr == S_OK, "get_Size returned %#lx\n", hr ); ok( size == 1, "got size %u\n", size ); + hr = IVectorView_RawGameController_GetAt( controller_view, 0, &raw_controller ); + ok( hr == S_OK, "GetAt returned %#lx\n", hr ); + hr = IRawGameController_QueryInterface( raw_controller, &IID_IGameController, (void **)&game_controller ); + ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + + hr = IGameControllerFactoryManagerStatics2_TryGetFactoryControllerFromGameController( manager_statics2, + &custom_factory.ICustomGameControllerFactory_iface, game_controller, &tmp_game_controller ); + ok( hr == S_OK, "TryGetFactoryControllerFromGameController returned %#lx\n", hr ); + ok( !tmp_game_controller, "got controller %p\n", tmp_game_controller ); + + hr = IRawGameControllerStatics_FromGameController( statics, game_controller, &tmp_raw_controller ); + ok( hr == S_OK, "FromGameController returned %#lx\n", hr ); + ok( tmp_raw_controller == raw_controller, "got controller %p\n", tmp_raw_controller ); + IRawGameController_Release( tmp_raw_controller ); + + IGameController_Release( game_controller ); + IRawGameController_Release( raw_controller );
SetEvent( stop_event ); wait_for_events( 1, &controller_removed.event, INFINITE ); @@ -672,8 +806,10 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "remove_RawGameControllerRemoved returned %#lx\n", hr );
IVectorView_RawGameController_Release( controller_view ); - IRawGameControllerStatics_Release( statics );
+ IGameControllerFactoryManagerStatics2_Release( manager_statics2 ); + IGameControllerFactoryManagerStatics_Release( manager_statics ); + IRawGameControllerStatics_Release( statics ); WaitForSingleObject( thread, INFINITE ); CloseHandle( thread ); CloseHandle( stop_event );
I just found that this last patch is actually causing a segfault, please ignore it. Patches 1-5 should be fine.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=109445
Your paranoid android.
=== debian11 (32 bit report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit Arabic:Morocco report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit German report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit French report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit Hebrew:Israel report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit Hindi:India report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit Japanese:Japan report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (32 bit Chinese:China report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x0044104b).
=== debian11 (64 bit WoW report) ===
dinput: hotplug.c:704: Test failed: RoGetActivationFactory failed, hr 0x80040154 hotplug.c:706: Test failed: RoGetActivationFactory failed, hr 0x80040154 Unhandled exception: page fault on read access to 0x0000000000000000 in 64-bit code (0x000000000043a4e0).