From: "Rémi Bernon" Subject: [PATCH v2 4/6] dinput8: Add support for rawinput based devices. Message-Id: <20200703080248.164268-4-rbernon@codeweavers.com> Date: Fri, 3 Jul 2020 10:02:46 +0200 In-Reply-To: <20200703080248.164268-1-rbernon@codeweavers.com> References: <20200703080248.164268-1-rbernon@codeweavers.com> This adds a message window that will be used as the rawinput target window for WM_INPUT messages. Signed-off-by: Rémi Bernon --- v2: Rewrite GetRawInputData return value check. dlls/dinput/device_private.h | 3 ++ dlls/dinput/dinput_main.c | 77 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index fe5644f21c7..2fac4f0e61e 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -69,6 +69,9 @@ struct IDirectInputDeviceImpl HWND win; int acquired; + 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; /* valid size of the queue */ 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 2e561502406..cd1a11b02fb 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -97,6 +97,9 @@ static const struct dinput_device *dinput_devices[] = HINSTANCE DINPUT_instance; +static const WCHAR di_em_win_w[] = {'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 ); @@ -637,6 +640,45 @@ 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) +{ + IDirectInputDeviceImpl *dev; + RAWINPUT ri; + UINT size = sizeof(ri); + int rim = GET_RAWINPUT_CODE_WPARAM( wparam ); + + TRACE( "%p %d %lx %lx\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_INPUT && (rim == RIM_INPUT || rim == RIM_INPUTSINK)) + { + size = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER) ); + if (size == (UINT)-1 || size < sizeof(RAWINPUTHEADER)) + WARN( "Unable to read raw input data\n" ); + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static void register_di_em_win_class(void) +{ + WNDCLASSEXW class; + + memset(&class, 0, sizeof(class)); + class.cbSize = sizeof(class); + class.lpfnWndProc = di_em_win_wndproc; + class.hInstance = DINPUT_instance; + class.lpszClassName = di_em_win_w; + + if (!RegisterClassExW( &class ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) + WARN( "Unable to register message window class\n" ); +} + +static void unregister_di_em_win_class(void) +{ + if (!UnregisterClassW( di_em_win_w, NULL ) && GetLastError() != ERROR_CLASS_DOES_NOT_EXIST) + WARN( "Unable to unregister message window class\n" ); +} + static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion) { if (!This->initialized) @@ -1668,11 +1710,13 @@ static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) EnterCriticalSection( &dinput_hook_crit ); LIST_FOR_EACH_ENTRY( dev, &acquired_mouse_list, IDirectInputDeviceImpl, entry ) { + if (dev->use_raw_input) continue; TRACE("calling dinput_mouse_hook (%p %lx %lx)\n", dev, wparam, lparam); skip |= dinput_mouse_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam ); } LIST_FOR_EACH_ENTRY( dev, &acquired_keyboard_list, IDirectInputDeviceImpl, entry ) { + if (dev->use_raw_input) continue; TRACE("calling dinput_keyboard_hook (%p %lx %lx)\n", dev, wparam, lparam); skip |= dinput_keyboard_hook( &dev->IDirectInputDevice8A_iface, wparam, lparam ); } @@ -1728,6 +1772,9 @@ static DWORD WINAPI hook_thread_proc(void *param) static HHOOK kbd_hook, mouse_hook; MSG msg; + di_em_win = CreateWindowW( di_em_win_w, di_em_win_w, 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); @@ -1778,6 +1825,9 @@ static DWORD WINAPI hook_thread_proc(void *param) DispatchMessageW(&msg); } + DestroyWindow( di_em_win ); + di_em_win = NULL; + FreeLibraryAndExitThread(DINPUT_instance, 0); } @@ -1860,6 +1910,31 @@ void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) hook_thread_event = NULL; } + if (dev->use_raw_input) + { + if (acquired) + { + dev->raw_device.dwFlags = 0; + if (dev->dwCoopLevel & DISCL_BACKGROUND) + dev->raw_device.dwFlags |= RIDEV_INPUTSINK; + if (dev->dwCoopLevel & DISCL_EXCLUSIVE) + dev->raw_device.dwFlags |= RIDEV_NOLEGACY; + if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 2) + dev->raw_device.dwFlags |= RIDEV_CAPTUREMOUSE; + if ((dev->dwCoopLevel & DISCL_EXCLUSIVE) && dev->raw_device.usUsage == 6) + dev->raw_device.dwFlags |= RIDEV_NOHOTKEYS; + dev->raw_device.hwndTarget = di_em_win; + } + else + { + dev->raw_device.dwFlags = RIDEV_REMOVE; + dev->raw_device.hwndTarget = NULL; + } + + 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 ); + } + if (acquired) hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL ); PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, (LPARAM)hook_change_finished_event ); @@ -1894,9 +1969,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.27.0