Skip to content

Commit f4d41b9

Browse files
Merge pull request GloriousEggroll#131 from loathingKernel/gloriouseggroll_master_dai_xinput
patches: update Dragon Age Inquisition xinput patch
2 parents dfb69db + bab60a6 commit f4d41b9

File tree

1 file changed

+83
-34
lines changed

1 file changed

+83
-34
lines changed

patches/game-patches/dai_xinput.patch

+83-34
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,88 @@
1-
From 98744d243b9ef173ab0c82a9b3e13e675175589b Mon Sep 17 00:00:00 2001
2-
From: GloriousEggroll <[email protected]>
3-
Date: Sat, 27 Jul 2024 18:59:05 -0600
4-
Subject: [PATCH] dai_xinput_fix
1+
From 4fd6c1a286dd2babd098decf045522be1dff5656 Mon Sep 17 00:00:00 2001
2+
From: Cameron Moore <[email protected]>
3+
Date: Sat, 3 Feb 2024 21:21:50 -0500
4+
Subject: [PATCH] user32: [GAMEFIX] Fix xinput support for Dragon Age
5+
Inquisition
56

7+
user32: [GAMEFIX] 1/2 Dragon Age Inquisition: fix xinput support
8+
9+
https://bugs.winehq.org/show_bug.cgi?id=47070
10+
11+
I'm not completely sure on the specifics of why the bug happens,
12+
but there are two main threads involved. Thread A owns the window
13+
object for the game. Thread B makes all the calls to XInputGetState.
14+
However, Thread B checks if the window has focus to receive keyboard
15+
inputs every frame. Thread B calls AttachThreadInput to attach its
16+
message queue to the Thread A's window a few times before the bug
17+
starts occurring along with one separate time at the start where
18+
Thread A attaches Thread B's message queue to the window as well.
19+
The message queue is detached one last time and then Thread B no
20+
longer has access to the window.
21+
22+
My workaround checks GetFocus for when it starts receiving Null
23+
for a response (meaning it does not have access to a window anymore).
24+
Prior to this, AttachThreadInput stores the IDs of the two threads
25+
which call the function the very first time (hopefully this works
26+
with the EA App as I've been debugging this with Origin which doesn't
27+
seem to call either of the two WINAPI functions as long as you load
28+
straight into the game from the Origin library menu). When GetFocus
29+
realizes it does not have a window for the thread, it calls
30+
AttachThreadInput with the two thread IDs. This allows Thread B to
31+
access the window, which let's GetFocus return the proper window
32+
handle, which then let's the program access XInputGetState meaning
33+
the controller finally works.
34+
35+
Anyway, as far as the final cause of the bug: it might be because
36+
of thread prioritization causing Thread B to AttachThreadInput to
37+
be called by it last as the only time Thread A calls it, it does
38+
not detach the message queue afterwards. This leads me to believe
39+
that the bug might just be caused by incomplete wine
40+
functionality / stubs. Although, this part is speculation.
41+
42+
user32: [GAMEFIX] 2/2 Dragon Age Inquisition: fix xinput support
43+
44+
Wrap hack with a SteamGameId check and cache it.
645
---
7-
dlls/user32/input.c | 15 ++++++++++++++-
8-
dlls/win32u/input.c | 32 ++++++++++++++++++++++++++++++++
9-
2 files changed, 46 insertions(+), 1 deletion(-)
46+
dlls/user32/input.c | 22 +++++++++++++++++++++-
47+
dlls/win32u/input.c | 37 +++++++++++++++++++++++++++++++++++++
48+
2 files changed, 58 insertions(+), 1 deletion(-)
1049

