[PATCH 2/4] windows.gaming.input: Start a thread to monitor HID device addition and removal.

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


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/windows.gaming.input/Makefile.in |   3 +-
 dlls/windows.gaming.input/main.c      | 145 ++++++++++++++++++++++++++
 dlls/windows.gaming.input/private.h   |   3 +
 dlls/windows.gaming.input/provider.c  |  37 +++++++
 4 files changed, 187 insertions(+), 1 deletion(-)
 create mode 100644 dlls/windows.gaming.input/provider.c

diff --git a/dlls/windows.gaming.input/Makefile.in b/dlls/windows.gaming.input/Makefile.in
index 46470ac045b..1a3cdb364f2 100644
--- a/dlls/windows.gaming.input/Makefile.in
+++ b/dlls/windows.gaming.input/Makefile.in
@@ -1,11 +1,12 @@
 MODULE = windows.gaming.input.dll
-IMPORTS = combase uuid
+IMPORTS = combase uuid user32 setupapi hid
 
 C_SRCS = \
 	controller.c \
 	gamepad.c \
 	main.c \
 	manager.c \
+	provider.c \
 	vector.c
 
 IDL_SRCS = classes.idl \
diff --git a/dlls/windows.gaming.input/main.c b/dlls/windows.gaming.input/main.c
index c050d1d5113..0fc23cea5bf 100644
--- a/dlls/windows.gaming.input/main.c
+++ b/dlls/windows.gaming.input/main.c
@@ -23,6 +23,13 @@
 #define COBJMACROS
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
+#include "winuser.h"
+
+#include "dbt.h"
+#include "ddk/hidclass.h"
+#include "ddk/hidsdi.h"
+#include "setupapi.h"
 
 #include "initguid.h"
 #include "private.h"
@@ -31,6 +38,127 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(input);
 
+static HINSTANCE windows_gaming_input;
+
+DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 );
+
+static LRESULT CALLBACK devnotify_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
+{
+    DEV_BROADCAST_DEVICEINTERFACE_W *iface;
+
+    TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam );
+
+    if (msg == WM_DEVICECHANGE)
+    {
+        switch (wparam)
+        {
+        case DBT_DEVICEARRIVAL:
+            iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)lparam;
+            provider_create( iface->dbcc_name );
+            break;
+        case DBT_DEVICEREMOVECOMPLETE:
+            iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)lparam;
+            provider_remove( iface->dbcc_name );
+            break;
+        default: break;
+        }
+    }
+
+    return DefWindowProcW( hwnd, msg, wparam, lparam );
+}
+
+static void initialize_providers( void )
+{
+    char buffer[offsetof( SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath[MAX_PATH] )];
+    SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer;
+    SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
+    GUID guid = GUID_DEVINTERFACE_WINEXINPUT;
+    HDEVINFO set;
+    DWORD i = 0;
+
+    set = SetupDiGetClassDevsW( NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE | DIGCF_PRESENT );
+
+    while (SetupDiEnumDeviceInterfaces( set, NULL, &guid, i++, &iface ))
+    {
+        detail->cbSize = sizeof(*detail);
+        if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, NULL )) continue;
+        provider_create( detail->DevicePath );
+    }
+
+    HidD_GetHidGuid( &guid );
+
+    while (SetupDiEnumDeviceInterfaces( set, NULL, &guid, i++, &iface ))
+    {
+        detail->cbSize = sizeof(*detail);
+        if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, NULL )) continue;
+        provider_create( detail->DevicePath );
+    }
+
+    SetupDiDestroyDeviceInfoList( set );
+}
+
+static DWORD WINAPI monitor_thread_proc( void *param )
+{
+    DEV_BROADCAST_DEVICEINTERFACE_W filter =
+    {
+        .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W),
+        .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE,
+    };
+    WNDCLASSEXW wndclass =
+    {
+        .cbSize = sizeof(WNDCLASSEXW),
+        .lpszClassName = L"__wine_gaming_input_devnotify",
+        .lpfnWndProc = devnotify_wndproc,
+    };
+    HANDLE start_event = param;
+    HDEVNOTIFY devnotify;
+    HMODULE module;
+    HWND hwnd;
+    MSG msg;
+
+    GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (void *)windows_gaming_input, &module );
+    RegisterClassExW( &wndclass );
+    hwnd = CreateWindowExW( 0, wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL );
+    devnotify = RegisterDeviceNotificationW( hwnd, &filter, DEVICE_NOTIFY_ALL_INTERFACE_CLASSES );
+    initialize_providers();
+    SetEvent( start_event );
+
+    do
+    {
+        while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE ))
+        {
+            TranslateMessage( &msg );
+            DispatchMessageW( &msg );
+        }
+    } while (!MsgWaitForMultipleObjectsEx( 0, NULL, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE ));
+
+    UnregisterDeviceNotification( devnotify );
+    DestroyWindow( hwnd );
+    UnregisterClassW( wndclass.lpszClassName, NULL );
+
+    FreeLibraryAndExitThread( module, 0 );
+    return 0;
+}
+
+static BOOL WINAPI start_monitor_thread( INIT_ONCE *once, void *param, void **context )
+{
+    HANDLE thread, start_event;
+
+    start_event = CreateEventA( NULL, FALSE, FALSE, NULL );
+    if (!start_event) ERR( "Failed to create start event, error %lu\n", GetLastError() );
+
+    thread = CreateThread( NULL, 0, monitor_thread_proc, start_event, 0, NULL );
+    if (!thread) ERR( "Failed to create monitor thread, error %lu\n", GetLastError() );
+    else
+    {
+        WaitForSingleObject( start_event, INFINITE );
+        CloseHandle( thread );
+    }
+
+    CloseHandle( start_event );
+    return !!thread;
+}
+
 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
 {
     FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out);
