Rémi Bernon : windows.gaming.input: Implement IRawGameControllerStatics_get_RawGameControllers.

Alexandre Julliard julliard at winehq.org
Thu Mar 10 16:10:16 CST 2022


Module: wine
Branch: master
Commit: 1ca51d33c26786482cfac6f96e433edf15b4782c
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=1ca51d33c26786482cfac6f96e433edf15b4782c

Author: Rémi Bernon <rbernon at codeweavers.com>
Date:   Thu Mar 10 13:05:47 2022 +0100

windows.gaming.input: Implement IRawGameControllerStatics_get_RawGameControllers.

It is important to add RawGameController instances to the vector in the
initialization callback, because some games check the vector, as well
as the Gamepad class vector in the OnGameControllerAdded callback.

This also removes the OnGameControllerAdded failure case, to avoid
leaking controllers that were already added to the controller vector,
and instead rely on the OnGameControllerRemoved call to do the cleanup.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/dinput/tests/joystick8.c          |  9 +---
 dlls/windows.gaming.input/controller.c | 82 +++++++++++++++++++++++++++-------
 dlls/windows.gaming.input/manager.c    |  6 +--
 3 files changed, 70 insertions(+), 27 deletions(-)

diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c
index 2d801aacda2..e74e76482f9 100644
--- a/dlls/dinput/tests/joystick8.c
+++ b/dlls/dinput/tests/joystick8.c
@@ -3340,17 +3340,10 @@ static void test_windows_gaming_input(void)
     ok( hr == S_OK, "get_RawGameControllers returned %#lx\n", hr );
     hr = IVectorView_RawGameController_get_Size( controllers_view, &size );
     ok( hr == S_OK, "get_Size returned %#lx\n", hr );
-    todo_wine
     ok( size == 1, "got size %u\n", size );
     hr = IVectorView_RawGameController_GetAt( controllers_view, 0, &raw_controller );
-    todo_wine
     ok( hr == S_OK, "GetAt returned %#lx\n", hr );
     IVectorView_RawGameController_Release( controllers_view );
-    if (hr != S_OK)
-    {
-        IRawGameControllerStatics_Release( controller_statics );
-        goto done;
-    }
 
     /* HID gamepads aren't exposed as WGI gamepads on Windows */
 
@@ -3372,6 +3365,7 @@ static void test_windows_gaming_input(void)
     check_interface( raw_controller, &IID_IInspectable, TRUE );
     check_interface( raw_controller, &IID_IAgileObject, TRUE );
     check_interface( raw_controller, &IID_IRawGameController, TRUE );
+    todo_wine
     check_interface( raw_controller, &IID_IRawGameController2, TRUE );
     check_interface( raw_controller, &IID_IGameController, TRUE );
     check_interface( raw_controller, &IID_IGamepad, FALSE );
@@ -3384,6 +3378,7 @@ static void test_windows_gaming_input(void)
     check_interface( game_controller, &IID_IInspectable, TRUE );
     check_interface( game_controller, &IID_IAgileObject, TRUE );
     check_interface( game_controller, &IID_IRawGameController, TRUE );
+    todo_wine
     check_interface( game_controller, &IID_IRawGameController2, TRUE );
     check_interface( game_controller, &IID_IGameController, TRUE );
     check_interface( game_controller, &IID_IGamepad, FALSE );
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c
index 9fb1b1a69a2..51ede5a0e47 100644
--- a/dlls/windows.gaming.input/controller.c
+++ b/dlls/windows.gaming.input/controller.c
@@ -24,6 +24,36 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(input);
 