1150
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
12-
index f91b65a5f56..02241110eae 100644
51+
index f91b65a5f56..dda952262ac 100644
1352
--- a/dlls/user32/input.c
1453
+++ b/dlls/user32/input.c
15-
@@ -814,8 +814,21 @@ HWND WINAPI GetActiveWindow(void)
54+
@@ -814,8 +814,28 @@ HWND WINAPI GetActiveWindow(void)
1655
HWND WINAPI GetFocus(void)
1756
{
1857
GUITHREADINFO info;
1958
+ HWND retValueWindow;
2059
+ static HWND prev = 0;
2160
+ const char *sgi;
61+
+ static int is_DragonAgeInquis = -1;
62+
+
2263
info.cbSize = sizeof(info);
2364
- return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0;
2465
+
2566
+ retValueWindow = NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0;
2667
+
27-
+ if ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690")) {
28-
+ if (retValueWindow == 0 && prev != 0)
29-
+ NtUserAttachThreadInput(0, 0, 1);
30-
+ else
31-
+ prev = retValueWindow;
68+
+ if (is_DragonAgeInquis)
69+
+ {
70+
+ if ((is_DragonAgeInquis == 1) ||
71+
+ (is_DragonAgeInquis = ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690"))))
72+
+ {
73+
+ if (retValueWindow == 0 && prev != 0)
74+
+ NtUserAttachThreadInput(0, 0, 1);
75+
+ else
76+
+ prev = retValueWindow;
77+
+ }
3278
+ }
3379
+
3480
+ return retValueWindow;
3581
}
3682

3783

3884
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
39-
index d67f462359c..dee6c5acf57 100644
85+
index 6268c978dab..1dbb6690c03 100644
4086
--- a/dlls/win32u/input.c
4187
+++ b/dlls/win32u/input.c
4288
@@ -30,6 +30,8 @@
@@ -48,7 +94,7 @@ index d67f462359c..dee6c5acf57 100644
4894
#include "ntstatus.h"
4995
#define WIN32_NO_STATUS
5096
#include "win32u_private.h"
51-
@@ -596,6 +598,38 @@ HWND get_focus(void)
97+
@@ -596,6 +598,41 @@ HWND get_focus(void)
5298
BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach )
5399
{
54100
BOOL ret;
@@ -58,35 +104,38 @@ index d67f462359c..dee6c5acf57 100644
58104
+ static char processNameForHack[16];
59105
+ static const char* DAIprocessName = "DragonAgeInquis";
60106
+ static const char* DAIGameLoopName = "GameLoop";
107+
+ static int is_DragonAgeInquis = -1;
61108
+ const char *sgi;
62109
+
63-
+ if ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690"))
110+
+ if (is_DragonAgeInquis)
64111
+ {
65-
+ prctl(PR_GET_NAME, processNameForHack);
66-
+
67-
+ TRACE("Process Name: %s\n", processNameForHack);
68-
+
69-
+ if (strncmp(DAIprocessName, processNameForHack, 15) == 0 || strncmp(DAIGameLoopName, processNameForHack, 8) == 0)
112+
+ if ((is_DragonAgeInquis == 1) ||
113+
+ (is_DragonAgeInquis = ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690"))))
70114
+ {
71-
+ if (!visited)
115+
+ prctl(PR_GET_NAME, processNameForHack);
116+
+ TRACE("Process Name: %s\n", processNameForHack);
117+
+ if (strncmp(DAIprocessName, processNameForHack, 15) == 0 || strncmp(DAIGameLoopName, processNameForHack, 8) == 0)
72118
+ {
73-
+ TRACE("First Visit Process Name: %s\n", processNameForHack);
74-
+ fromThreadForHack = from;
75-
+ toThreadForHack = to;
76-
+ visited = 1;
77-
+ }
119+
+ if (!visited)
120+
+ {
121+
+ TRACE("First Visit Process Name: %s\n", processNameForHack);
122+
+ fromThreadForHack = from;
123+
+ toThreadForHack = to;
124+
+ visited = 1;
125+
+ }
78126
+
79-
+ if (from == 0 && to == 0 && visited)
80-
+ {
81-
+ TRACE("00 Process Name: %s\n", processNameForHack);
82-
+ from = fromThreadForHack;
83-
+ to = toThreadForHack;
127+
+ if (from == 0 && to == 0 && visited)
128+
+ {
129+
+ TRACE("00 Process Name: %s\n", processNameForHack);
130+
+ from = fromThreadForHack;
131+
+ to = toThreadForHack;
132+
+ }
84133
+ }
85134
+ }
86135
+ }
87136

88137
SERVER_START_REQ( attach_thread_input )
89138
{
90139
--
91-
2.45.2
140+
2.48.1
92141

0 commit comments

Comments
 (0)