Instead of doing it lazily, which is more likely to be after the game has registered theirs. As the message handling order is the same as the registration, XInput may end updating its device list only too late, every time.
Some games register device notifications and call XInputGetCapabilities or XInputGetState from their window proc, expecting XInput controller list to be updated already. If the controller is missing they won't try calling XInput functions again until another WM_DEVICECHANGE message is received.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 55 ++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 506802d142a..4536b027dc2 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -119,7 +119,8 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] = {{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }}, };
-static HMODULE xinput_instance; +static HDEVNOTIFY update_devnotify; +static HWND update_hwnd; static HANDLE start_event; static HANDLE stop_event; static HANDLE done_event; @@ -654,34 +655,14 @@ static DWORD WINAPI hid_update_thread_proc(void *param) struct xinput_controller *devices[XUSER_MAX_COUNT + 2]; HANDLE events[XUSER_MAX_COUNT + 2]; DWORD i, count = 2, ret = WAIT_TIMEOUT; - DEV_BROADCAST_DEVICEINTERFACE_W filter = - { - .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W), - .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE, - .dbcc_classguid = GUID_DEVINTERFACE_WINEXINPUT, - }; - WNDCLASSEXW cls = - { - .cbSize = sizeof(WNDCLASSEXW), - .hInstance = xinput_instance, - .lpszClassName = L"__wine_xinput_devnotify", - .lpfnWndProc = xinput_devnotify_wndproc, - }; - HDEVNOTIFY notif; - HWND hwnd; MSG msg;
- RegisterClassExW(&cls); - hwnd = CreateWindowExW(0, cls.lpszClassName, NULL, 0, 0, 0, 0, 0, - HWND_MESSAGE, NULL, NULL, NULL); - notif = RegisterDeviceNotificationW(hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); - update_controller_list(); SetEvent(start_event);
do { - if (ret == count) while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); + if (ret == count) while (PeekMessageW(&msg, update_hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg); if (ret == WAIT_TIMEOUT) update_controller_list(); if (ret < count - 2) read_controller_state(devices[ret]);
@@ -704,10 +685,6 @@ static DWORD WINAPI hid_update_thread_proc(void *param) while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) < count - 1 || ret == count || ret == WAIT_TIMEOUT);
- UnregisterDeviceNotification(notif); - DestroyWindow(hwnd); - UnregisterClassW(cls.lpszClassName, xinput_instance); - if (ret != count - 1) ERR("update thread exited unexpectedly, ret %u\n", ret); SetEvent(done_event); return ret; @@ -765,15 +742,39 @@ static void controller_unlock(struct xinput_controller *controller)
BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { + DEV_BROADCAST_DEVICEINTERFACE_W filter = + { + .dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE_W), + .dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE, + .dbcc_classguid = GUID_DEVINTERFACE_WINEXINPUT, + }; + WNDCLASSEXW class = + { + .cbSize = sizeof(WNDCLASSEXW), + .hInstance = inst, + .lpszClassName = L"__wine_xinput_devnotify", + .lpfnWndProc = xinput_devnotify_wndproc, + }; + + TRACE("inst %p, reason %u, reserved %p.\n", inst, reason, reserved); + switch (reason) { case DLL_PROCESS_ATTACH: - xinput_instance = inst; DisableThreadLibraryCalls(inst); + + RegisterClassExW(&class); + update_hwnd = CreateWindowExW(0, class.lpszClassName, NULL, 0, 0, 0, 0, 0, + HWND_MESSAGE, NULL, NULL, NULL); + update_devnotify = RegisterDeviceNotificationW(update_hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); break; case DLL_PROCESS_DETACH: if (reserved) break; stop_update_thread(); + + UnregisterDeviceNotification(update_devnotify); + DestroyWindow(update_hwnd); + UnregisterClassW(class.lpszClassName, class.hInstance); break; } return TRUE;