[PATCH v2 2/4] dinput8: Add support for dinput devices that use raw input interface

Rémi Bernon rbernon at codeweavers.com
Thu Aug 29 03:30:57 CDT 2019


This adds a global message window that will receive WM_INPUT messages,
dispatched to every raw input device event_proc.

Devices that use raw input interface will not register low-level hooks
anymore. They will also conflict with any raw input device registered
outside of dinput, as exposed by the unit tests.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/device_private.h |  3 ++
 dlls/dinput/dinput_main.c    | 79 +++++++++++++++++++++++++++++++++++-
 2 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index 27e9c262869..8d4d6a0b5bf 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -70,6 +70,9 @@ struct IDirectInputDeviceImpl
     int                         acquired;
     DI_EVENT_PROC               event_proc;  /* function to receive mouse & keyboard events */
 
+    BOOL                        use_raw_input; /* use raw input instead of low-level messages */
+    RAWINPUTDEVICE              raw_device;    /* raw device to (un)register */
+
     LPDIDEVICEOBJECTDATA        data_queue;  /* buffer for 'GetDeviceData'.                 */
     int                         queue_len;   /* size of the queue - set in 'SetProperty'    */
     int                         queue_head;  /* position to write new event into queue      */
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c
index 0855cb41cd5..4fd0b9cc5a9 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -97,6 +97,10 @@ static const struct dinput_device *dinput_devices[] =
 
 HINSTANCE DINPUT_instance;
 
+static ATOM        di_em_win_class;
+static const WCHAR di_em_winW[] = {'D','I','E','m','W','i','n',0};
+static HWND        di_em_win;
+
 static BOOL check_hook_thread(void);
 static CRITICAL_SECTION dinput_hook_crit;
 static struct list direct_input_list = LIST_INIT( direct_input_list );
@@ -611,6 +615,59 @@ static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, RE
     return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj );
 }
 
+static LRESULT WINAPI di_em_win_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    IDirectInputImpl *dinput;
+
+    TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam );
+
+    if (msg == WM_INPUT)
+    {
+        EnterCriticalSection( &dinput_hook_crit );
+        LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry )
+        {
+            IDirectInputDeviceImpl *dev;
+
+            EnterCriticalSection( &dinput->crit );
+            LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
+            {
+                if (dev->acquired && dev->event_proc && dev->use_raw_input)
+                {
+                    TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam);
+                    dev->event_proc( &dev->IDirectInputDevice8A_iface, GET_RAWINPUT_CODE_WPARAM(wparam), lparam );
+                }
+            }
+            LeaveCriticalSection( &dinput->crit );
+        }
+        LeaveCriticalSection( &dinput_hook_crit );
+    }
+
+    return DefWindowProcW(hwnd, msg, wparam, lparam);
+}
+
+static void register_di_em_win_class(void)
+{
+    static WNDCLASSEXW class;
+
+    ZeroMemory(&class, sizeof(class));
+    class.cbSize = sizeof(class);
+    class.lpfnWndProc = di_em_win_wndproc;
+    class.hInstance = DINPUT_instance;
+    class.lpszClassName = di_em_winW;
+
+    if (!(di_em_win_class = RegisterClassExW( &class )))
+        WARN( "Unable to register message window class\n" );
+}
+
+static void unregister_di_em_win_class(void)
+{
+    if (!di_em_win_class)
+        return;
+
+    if (!UnregisterClassW( MAKEINTRESOURCEW( di_em_win_class ), DINPUT_instance ))
+        WARN( "Unable to unregister message window class\n" );
+}
+
 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion)
 {
     if (!This->initialized)
@@ -1706,6 +1763,9 @@ static DWORD WINAPI hook_thread_proc(void *param)
     static HHOOK kbd_hook, mouse_hook;
     MSG msg;
 
+    di_em_win = CreateWindowW( MAKEINTRESOURCEW(di_em_win_class), di_em_winW,
+                               0, 0, 0, 0, 0, HWND_MESSAGE, 0, DINPUT_instance, NULL );
+
     /* Force creation of the message queue */
     PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE );
     SetEvent(param);
@@ -1738,7 +1798,7 @@ static DWORD WINAPI hook_thread_proc(void *param)
                 EnterCriticalSection( &dinput->crit );
                 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry )
                 {
-                    if (!dev->acquired || !dev->event_proc) continue;
+                    if (!dev->acquired || !dev->event_proc || dev->use_raw_input) continue;
 
                     if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ))
                         kbd_cnt++;
@@ -1770,6 +1830,9 @@ static DWORD WINAPI hook_thread_proc(void *param)
         DispatchMessageW(&msg);
     }
 
+    DestroyWindow( di_em_win );
+    di_em_win = NULL;
+
     FreeLibraryAndExitThread(DINPUT_instance, 0);
 }
 
@@ -1851,6 +1914,18 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired)
         hook_thread_event = NULL;
     }
 
+    if (dev->use_raw_input)
+    {
+        if (acquired)
+            dev->raw_device.dwFlags = RIDEV_INPUTSINK;
+        else
+            dev->raw_device.dwFlags = RIDEV_REMOVE;
+        dev->raw_device.hwndTarget = di_em_win;
+
+        if (!RegisterRawInputDevices( &dev->raw_device, 1, sizeof(RAWINPUTDEVICE) ))
+            WARN( "Unable to (un)register raw device %x:%x\n", dev->raw_device.usUsagePage, dev->raw_device.usUsage );
+    }
+
     PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 );
 
     LeaveCriticalSection(&dinput_hook_crit);
@@ -1877,9 +1952,11 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved)
       case DLL_PROCESS_ATTACH:
         DisableThreadLibraryCalls(inst);
         DINPUT_instance = inst;
+        register_di_em_win_class();
         break;
       case DLL_PROCESS_DETACH:
         if (reserved) break;
+        unregister_di_em_win_class();
         DeleteCriticalSection(&dinput_hook_crit);
         break;
     }
-- 
2.23.0.rc1




More information about the wine-devel mailing list