Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: Fix test failure in PATCH 7, IGameControllerImpl really needs to be the inner IInspectable iface instead of an additional iface, as the runtime queries it then calls Initialize to provide the outer iface.
dlls/windows.gaming.input/controller.c | 41 +------------------------- dlls/windows.gaming.input/gamepad.c | 41 +------------------------- dlls/windows.gaming.input/private.h | 36 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 80 deletions(-)
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index 00ab9c5d91c..654d0795eac 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -35,11 +35,6 @@ static inline struct controller_statics *impl_from_IActivationFactory( IActivati return CONTAINING_RECORD( iface, struct controller_statics, IActivationFactory_iface ); }
-static inline struct controller_statics *impl_from_IRawGameControllerStatics( IRawGameControllerStatics *iface ) -{ - return CONTAINING_RECORD( iface, struct controller_statics, IRawGameControllerStatics_iface ); -} - static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) { struct controller_statics *impl = impl_from_IActivationFactory( iface ); @@ -121,41 +116,7 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
-static HRESULT WINAPI statics_QueryInterface( IRawGameControllerStatics *iface, REFIID iid, void **out ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_QueryInterface( &impl->IActivationFactory_iface, iid, out ); -} - -static ULONG WINAPI statics_AddRef( IRawGameControllerStatics *iface ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_AddRef( &impl->IActivationFactory_iface ); -} - -static ULONG WINAPI statics_Release( IRawGameControllerStatics *iface ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetIids( IRawGameControllerStatics *iface, ULONG *iid_count, IID **iids ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetRuntimeClassName( IRawGameControllerStatics *iface, HSTRING *class_name ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetTrustLevel( IRawGameControllerStatics *iface, TrustLevel *trust_level ) -{ - struct controller_statics *impl = impl_from_IRawGameControllerStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} +DEFINE_IINSPECTABLE( statics, IRawGameControllerStatics, struct controller_statics, IActivationFactory_iface )
static HRESULT WINAPI statics_add_RawGameControllerAdded( IRawGameControllerStatics *iface, IEventHandler_RawGameController *value, EventRegistrationToken *token ) diff --git a/dlls/windows.gaming.input/gamepad.c b/dlls/windows.gaming.input/gamepad.c index e69568e2fb1..231e923b5e8 100644 --- a/dlls/windows.gaming.input/gamepad.c +++ b/dlls/windows.gaming.input/gamepad.c @@ -35,11 +35,6 @@ static inline struct gamepad_statics *impl_from_IActivationFactory( IActivationF return CONTAINING_RECORD( iface, struct gamepad_statics, IActivationFactory_iface ); }
-static inline struct gamepad_statics *impl_from_IGamepadStatics( IGamepadStatics *iface ) -{ - return CONTAINING_RECORD( iface, struct gamepad_statics, IGamepadStatics_iface ); -} - static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) { struct gamepad_statics *impl = impl_from_IActivationFactory( iface ); @@ -121,41 +116,7 @@ static const struct IActivationFactoryVtbl factory_vtbl = factory_ActivateInstance, };
-static HRESULT WINAPI statics_QueryInterface( IGamepadStatics *iface, REFIID iid, void **out ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_QueryInterface( &impl->IActivationFactory_iface, iid, out ); -} - -static ULONG WINAPI statics_AddRef( IGamepadStatics *iface ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_AddRef( &impl->IActivationFactory_iface ); -} - -static ULONG WINAPI statics_Release( IGamepadStatics *iface ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetIids( IGamepadStatics *iface, ULONG *iid_count, IID **iids ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetRuntimeClassName( IGamepadStatics *iface, HSTRING *class_name ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} - -static HRESULT WINAPI statics_GetTrustLevel( IGamepadStatics *iface, TrustLevel *trust_level ) -{ - struct gamepad_statics *impl = impl_from_IGamepadStatics( iface ); - return IActivationFactory_Release( &impl->IActivationFactory_iface ); -} +DEFINE_IINSPECTABLE( statics, IGamepadStatics, struct gamepad_statics, IActivationFactory_iface )
static HRESULT WINAPI statics_add_GamepadAdded( IGamepadStatics *iface, IEventHandler_Gamepad *value, EventRegistrationToken *token ) diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index 612d11135f4..d36f88d58e4 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -38,3 +38,39 @@ extern IActivationFactory *controller_factory; extern IActivationFactory *gamepad_factory;
extern HRESULT vector_create( REFIID iid, REFIID view_iid, void **out ); + +#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface ) \ + static inline impl_type *impl_from_##iface_type( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_type##_iface ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)&impl->base_iface, iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_AddRef( (IInspectable *)&impl->base_iface ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_Release( (IInspectable *)&impl->base_iface ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_GetIids( (IInspectable *)&impl->base_iface, iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)&impl->base_iface, class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)&impl->base_iface, trust_level ); \ + }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/Makefile.in | 1 + dlls/windows.gaming.input/main.c | 2 + dlls/windows.gaming.input/manager.c | 201 ++++++++++++++++++++++++++ dlls/windows.gaming.input/private.h | 4 +- 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 dlls/windows.gaming.input/manager.c
diff --git a/dlls/windows.gaming.input/Makefile.in b/dlls/windows.gaming.input/Makefile.in index 5031e72f08d..d7f93283bec 100644 --- a/dlls/windows.gaming.input/Makefile.in +++ b/dlls/windows.gaming.input/Makefile.in @@ -5,6 +5,7 @@ C_SRCS = \ controller.c \ gamepad.c \ main.c \ + manager.c \ vector.c
IDL_SRCS = classes.idl diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c index aac21a0c33c..c050d1d5113 100644 --- a/dlls/windows.gaming.input/main.c +++ b/dlls/windows.gaming.input/main.c @@ -49,6 +49,8 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory ** IActivationFactory_AddRef( (*factory = controller_factory) ); if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Gamepad )) IActivationFactory_AddRef( (*factory = gamepad_factory) ); + if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_Custom_GameControllerFactoryManager )) + IActivationFactory_AddRef( (*factory = manager_factory) );
if (*factory) return S_OK; return REGDB_E_CLASSNOTREG; diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c new file mode 100644 index 00000000000..61f639b8e7e --- /dev/null +++ b/dlls/windows.gaming.input/manager.c @@ -0,0 +1,201 @@ +/* WinRT Windows.Gaming.Input implementation + * + * 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 + */ + +#include "private.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(input); + +struct manager_statics +{ + IActivationFactory IActivationFactory_iface; + IGameControllerFactoryManagerStatics IGameControllerFactoryManagerStatics_iface; + IGameControllerFactoryManagerStatics2 IGameControllerFactoryManagerStatics2_iface; + LONG ref; +}; + +static inline struct manager_statics *impl_from_IActivationFactory( IActivationFactory *iface ) +{ + return CONTAINING_RECORD( iface, struct manager_statics, IActivationFactory_iface ); +} + +static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out ) +{ + struct manager_statics *impl = impl_from_IActivationFactory( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IAgileObject ) || + IsEqualGUID( iid, &IID_IActivationFactory )) + { + IInspectable_AddRef( (*out = &impl->IActivationFactory_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerFactoryManagerStatics )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerFactoryManagerStatics_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerFactoryManagerStatics2 )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerFactoryManagerStatics2_iface) ); + return S_OK; + } + + FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI factory_AddRef( IActivationFactory *iface ) +{ + struct manager_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p increasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static ULONG WINAPI factory_Release( IActivationFactory *iface ) +{ + struct manager_statics *impl = impl_from_IActivationFactory( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref ); + return ref; +} + +static HRESULT WINAPI factory_GetIids( IActivationFactory *iface, ULONG *iid_count, IID **iids ) +{ + FIXME( "iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name ) +{ + FIXME( "iface %p, class_name %p stub!\n", iface, class_name ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level ) +{ + FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level ); + return E_NOTIMPL; +} + +static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance ) +{ + FIXME( "iface %p, instance %p stub!\n", iface, instance ); + return E_NOTIMPL; +} + +static const struct IActivationFactoryVtbl factory_vtbl = +{ + factory_QueryInterface, + factory_AddRef, + factory_Release, + /* IInspectable methods */ + factory_GetIids, + factory_GetRuntimeClassName, + factory_GetTrustLevel, + /* IActivationFactory methods */ + factory_ActivateInstance, +}; + +DEFINE_IINSPECTABLE( statics, IGameControllerFactoryManagerStatics, struct manager_statics, IActivationFactory_iface ) + +static HRESULT WINAPI +statics_RegisterCustomFactoryForGipInterface( IGameControllerFactoryManagerStatics *iface, + ICustomGameControllerFactory *factory, + GUID interface_id ) +{ + FIXME( "iface %p, factory %p, interface_id %s stub!\n", iface, factory, debugstr_guid(&interface_id) ); + return E_NOTIMPL; +} + +static HRESULT WINAPI +statics_RegisterCustomFactoryForHardwareId( IGameControllerFactoryManagerStatics *iface, + ICustomGameControllerFactory *factory, + UINT16 vendor_id, UINT16 product_id ) +{ + FIXME( "iface %p, factory %p, vendor_id %u, product_id %u stub!\n", iface, factory, vendor_id, product_id ); + return E_NOTIMPL; +} + +static HRESULT WINAPI +statics_RegisterCustomFactoryForXusbType( IGameControllerFactoryManagerStatics *iface, + ICustomGameControllerFactory *factory, + XusbDeviceType type, XusbDeviceSubtype subtype ) +{ + FIXME( "iface %p, factory %p, type %d, subtype %d stub!\n", iface, factory, type, subtype ); + return E_NOTIMPL; +} + +static const struct IGameControllerFactoryManagerStaticsVtbl statics_vtbl = +{ + statics_QueryInterface, + statics_AddRef, + statics_Release, + /* IInspectable methods */ + statics_GetIids, + statics_GetRuntimeClassName, + statics_GetTrustLevel, + /* IGameControllerFactoryManagerStatics methods */ + statics_RegisterCustomFactoryForGipInterface, + statics_RegisterCustomFactoryForHardwareId, + statics_RegisterCustomFactoryForXusbType, +}; + +DEFINE_IINSPECTABLE( statics2, IGameControllerFactoryManagerStatics2, struct manager_statics, IActivationFactory_iface ) + +static HRESULT WINAPI +statics2_TryGetFactoryControllerFromGameController( IGameControllerFactoryManagerStatics2 *iface, + ICustomGameControllerFactory *factory, + IGameController *controller, IGameController **value ) +{ + FIXME( "iface %p, factory %p, controller %p, value %p stub!\n", iface, factory, controller, value ); + return E_NOTIMPL; +} + +static const struct IGameControllerFactoryManagerStatics2Vtbl statics2_vtbl = +{ + statics2_QueryInterface, + statics2_AddRef, + statics2_Release, + /* IInspectable methods */ + statics2_GetIids, + statics2_GetRuntimeClassName, + statics2_GetTrustLevel, + /* IGameControllerFactoryManagerStatics2 methods */ + statics2_TryGetFactoryControllerFromGameController, +}; + +static struct manager_statics manager_statics = +{ + {&factory_vtbl}, + {&statics_vtbl}, + {&statics2_vtbl}, + 1, +}; + +IActivationFactory *manager_factory = &manager_statics.IActivationFactory_iface; diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h index d36f88d58e4..c6dd1105896 100644 --- a/dlls/windows.gaming.input/private.h +++ b/dlls/windows.gaming.input/private.h @@ -32,10 +32,12 @@ #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"
extern IActivationFactory *controller_factory; extern IActivationFactory *gamepad_factory; +extern IActivationFactory *manager_factory;
extern HRESULT vector_create( REFIID iid, REFIID view_iid, void **out );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/classes.idl | 15 +++++++++++++++ include/windows.gaming.input.custom.idl | 2 ++ include/windows.gaming.input.idl | 2 ++ 3 files changed, 19 insertions(+)
diff --git a/dlls/windows.gaming.input/classes.idl b/dlls/windows.gaming.input/classes.idl index c9cb91e3182..fd52d8ebf66 100644 --- a/dlls/windows.gaming.input/classes.idl +++ b/dlls/windows.gaming.input/classes.idl @@ -20,4 +20,19 @@
#pragma makedep register
+#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.devices.haptics.idl"; +import "windows.gaming.input.forcefeedback.idl"; +import "windows.system.idl"; + +#define DO_NO_IMPORTS #include "windows.gaming.input.idl" +#include "windows.gaming.input.custom.idl" diff --git a/include/windows.gaming.input.custom.idl b/include/windows.gaming.input.custom.idl index 0811b991091..8347f4663d3 100644 --- a/include/windows.gaming.input.custom.idl +++ b/include/windows.gaming.input.custom.idl @@ -20,6 +20,7 @@ #pragma winrt ns_prefix #endif
+#ifndef DO_NO_IMPORTS import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; @@ -27,6 +28,7 @@ import "windowscontracts.idl"; import "windows.foundation.idl"; import "windows.gaming.input.idl"; import "windows.storage.streams.idl"; +#endif
namespace Windows.Gaming.Input.Custom { typedef enum XusbDeviceSubtype XusbDeviceSubtype; diff --git a/include/windows.gaming.input.idl b/include/windows.gaming.input.idl index a7d5e71381d..90253b3a8f6 100644 --- a/include/windows.gaming.input.idl +++ b/include/windows.gaming.input.idl @@ -20,6 +20,7 @@ #pragma winrt ns_prefix #endif
+#ifndef DO_NO_IMPORTS import "inspectable.idl"; import "asyncinfo.idl"; import "eventtoken.idl"; @@ -28,6 +29,7 @@ import "windows.foundation.idl"; import "windows.devices.haptics.idl"; import "windows.gaming.input.forcefeedback.idl"; import "windows.system.idl"; +#endif
namespace Windows.Gaming.Input { typedef enum GamepadButtons GamepadButtons;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/hotplug.c | 141 +++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 2f30cc19d9d..e8f5157d73f 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,24 @@ 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) ); + todo_wine + 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 +750,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 +763,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 +807,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 );
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/windows.gaming.input/classes.idl | 1 + include/Makefile.in | 1 + include/windows.devices.power.idl | 39 +++++++++++++++++++++++++++ include/windows.gaming.input.idl | 10 +++++++ 4 files changed, 51 insertions(+) create mode 100644 include/windows.devices.power.idl
diff --git a/dlls/windows.gaming.input/classes.idl b/dlls/windows.gaming.input/classes.idl index fd52d8ebf66..ca3bd5d8dd7 100644 --- a/dlls/windows.gaming.input/classes.idl +++ b/dlls/windows.gaming.input/classes.idl @@ -32,6 +32,7 @@ import "windows.foundation.idl"; import "windows.devices.haptics.idl"; import "windows.gaming.input.forcefeedback.idl"; import "windows.system.idl"; +import "windows.devices.power.idl";
#define DO_NO_IMPORTS #include "windows.gaming.input.idl" diff --git a/include/Makefile.in b/include/Makefile.in index 2bb8cd672a7..b89225510e9 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -777,6 +777,7 @@ SOURCES = \ windot11.h \ windows.devices.enumeration.idl \ windows.devices.haptics.idl \ + windows.devices.power.idl \ windows.foundation.collections.idl \ windows.foundation.idl \ windows.gaming.input.custom.idl \ diff --git a/include/windows.devices.power.idl b/include/windows.devices.power.idl new file mode 100644 index 00000000000..4bf2599686c --- /dev/null +++ b/include/windows.devices.power.idl @@ -0,0 +1,39 @@ +/* + * 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 "windows.foundation.idl"; + +namespace Windows.Devices.Power { + interface IBatteryReport; + runtimeclass BatteryReport; + + [ + contract(Windows.Foundation.UniversalApiContract, 1.0), + marshaling_behavior(agile), + threading(both) + ] + runtimeclass BatteryReport + { + [default] interface Windows.Devices.Power.IBatteryReport; + } +} diff --git a/include/windows.gaming.input.idl b/include/windows.gaming.input.idl index 90253b3a8f6..6a5fc8af1ee 100644 --- a/include/windows.gaming.input.idl +++ b/include/windows.gaming.input.idl @@ -29,6 +29,7 @@ import "windows.foundation.idl"; import "windows.devices.haptics.idl"; import "windows.gaming.input.forcefeedback.idl"; import "windows.system.idl"; +import "windows.devices.power.idl"; #endif
namespace Windows.Gaming.Input { @@ -319,6 +320,15 @@ namespace Windows.Gaming.Input { HRESULT FromGameController([in] Windows.Gaming.Input.IGameController *game_controller, [out, retval] Windows.Gaming.Input.RawGameController **value); }
+ [ + contract(Windows.Foundation.UniversalApiContract, 4.0), + uuid(dcecc681-3963-4da6-955d-553f3b6f6161) + ] + interface IGameControllerBatteryInfo : IInspectable + { + HRESULT TryGetBatteryReport([out, retval] Windows.Devices.Power.BatteryReport **value); + } + [ contract(Windows.Foundation.UniversalApiContract, 1.0), marshaling_behavior(agile),
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/Makefile.in | 1 + include/weakreference.idl | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 include/weakreference.idl
diff --git a/include/Makefile.in b/include/Makefile.in index b89225510e9..ae551abd4c0 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -755,6 +755,7 @@ SOURCES = \ wbemdisp.idl \ wbemprov.idl \ wct.h \ + weakreference.idl \ webservices.h \ werapi.h \ wfext.h \ diff --git a/include/weakreference.idl b/include/weakreference.idl new file mode 100644 index 00000000000..e0d700a44de --- /dev/null +++ b/include/weakreference.idl @@ -0,0 +1,39 @@ +/* + * 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 + */ + +import "inspectable.idl"; + +[ + object, + uuid(00000037-0000-0000-c000-000000000046), + pointer_default(unique) +] +interface IWeakReference : IUnknown +{ + HRESULT Resolve([in] REFIID iid, [out, retval, iid_is(iid)] IInspectable **ref); +} + +[ + object, + uuid(00000038-0000-0000-c000-000000000046), + pointer_default(unique) +] +interface IWeakReferenceSource : IUnknown +{ + HRESULT GetWeakReference([out, retval] IWeakReference **ref); +}
This shows that the runtime uses COM aggregation to provide the IGameController and IGameControllerBatteryInfo implementation, while expecting the custom controller to implement several other interfaces depending on the type of provider used as a backend.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/tests/hotplug.c | 369 +++++++++++++++++++++++++++++++++++- 1 file changed, 364 insertions(+), 5 deletions(-)
diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index e8f5157d73f..46e297d5b91 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -41,6 +41,7 @@
#include "initguid.h" #include "roapi.h" +#include "weakreference.h" #define WIDL_using_Windows_Foundation #define WIDL_using_Windows_Foundation_Collections #include "windows.foundation.h" @@ -95,6 +96,19 @@ static DWORD wait_for_events( DWORD count, HANDLE *events, DWORD timeout ) return ret; }
+#define check_interface( a, b, c ) check_interface_( __LINE__, a, b, c ) +static void check_interface_( unsigned int line, void *iface_ptr, REFIID iid, BOOL supported ) +{ + IUnknown *iface = iface_ptr; + HRESULT hr, expected; + IUnknown *unk; + + expected = supported ? S_OK : E_NOINTERFACE; + hr = IUnknown_QueryInterface( iface, iid, (void **)&unk ); + ok_ (__FILE__, line)( hr == expected, "got hr %#lx, expected %#lx.\n", hr, expected ); + if (SUCCEEDED(hr)) IUnknown_Release( unk ); +} + static BOOL test_input_lost( DWORD version ) { #include "psh_hid_macros.h" @@ -528,10 +542,246 @@ 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}};
+DEFINE_GUID( IID_IGameControllerImpl, 0x06e58977, 0x7684, 0x4dc5, 0xba, 0xd1, 0xcd, 0xa5, 0x2a, 0x4a, 0xa0, 0x6d ); +typedef IInspectable IGameControllerImpl; + +#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface ) \ + static inline impl_type *impl_from_##iface_type( iface_type *iface ) \ + { \ + return CONTAINING_RECORD( iface, impl_type, iface_type##_iface ); \ + } \ + static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_QueryInterface( (IInspectable *)impl->outer_iface, iid, out ); \ + } \ + static ULONG WINAPI pfx##_AddRef( iface_type *iface ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_AddRef( (IInspectable *)impl->outer_iface ); \ + } \ + static ULONG WINAPI pfx##_Release( iface_type *iface ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_Release( (IInspectable *)impl->outer_iface ); \ + } \ + static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_GetIids( (IInspectable *)impl->outer_iface, iid_count, iids ); \ + } \ + static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_GetRuntimeClassName( (IInspectable *)impl->outer_iface, class_name ); \ + } \ + static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level ) \ + { \ + impl_type *impl = impl_from_##iface_type( iface ); \ + return IInspectable_GetTrustLevel( (IInspectable *)impl->outer_iface, trust_level ); \ + } + +struct custom_controller +{ + IGameControllerImpl IGameControllerImpl_iface; + IGameControllerInputSink IGameControllerInputSink_iface; + IHidGameControllerInputSink IHidGameControllerInputSink_iface; + IGameController *IGameController_outer; + LONG ref; + + BOOL initialize_called; + BOOL on_input_resumed_called; + BOOL on_input_suspended_called; + BOOL raw_game_controller_queried; +}; + +static inline struct custom_controller *impl_from_IGameControllerImpl( IGameControllerImpl *iface ) +{ + return CONTAINING_RECORD( iface, struct custom_controller, IGameControllerImpl_iface ); +} + +static HRESULT WINAPI controller_QueryInterface( IGameControllerImpl *iface, REFIID iid, void **out ) +{ + struct custom_controller *impl = impl_from_IGameControllerImpl( iface ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || + IsEqualGUID( iid, &IID_IGameControllerImpl )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerImpl_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IGameControllerInputSink )) + { + IInspectable_AddRef( (*out = &impl->IGameControllerInputSink_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IHidGameControllerInputSink )) + { + IInspectable_AddRef( (*out = &impl->IHidGameControllerInputSink_iface) ); + return S_OK; + } + + if (IsEqualGUID( iid, &IID_IRawGameController )) + { + impl->raw_game_controller_queried = TRUE; + *out = NULL; + return E_NOINTERFACE; + } + + ok( 0, "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI controller_AddRef( IGameControllerImpl *iface ) +{ + struct custom_controller *impl = impl_from_IGameControllerImpl( iface ); + return InterlockedIncrement( &impl->ref ); +} + +static ULONG WINAPI controller_Release( IGameControllerImpl *iface ) +{ + struct custom_controller *impl = impl_from_IGameControllerImpl( iface ); + return InterlockedDecrement( &impl->ref ); +} + +static HRESULT WINAPI controller_GetIids( IGameControllerImpl *iface, ULONG *iid_count, IID **iids ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_GetRuntimeClassName( IGameControllerImpl *iface, HSTRING *class_name ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_GetTrustLevel( IGameControllerImpl *iface, TrustLevel *trust_level ) +{ + ok( 0, "unexpected call\n" ); + return E_NOTIMPL; +} + +static HRESULT WINAPI controller_Initialize( IGameControllerImpl *iface, IGameController *outer, IGameControllerProvider *provider ) +{ + struct custom_controller *impl = impl_from_IGameControllerImpl( iface ); + + ok( !impl->initialize_called, "Initialize already called\n" ); + impl->initialize_called = TRUE; + + check_interface( outer, &IID_IUnknown, TRUE ); + check_interface( outer, &IID_IInspectable, TRUE ); + check_interface( outer, &IID_IAgileObject, TRUE ); + check_interface( outer, &IID_IWeakReferenceSource, TRUE ); + check_interface( outer, &IID_IGameController, TRUE ); + impl->IGameController_outer = outer; + + check_interface( provider, &IID_IUnknown, TRUE ); + check_interface( provider, &IID_IInspectable, TRUE ); + check_interface( provider, &IID_IAgileObject, TRUE ); + check_interface( provider, &IID_IWeakReferenceSource, TRUE ); + check_interface( provider, &IID_IGameControllerProvider, TRUE ); + check_interface( provider, &IID_IHidGameControllerProvider, TRUE ); + + return S_OK; +} + +static const void *controller_vtbl[] = +{ + controller_QueryInterface, + controller_AddRef, + controller_Release, + /* IInspectable methods */ + controller_GetIids, + controller_GetRuntimeClassName, + controller_GetTrustLevel, + /* IGameControllerImpl methods */ + controller_Initialize, +}; + +DEFINE_IINSPECTABLE_OUTER( input_sink, IGameControllerInputSink, struct custom_controller, IGameController_outer ) + +static HRESULT WINAPI input_sink_OnInputResumed( IGameControllerInputSink *iface, UINT64 timestamp ) +{ + struct custom_controller *impl = impl_from_IGameControllerInputSink( iface ); + + trace( "iface %p, timestamp %I64u\n", iface, timestamp ); + + ok( !controller_added.invoked, "controller added handler invoked\n" ); + ok( !impl->on_input_resumed_called, "OnInputResumed already called\n" ); + impl->on_input_resumed_called = TRUE; + + return S_OK; +} + +static HRESULT WINAPI input_sink_OnInputSuspended( IGameControllerInputSink *iface, UINT64 timestamp ) +{ + struct custom_controller *impl = impl_from_IGameControllerInputSink( iface ); + + trace( "iface %p, timestamp %I64u\n", iface, timestamp ); + + ok( !controller_removed.invoked, "controller removed handler invoked\n" ); + ok( !impl->on_input_suspended_called, "OnInputSuspended already called\n" ); + impl->on_input_suspended_called = TRUE; + + return S_OK; +} + +static const struct IGameControllerInputSinkVtbl input_sink_vtbl = +{ + input_sink_QueryInterface, + input_sink_AddRef, + input_sink_Release, + /* IInspectable methods */ + input_sink_GetIids, + input_sink_GetRuntimeClassName, + input_sink_GetTrustLevel, + /* IGameControllerInputSink methods */ + input_sink_OnInputResumed, + input_sink_OnInputSuspended, +}; + +DEFINE_IINSPECTABLE_OUTER( hid_sink, IHidGameControllerInputSink, struct custom_controller, IGameController_outer ) + +static HRESULT WINAPI hid_sink_OnInputReportReceived( IHidGameControllerInputSink *iface, UINT64 timestamp, BYTE id, UINT32 report_len, BYTE *report_buf ) +{ + ok( 0, "unexpected call\n" ); + return S_OK; +} + +static const struct IHidGameControllerInputSinkVtbl hid_sink_vtbl = +{ + hid_sink_QueryInterface, + hid_sink_AddRef, + hid_sink_Release, + /* IInspectable methods */ + hid_sink_GetIids, + hid_sink_GetRuntimeClassName, + hid_sink_GetTrustLevel, + /* IGameControllerInputSink methods */ + hid_sink_OnInputReportReceived, +}; + +static struct custom_controller custom_controller = +{ + {(IInspectableVtbl *)controller_vtbl}, + {&input_sink_vtbl}, + {&hid_sink_vtbl}, +}; + struct custom_factory { ICustomGameControllerFactory ICustomGameControllerFactory_iface; BOOL create_controller_called; + BOOL create_controller; + BOOL on_game_controller_added_called; + HANDLE added_event; + BOOL on_game_controller_removed_called; + HANDLE removed_event; };
static inline struct custom_factory *impl_from_ICustomGameControllerFactory( ICustomGameControllerFactory *iface ) @@ -590,23 +840,60 @@ static HRESULT WINAPI custom_factory_CreateGameController( ICustomGameController { struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface );
+ trace( "iface %p, provider %p, value %p\n", iface, provider, value ); + ok( !controller_added.invoked, "controller added handler invoked\n" ); ok( !impl->create_controller_called, "unexpected call\n" ); impl->create_controller_called = TRUE; + if (!impl->create_controller) return E_NOTIMPL;
- return E_NOTIMPL; + check_interface( provider, &IID_IUnknown, TRUE ); + check_interface( provider, &IID_IInspectable, TRUE ); + check_interface( provider, &IID_IAgileObject, TRUE ); + check_interface( provider, &IID_IGameControllerProvider, TRUE ); + check_interface( provider, &IID_IHidGameControllerProvider, TRUE ); + check_interface( provider, &IID_IXusbGameControllerProvider, FALSE ); + check_interface( provider, &IID_IGameControllerInputSink, FALSE ); + custom_controller.ref = 1; + + *value = &custom_controller.IGameControllerImpl_iface; + return S_OK; }
static HRESULT WINAPI custom_factory_OnGameControllerAdded( ICustomGameControllerFactory *iface, IGameController *value ) { - ok( 0, "unexpected call\n" ); - return E_NOTIMPL; + struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface ); + + trace( "iface %p, value %p\n", iface, value ); + + ok( controller_added.invoked, "controller added handler not invoked\n" ); + ok( impl->create_controller_called, "CreateGameController not called\n" ); + ok( impl->create_controller, "unexpected call\n" ); + ok( custom_controller.initialize_called, "Initialize not called\n" ); + ok( custom_controller.on_input_resumed_called, "OnInputResumed not called\n" ); + ok( !custom_controller.on_input_suspended_called, "OnInputSuspended not called\n" ); + ok( !impl->on_game_controller_added_called, "OnGameControllerAdded already called\n" ); + impl->on_game_controller_added_called = TRUE; + SetEvent( impl->added_event ); + + return S_OK; }
static HRESULT WINAPI custom_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value ) { - ok( 0, "unexpected call\n" ); - return E_NOTIMPL; + struct custom_factory *impl = impl_from_ICustomGameControllerFactory( iface ); + + trace( "iface %p, value %p\n", iface, value ); + + ok( controller_removed.invoked, "controller removed handler invoked\n" ); + ok( custom_controller.on_input_suspended_called, "OnInputSuspended not called\n" ); + ok( impl->create_controller, "unexpected call\n" ); + ok( impl->on_game_controller_added_called, "OnGameControllerAdded already called\n" ); + ok( !impl->on_game_controller_removed_called, "OnGameControllerRemoved already called\n" ); + impl->on_game_controller_removed_called = TRUE; + SetEvent( impl->removed_event ); + + return S_OK; }
static const struct ICustomGameControllerFactoryVtbl custom_factory_vtbl = @@ -675,6 +962,7 @@ static void test_windows_gaming_input(void) EventRegistrationToken controller_added_token; IRawGameControllerStatics *statics; HANDLE hwnd, thread, stop_event; + IInspectable *tmp_inspectable; HDEVNOTIFY devnotify; HSTRING str; UINT32 size; @@ -799,6 +1087,75 @@ static void test_windows_gaming_input(void) ok( hr == S_OK, "get_Size returned %#lx\n", hr ); ok( size == 0, "got size %u\n", size );
+ IVectorView_RawGameController_Release( controller_view ); + + WaitForSingleObject( thread, INFINITE ); + CloseHandle( thread ); + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + + device_change_count = 0; + device_change_expect = 2; + custom_factory.create_controller = TRUE; + custom_factory.create_controller_called = FALSE; + ResetEvent( controller_added.event ); + controller_added.invoked = FALSE; + ResetEvent( controller_removed.event ); + controller_removed.invoked = FALSE; + ResetEvent( stop_event ); + + custom_factory.added_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!custom_factory.added_event, "CreateEventW failed, error %lu\n", GetLastError() ); + custom_factory.removed_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + ok( !!custom_factory.removed_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() ); + wait_for_events( 1, &controller_added.event, INFINITE ); + wait_for_events( 1, &custom_factory.added_event, INFINITE ); + hr = IRawGameControllerStatics_get_RawGameControllers( statics, &controller_view ); + ok( hr == S_OK, "get_RawGameControllers returned %#lx\n", hr ); + 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 ); + ok( game_controller != custom_controller.IGameController_outer, "got controller %p\n", game_controller ); + + 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 == custom_controller.IGameController_outer, "got controller %p\n", tmp_game_controller ); + hr = IGameController_QueryInterface( tmp_game_controller, &IID_IInspectable, (void **)&tmp_inspectable ); + ok( hr == S_OK, "QueryInterface returned %#lx\n", hr ); + ok( tmp_inspectable == (void *)tmp_game_controller, "got inspectable %p\n", tmp_inspectable ); + + check_interface( tmp_inspectable, &IID_IUnknown, TRUE ); + check_interface( tmp_inspectable, &IID_IInspectable, TRUE ); + check_interface( tmp_inspectable, &IID_IAgileObject, TRUE ); + check_interface( tmp_inspectable, &IID_IWeakReferenceSource, TRUE ); + check_interface( tmp_inspectable, &IID_IGameController, TRUE ); + check_interface( tmp_inspectable, &IID_IGameControllerBatteryInfo, TRUE ); + check_interface( tmp_inspectable, &IID_IGameControllerInputSink, TRUE ); + check_interface( tmp_inspectable, &IID_IHidGameControllerInputSink, TRUE ); + check_interface( tmp_inspectable, &IID_IGameControllerImpl, TRUE ); + + check_interface( tmp_inspectable, &IID_IRawGameController, FALSE ); + check_interface( tmp_inspectable, &IID_IGameControllerProvider, FALSE ); + IInspectable_Release( tmp_inspectable ); + ok( custom_controller.raw_game_controller_queried, "IRawGameController not queried\n" ); + + IGameController_Release( tmp_game_controller ); + + hr = IRawGameControllerStatics_FromGameController( statics, custom_controller.IGameController_outer, &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, &custom_factory.removed_event, INFINITE ); + wait_for_events( 1, &controller_removed.event, INFINITE ); + hr = IRawGameControllerStatics_remove_RawGameControllerAdded( statics, controller_added_token ); ok( hr == S_OK, "remove_RawGameControllerAdded returned %#lx\n", hr ); hr = IRawGameControllerStatics_remove_RawGameControllerRemoved( statics, controller_removed_token ); @@ -820,6 +1177,8 @@ static void test_windows_gaming_input(void) DestroyWindow( hwnd ); UnregisterClassW( class.lpszClassName, class.hInstance );
+ CloseHandle( custom_factory.added_event ); + CloseHandle( custom_factory.removed_event ); CloseHandle( controller_added.event ); CloseHandle( controller_removed.event ); }