+static CRITICAL_SECTION controller_cs;
+static CRITICAL_SECTION_DEBUG controller_cs_debug =
+{
+    0, 0, &controller_cs,
+    { &controller_cs_debug.ProcessLocksList, &controller_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": controller_cs") }
+};
+static CRITICAL_SECTION controller_cs = { &controller_cs_debug, -1, 0, 0, 0, 0 };
+
+static IVector_RawGameController *controllers;
+
+static HRESULT init_controllers(void)
+{
+    static const struct vector_iids iids =
+    {
+        .vector = &IID_IVector_RawGameController,
+        .view = &IID_IVectorView_RawGameController,
+        .iterable = &IID_IIterable_RawGameController,
+        .iterator = &IID_IIterator_RawGameController,
+    };
+    HRESULT hr;
+
+    EnterCriticalSection( &controller_cs );
+    if (controllers) hr = S_OK;
+    else hr = vector_create( &iids, (void **)&controllers );
+    LeaveCriticalSection( &controller_cs );
+
+    return hr;
+}
+
 struct controller
 {
     IGameControllerImpl IGameControllerImpl_iface;
@@ -118,13 +148,19 @@ static HRESULT WINAPI controller_Initialize( IGameControllerImpl *iface, IGameCo
                                              IGameControllerProvider *provider )
 {
     struct controller *impl = impl_from_IGameControllerImpl( iface );
+    HRESULT hr;
 
     TRACE( "iface %p, outer %p, provider %p.\n", iface, outer, provider );
 
     impl->IGameController_outer = outer;
     IGameControllerProvider_AddRef( (impl->provider = provider) );
 
-    return S_OK;
+    EnterCriticalSection( &controller_cs );
+    if (SUCCEEDED(hr = init_controllers()))
+        hr = IVector_RawGameController_Append( controllers, &impl->IRawGameController_iface );
+    LeaveCriticalSection( &controller_cs );
+
+    return hr;
 }
 
 static const struct IGameControllerImplVtbl controller_vtbl =
@@ -381,23 +417,14 @@ static HRESULT WINAPI statics_remove_RawGameControllerRemoved( IRawGameControlle
 
 static HRESULT WINAPI statics_get_RawGameControllers( IRawGameControllerStatics *iface, IVectorView_RawGameController **value )
 {
-    static const struct vector_iids iids =
-    {
-        .vector = &IID_IVector_RawGameController,
-        .view = &IID_IVectorView_RawGameController,
-        .iterable = &IID_IIterable_RawGameController,
-        .iterator = &IID_IIterator_RawGameController,
-    };
-    IVector_RawGameController *controllers;
     HRESULT hr;
 
     TRACE( "iface %p, value %p.\n", iface, value );
 
-    if (SUCCEEDED(hr = vector_create( &iids, (void **)&controllers )))
-    {
+    EnterCriticalSection( &controller_cs );
+    if (SUCCEEDED(hr = init_controllers()))
         hr = IVector_RawGameController_GetView( controllers, value );
-        IVector_RawGameController_Release( controllers );
-    }
+    LeaveCriticalSection( &controller_cs );
 
     return hr;
 }
@@ -468,8 +495,33 @@ static HRESULT WINAPI controller_factory_OnGameControllerAdded( ICustomGameContr
 
 static HRESULT WINAPI controller_factory_OnGameControllerRemoved( ICustomGameControllerFactory *iface, IGameController *value )
 {
-    FIXME( "iface %p, value %p stub!\n", iface, value );
-    return E_NOTIMPL;
+    IRawGameController *controller;
+    BOOLEAN found;
+    UINT32 index;
+    HRESULT hr;
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (FAILED(hr = IGameController_QueryInterface( value, &IID_IRawGameController, (void **)&controller )))
+        return hr;
+
+    EnterCriticalSection( &controller_cs );
+    if (SUCCEEDED(hr = init_controllers()))
+    {
+        if (FAILED(hr = IVector_RawGameController_IndexOf( controllers, controller, &index, &found )) || !found)
+            WARN( "Could not find controller %p, hr %#lx!\n", controller, hr );
+        else
+            hr = IVector_RawGameController_RemoveAt( controllers, index );
+    }
+    LeaveCriticalSection( &controller_cs );
+
+    if (FAILED(hr))
+        WARN( "Failed to remove controller %p, hr %#lx!\n", controller, hr );
+    else if (found)
+        TRACE( "Removed controller %p.\n", controller );
+    IRawGameController_Release( controller );
+
+    return S_OK;
 }
 
 static const struct ICustomGameControllerFactoryVtbl controller_factory_vtbl =
diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c
index 489588a68ab..6a8963a1fc4 100644
--- a/dlls/windows.gaming.input/manager.c
+++ b/dlls/windows.gaming.input/manager.c
@@ -502,11 +502,7 @@ void manager_on_provider_created( IGameControllerProvider *provider )
         controller = LIST_ENTRY( entry, struct controller, entry );
         hr = ICustomGameControllerFactory_OnGameControllerAdded( controller->factory,
                                                                  &controller->IGameController_iface );
-        if (FAILED(hr))
-        {
-            list_remove( &controller->entry );
-            IGameController_Release( &controller->IGameController_iface );
-        }
+        if (FAILED(hr)) WARN( "OnGameControllerAdded failed, hr %#lx\n", hr );
         if (next == &controller_list) break;
     }
 




More information about the wine-cvs mailing list