@@ -39,10 +167,13 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
 
 HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory **factory )
 {
+    static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
     const WCHAR *buffer = WindowsGetStringRawBuffer( class_str, NULL );
 
     TRACE( "class %s, factory %p.\n", debugstr_w(buffer), factory );
 
+    InitOnceExecuteOnce( &init_once, start_monitor_thread, NULL, NULL );
+
     *factory = NULL;
 
     if (!wcscmp( buffer, RuntimeClass_Windows_Gaming_Input_RawGameController ))
@@ -55,3 +186,17 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING class_str, IActivationFactory **
     if (*factory) return S_OK;
     return REGDB_E_CLASSNOTREG;
 }
+
+BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved )
+{
+    TRACE( "instance %p, reason %lu, reserved %p.\n", instance, reason, reserved );
+
+    switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+        DisableThreadLibraryCalls( instance );
+        windows_gaming_input = instance;
+        break;
+    }
+    return TRUE;
+}
diff --git a/dlls/windows.gaming.input/private.h b/dlls/windows.gaming.input/private.h
index c6dd1105896..87a3f677d8c 100644
--- a/dlls/windows.gaming.input/private.h
+++ b/dlls/windows.gaming.input/private.h
@@ -41,6 +41,9 @@ extern IActivationFactory *manager_factory;
 
 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 );
+
 #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
new file mode 100644
index 00000000000..710349eb75f
--- /dev/null
+++ b/dlls/windows.gaming.input/provider.c
@@ -0,0 +1,37 @@
+/* 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 "initguid.h"
+#include "provider.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(input);
+
+void provider_create( const WCHAR *device_path )
+{
+    FIXME( "device_path %s stub!\n", debugstr_w( device_path ) );
+}
+
+void provider_remove( const WCHAR *device_path )
+{
+    FIXME( "device_path %s stub!\n", debugstr_w( device_path ) );
+}
-- 
2.34.1




More information about the wine-devel mailing list