[PATCH v2 2/2] xinput1_3: Register for device notifications to update controller list.

Rémi Bernon rbernon at codeweavers.com
Thu Oct 7 05:02:02 CDT 2021


Based on a patch from Andrew Eikum <aeikum at 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 at 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
-- 
2.33.0




More information about the wine-devel mailing list