[PATCH 4/4] windows.gaming.input: Instantiate the WineGameControllerProvider runtimeclass.

Rémi Bernon rbernon at codeweavers.com
Fri Mar 4 03:05:10 CST 2022


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/windows.gaming.input/Makefile.in |   2 +-
 dlls/windows.gaming.input/main.c      |   2 +-
 dlls/windows.gaming.input/manager.c   |  10 ++
 dlls/windows.gaming.input/private.h   |   4 +
 dlls/windows.gaming.input/provider.c  | 222 +++++++++++++++++++++++++-
 5 files changed, 236 insertions(+), 4 deletions(-)

diff --git a/dlls/windows.gaming.input/Makefile.in b/dlls/windows.gaming.input/Makefile.in
index 1a3cdb364f2..93d167f61e9 100644
--- a/dlls/windows.gaming.input/Makefile.in
+++ b/dlls/windows.gaming.input/Makefile.in
@@ -1,5 +1,5 @@
 MODULE = windows.gaming.input.dll
-IMPORTS = combase uuid user32 setupapi hid
+IMPORTS = combase uuid user32 dinput8 setupapi hid
 
 C_SRCS = \
 	controller.c \
diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c
index 0fc23cea5bf..03d47e1ce2f 100644
--- a/dlls/windows.gaming.input/main.c
+++ b/dlls/windows.gaming.input/main.c
@@ -38,7 +38,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(input);
 
-static HINSTANCE windows_gaming_input;
+HINSTANCE windows_gaming_input;
 
 DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 );
 
diff --git a/dlls/windows.gaming.input/manager.c b/dlls/windows.gaming.input/manager.c
index 61f639b8e7e..e6366256fe7 100644
--- a/dlls/windows.gaming.input/manager.c
+++ b/dlls/windows.gaming.input/manager.c
@@ -199,3 +199,13 @@ static struct manager_statics manager_statics =
 };
 
 IActivationFactory *manager_factory = &manager_statics.IActivationFactory_iface;
+
+void manager_on_provider_created( IGameControllerProvider *provider )
+{
+    FIXME( "provider %p stub!\n", provider );
+}
+
+void manager_on_provider_removed( IGameControllerProvider *provider )
+{
+    FIXME( "provider %p stub!\n", provider );
+}
diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h
index 87a3f677d8c..a0bd45b3f20 100644
--- a/dlls/windows.gaming.input/private.h
+++ b/dlls/windows.gaming.input/private.h
@@ -35,6 +35,7 @@
 #define WIDL_using_Windows_Gaming_Input_Custom
 #include "windows.gaming.input.custom.h"
 
+extern HINSTANCE windows_gaming_input;
 extern IActivationFactory *controller_factory;
 extern IActivationFactory *gamepad_factory;
 extern IActivationFactory *manager_factory;
@@ -44,6 +45,9 @@ extern HRESULT vector_create( REFIID iid, REFIID view_iid, void **out );
 extern void provider_create( const WCHAR *device_path );
 extern void provider_remove( const WCHAR *device_path );
 
+extern void manager_on_provider_created( IGameControllerProvider *provider );
+extern void manager_on_provider_removed( IGameControllerProvider *provider );
+
 #define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface )                              \
     static inline impl_type *impl_from_##iface_type( iface_type *iface )                           \
     {                                                                                              \
diff --git a/dlls/windows.gaming.input/provider.c b/dlls/windows.gaming.input/provider.c
index 710349eb75f..9ab9682f221 100644
--- a/dlls/windows.gaming.input/provider.c
+++ b/dlls/windows.gaming.input/provider.c
@@ -20,18 +20,236 @@
 #include "private.h"
 
 #include "initguid.h"
+#include "dinput.h"
 #include "provider.h"
 
 #include "wine/debug.h"
+#include "wine/list.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(input);
 
+DEFINE_GUID( device_path_guid, 0x00000000, 0x0000, 0x0000, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf8 );
+
+static CRITICAL_SECTION provider_cs;
+static CRITICAL_SECTION_DEBUG provider_cs_debug =
+{
+    0, 0, &provider_cs,
+    { &provider_cs_debug.ProcessLocksList, &provider_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": provider_cs") }
+};
+static CRITICAL_SECTION provider_cs = { &provider_cs_debug, -1, 0, 0, 0, 0 };
+
+static struct list provider_list = LIST_INIT( provider_list );
+
+struct provider
+{
+    IWineGameControllerProvider IWineGameControllerProvider_iface;
+    IGameControllerProvider IGameControllerProvider_iface;
+    LONG ref;
+
+    IDirectInputDevice8W *dinput_device;
+    WCHAR device_path[MAX_PATH];
+    struct list entry;
+};
+
+static inline struct provider *impl_from_IWineGameControllerProvider( IWineGameControllerProvider *iface )
+{
+    return CONTAINING_RECORD( iface, struct provider, IWineGameControllerProvider_iface );
+}
+
+static HRESULT WINAPI wine_provider_QueryInterface( IWineGameControllerProvider *iface, REFIID iid, void **out )
+{
+    struct provider *impl = impl_from_IWineGameControllerProvider( 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_IWineGameControllerProvider ))
+    {
+        IInspectable_AddRef( (*out = &impl->IWineGameControllerProvider_iface) );
+        return S_OK;
+    }
+
+    if (IsEqualGUID( iid, &IID_IGameControllerProvider ))
+    {
+        IInspectable_AddRef( (*out = &impl->IGameControllerProvider_iface) );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI wine_provider_AddRef( IWineGameControllerProvider *iface )
+{
+    struct provider *impl = impl_from_IWineGameControllerProvider( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI wine_provider_Release( IWineGameControllerProvider *iface )
+{
+    struct provider *impl = impl_from_IWineGameControllerProvider( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+
+    TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        IDirectInputDevice8_Release( impl->dinput_device );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI wine_provider_GetIids( IWineGameControllerProvider *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 wine_provider_GetRuntimeClassName( IWineGameControllerProvider *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI wine_provider_GetTrustLevel( IWineGameControllerProvider *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static const struct IWineGameControllerProviderVtbl wine_provider_vtbl =
+{
+    wine_provider_QueryInterface,
+    wine_provider_AddRef,
+    wine_provider_Release,
+    /* IInspectable methods */
+    wine_provider_GetIids,
+    wine_provider_GetRuntimeClassName,
+    wine_provider_GetTrustLevel,
+};
+
+DEFINE_IINSPECTABLE( game_provider, IGameControllerProvider, struct provider, IWineGameControllerProvider_iface )
+
+static HRESULT WINAPI game_provider_get_FirmwareVersionInfo( IGameControllerProvider *iface, GameControllerVersionInfo *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI game_provider_get_HardwareProductId( IGameControllerProvider *iface, UINT16 *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI game_provider_get_HardwareVendorId( IGameControllerProvider *iface, UINT16 *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI game_provider_get_HardwareVersionInfo( IGameControllerProvider *iface, GameControllerVersionInfo *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI game_provider_get_IsConnected( IGameControllerProvider *iface, boolean *value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static const struct IGameControllerProviderVtbl game_provider_vtbl =
+{
+    game_provider_QueryInterface,
+    game_provider_AddRef,
+    game_provider_Release,
+    /* IInspectable methods */
+    game_provider_GetIids,
+    game_provider_GetRuntimeClassName,
+    game_provider_GetTrustLevel,
+    /* IGameControllerProvider methods */
+    game_provider_get_FirmwareVersionInfo,
+    game_provider_get_HardwareProductId,
+    game_provider_get_HardwareVendorId,
+    game_provider_get_HardwareVersionInfo,
+    game_provider_get_IsConnected,
+};
+
 void provider_create( const WCHAR *device_path )
 {
-    FIXME( "device_path %s stub!\n", debugstr_w( device_path ) );
+    IDirectInputDevice8W *dinput_device;
+    IGameControllerProvider *provider;
+    struct provider *impl, *entry;
+    GUID guid = device_path_guid;
+    IDirectInput8W *dinput;
+    BOOL found = FALSE;
+    const WCHAR *tmp;
+    HRESULT hr;
+
+    if (wcsnicmp( device_path, L"\\\\?\\HID#", 8 )) return;
+    if ((tmp = wcschr( device_path + 8, '#' )) && !wcsnicmp( tmp - 6, L"&IG_", 4 )) return;
+
+    TRACE( "device_path %s\n", debugstr_w( device_path ) );
+
+    *(const WCHAR **)&guid = device_path;
+    if (FAILED(DirectInput8Create( windows_gaming_input, DIRECTINPUT_VERSION, &IID_IDirectInput8W,
+                                   (void **)&dinput, NULL ))) return;
+    hr = IDirectInput8_CreateDevice( dinput, &guid, &dinput_device, NULL );
+    IDirectInput8_Release( dinput );
+    if (FAILED(hr)) return;
+
+    if (!(impl = calloc( 1, sizeof(*impl) ))) goto done;
+    impl->IWineGameControllerProvider_iface.lpVtbl = &wine_provider_vtbl;
+    impl->IGameControllerProvider_iface.lpVtbl = &game_provider_vtbl;
+    IDirectInputDevice_AddRef( dinput_device );
+    impl->dinput_device = dinput_device;
+    impl->ref = 1;
+
+    wcscpy( impl->device_path, device_path );
+    list_init( &impl->entry );
+    provider = &impl->IGameControllerProvider_iface;
+    TRACE( "created WineGameControllerProvider %p\n", provider );
+
+    EnterCriticalSection( &provider_cs );
+    LIST_FOR_EACH_ENTRY( entry, &provider_list, struct provider, entry )
+        if ((found = !wcscmp( entry->device_path, device_path ))) break;
+    if (!found) list_add_tail( &provider_list, &impl->entry );
+    LeaveCriticalSection( &provider_cs );
+
+    if (found) IGameControllerProvider_Release( provider );
+    else manager_on_provider_created( provider );
+done:
+    IDirectInputDevice_Release( dinput_device );
 }
 
 void provider_remove( const WCHAR *device_path )
 {
-    FIXME( "device_path %s stub!\n", debugstr_w( device_path ) );
+    IGameControllerProvider *provider;
+    struct provider *entry;
+    BOOL found = FALSE;
+
+    TRACE( "device_path %s\n", debugstr_w( device_path ) );
+
+    EnterCriticalSection( &provider_cs );
+    LIST_FOR_EACH_ENTRY( entry, &provider_list, struct provider, entry )
+        if ((found = !wcscmp( entry->device_path, device_path ))) break;
+    if (found) list_remove( &entry->entry );
+    LeaveCriticalSection( &provider_cs );
+
+    if (found)
+    {
+        provider = &entry->IGameControllerProvider_iface;
+        manager_on_provider_removed( provider );
+        IGameControllerProvider_Release( provider );
+    }
 }
-- 
2.34.1




More information about the wine-devel mailing list