Commit 1ca51d33 authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

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: 's avatarRémi Bernon <rbernon@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 0ecde550
......@@ -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 );
......
......@@ -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 =
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment