Based on a patch from Andrew Eikum aeikum@codeweavers.com.
Dark Souls Remasters checks for xinput devices when it receives a WM_DEVICECHANGE message. We would only poll for new devices if it had been at least 2 seconds since the last check. So often, DS would receive the message, but we would refuse to poll for devices, so the game would think no controller was present.
This commit fixes that by also subscribing to event notifications and triggering a poll.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_1/Makefile.in | 2 +- dlls/xinput1_2/Makefile.in | 2 +- dlls/xinput1_3/Makefile.in | 2 +- dlls/xinput1_3/main.c | 54 ++++++++++++++++++++++++++++++++++-- dlls/xinput1_4/Makefile.in | 2 +- dlls/xinput9_1_0/Makefile.in | 2 +- 6 files changed, 57 insertions(+), 7 deletions(-)
diff --git a/dlls/xinput1_1/Makefile.in b/dlls/xinput1_1/Makefile.in index 328435a110f..88d230ef7b2 100644 --- a/dlls/xinput1_1/Makefile.in +++ b/dlls/xinput1_1/Makefile.in @@ -1,6 +1,6 @@ MODULE = xinput1_1.dll PARENTSRC = ../xinput1_3 -DELAYIMPORTS = hid setupapi advapi32 +DELAYIMPORTS = hid setupapi advapi32 user32
C_SRCS = \ main.c diff --git a/dlls/xinput1_2/Makefile.in b/dlls/xinput1_2/Makefile.in index e66b6e67261..4e6a1ec1348 100644 --- a/dlls/xinput1_2/Makefile.in +++ b/dlls/xinput1_2/Makefile.in @@ -1,6 +1,6 @@ MODULE = xinput1_2.dll PARENTSRC = ../xinput1_3 -DELAYIMPORTS = hid setupapi advapi32 +DELAYIMPORTS = hid setupapi advapi32 user32
C_SRCS = \ main.c diff --git a/dlls/xinput1_3/Makefile.in b/dlls/xinput1_3/Makefile.in index 15ce3a691dd..7f630d8c5f6 100644 --- a/dlls/xinput1_3/Makefile.in +++ b/dlls/xinput1_3/Makefile.in @@ -1,6 +1,6 @@ MODULE = xinput1_3.dll IMPORTLIB = xinput -DELAYIMPORTS = hid setupapi advapi32 +DELAYIMPORTS = hid setupapi advapi32 user32
C_SRCS = \ main.c diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index f3ad7d1d360..74f3f8afde8 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -33,6 +33,7 @@ #include "winnls.h" #include "winternl.h"
+#include "dbt.h" #include "setupapi.h" #include "devpkey.h" #include "hidusage.h" @@ -128,6 +129,8 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] = {{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }}, };
+static HMODULE xinput_instance; +static HANDLE start_event; static HANDLE stop_event; static HANDLE done_event; static HANDLE update_event; @@ -648,14 +651,52 @@ static void read_controller_state(struct xinput_controller *controller) LeaveCriticalSection(&controller->crit); }
+static LRESULT CALLBACK xinput_devnotify_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + if (msg == WM_DEVICECHANGE && wparam == DBT_DEVICEARRIVAL) + { + EnterCriticalSection(&xinput_crit); + update_controller_list(); + LeaveCriticalSection(&xinput_crit); + } + return DefWindowProcW(hwnd, msg, wparam, lparam); +} + 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, + }; + HWND hwnd; + MSG msg; + + RegisterClassExW(&cls); + hwnd = CreateWindowExW(0, cls.lpszClassName, NULL, 0, 0, 0, 0, 0, + HWND_MESSAGE, NULL, NULL, NULL); + RegisterDeviceNotificationW(hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); + SetEvent(start_event);
do { + while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + EnterCriticalSection(&xinput_crit); if (ret == WAIT_TIMEOUT) update_controller_list(); if (ret < count - 2) read_controller_state(devices[ret]); @@ -677,7 +718,11 @@ static DWORD WINAPI hid_update_thread_proc(void *param) events[count++] = stop_event; LeaveCriticalSection(&xinput_crit); } - while ((ret = WaitForMultipleObjectsEx( count, events, FALSE, 2000, TRUE )) < count - 1 || ret == WAIT_TIMEOUT); + while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) < count - 1 || + ret == count || ret == WAIT_TIMEOUT); + + DestroyWindow(hwnd); + UnregisterClassW(cls.lpszClassName, xinput_instance);
if (ret != count - 1) ERR("update thread exited unexpectedly, ret %u\n", ret); SetEvent(done_event); @@ -688,17 +733,21 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void { HANDLE thread;
+ start_event = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!start_event) ERR("failed to create start event, error %u\n", GetLastError()); + stop_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!stop_event) ERR("failed to create stop event, error %u\n", GetLastError());
done_event = CreateEventA(NULL, FALSE, FALSE, NULL); - if (!done_event) ERR("failed to create stop event, error %u\n", GetLastError()); + if (!done_event) ERR("failed to create done event, error %u\n", GetLastError());
update_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!update_event) ERR("failed to create update event, error %u\n", GetLastError());
thread = CreateThread(NULL, 0, hid_update_thread_proc, NULL, 0, NULL); if (!thread) ERR("failed to create update thread, error %u\n", GetLastError()); + WaitForSingleObject(start_event, INFINITE); CloseHandle(thread);
/* do it once now, to resolve delayed imports and populate the initial list */ @@ -740,6 +789,7 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) switch (reason) { case DLL_PROCESS_ATTACH: + xinput_instance = inst; DisableThreadLibraryCalls(inst); break; case DLL_PROCESS_DETACH: diff --git a/dlls/xinput1_4/Makefile.in b/dlls/xinput1_4/Makefile.in index b21a3d3ce53..7745b21139a 100644 --- a/dlls/xinput1_4/Makefile.in +++ b/dlls/xinput1_4/Makefile.in @@ -1,6 +1,6 @@ MODULE = xinput1_4.dll PARENTSRC = ../xinput1_3 -DELAYIMPORTS = hid setupapi advapi32 +DELAYIMPORTS = hid setupapi advapi32 user32
C_SRCS = \ main.c diff --git a/dlls/xinput9_1_0/Makefile.in b/dlls/xinput9_1_0/Makefile.in index f014e67dea3..a28e19c546c 100644 --- a/dlls/xinput9_1_0/Makefile.in +++ b/dlls/xinput9_1_0/Makefile.in @@ -1,6 +1,6 @@ MODULE = xinput9_1_0.dll PARENTSRC = ../xinput1_3 -DELAYIMPORTS = hid setupapi advapi32 +DELAYIMPORTS = hid setupapi advapi32 user32
C_SRCS = \ main.c