forked from ValveSoftware/Proton
-
-
Notifications
You must be signed in to change notification settings - Fork 274
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #131 from loathingKernel/gloriouseggroll_master_da…
…i_xinput patches: update Dragon Age Inquisition xinput patch
- Loading branch information
Showing
1 changed file
with
83 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,88 @@ | ||
From 98744d243b9ef173ab0c82a9b3e13e675175589b Mon Sep 17 00:00:00 2001 | ||
From: GloriousEggroll <[email protected]> | ||
Date: Sat, 27 Jul 2024 18:59:05 -0600 | ||
Subject: [PATCH] dai_xinput_fix | ||
From 4fd6c1a286dd2babd098decf045522be1dff5656 Mon Sep 17 00:00:00 2001 | ||
From: Cameron Moore <[email protected]> | ||
Date: Sat, 3 Feb 2024 21:21:50 -0500 | ||
Subject: [PATCH] user32: [GAMEFIX] Fix xinput support for Dragon Age | ||
Inquisition | ||
|
||
user32: [GAMEFIX] 1/2 Dragon Age Inquisition: fix xinput support | ||
|
||
https://bugs.winehq.org/show_bug.cgi?id=47070 | ||
|
||
I'm not completely sure on the specifics of why the bug happens, | ||
but there are two main threads involved. Thread A owns the window | ||
object for the game. Thread B makes all the calls to XInputGetState. | ||
However, Thread B checks if the window has focus to receive keyboard | ||
inputs every frame. Thread B calls AttachThreadInput to attach its | ||
message queue to the Thread A's window a few times before the bug | ||
starts occurring along with one separate time at the start where | ||
Thread A attaches Thread B's message queue to the window as well. | ||
The message queue is detached one last time and then Thread B no | ||
longer has access to the window. | ||
|
||
My workaround checks GetFocus for when it starts receiving Null | ||
for a response (meaning it does not have access to a window anymore). | ||
Prior to this, AttachThreadInput stores the IDs of the two threads | ||
which call the function the very first time (hopefully this works | ||
with the EA App as I've been debugging this with Origin which doesn't | ||
seem to call either of the two WINAPI functions as long as you load | ||
straight into the game from the Origin library menu). When GetFocus | ||
realizes it does not have a window for the thread, it calls | ||
AttachThreadInput with the two thread IDs. This allows Thread B to | ||
access the window, which let's GetFocus return the proper window | ||
handle, which then let's the program access XInputGetState meaning | ||
the controller finally works. | ||
|
||
Anyway, as far as the final cause of the bug: it might be because | ||
of thread prioritization causing Thread B to AttachThreadInput to | ||
be called by it last as the only time Thread A calls it, it does | ||
not detach the message queue afterwards. This leads me to believe | ||
that the bug might just be caused by incomplete wine | ||
functionality / stubs. Although, this part is speculation. | ||
|
||
user32: [GAMEFIX] 2/2 Dragon Age Inquisition: fix xinput support | ||
|
||
Wrap hack with a SteamGameId check and cache it. | ||
--- | ||
dlls/user32/input.c | 15 ++++++++++++++- | ||
dlls/win32u/input.c | 32 ++++++++++++++++++++++++++++++++ | ||
2 files changed, 46 insertions(+), 1 deletion(-) | ||
dlls/user32/input.c | 22 +++++++++++++++++++++- | ||
dlls/win32u/input.c | 37 +++++++++++++++++++++++++++++++++++++ | ||
2 files changed, 58 insertions(+), 1 deletion(-) | ||
|
||
diff --git a/dlls/user32/input.c b/dlls/user32/input.c | ||
index f91b65a5f56..02241110eae 100644 | ||
index f91b65a5f56..dda952262ac 100644 | ||
--- a/dlls/user32/input.c | ||
+++ b/dlls/user32/input.c | ||
@@ -814,8 +814,21 @@ HWND WINAPI GetActiveWindow(void) | ||
@@ -814,8 +814,28 @@ HWND WINAPI GetActiveWindow(void) | ||
HWND WINAPI GetFocus(void) | ||
{ | ||
GUITHREADINFO info; | ||
+ HWND retValueWindow; | ||
+ static HWND prev = 0; | ||
+ const char *sgi; | ||
+ static int is_DragonAgeInquis = -1; | ||
+ | ||
info.cbSize = sizeof(info); | ||
- return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0; | ||
+ | ||
+ retValueWindow = NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndFocus : 0; | ||
+ | ||
+ if ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690")) { | ||
+ if (retValueWindow == 0 && prev != 0) | ||
+ NtUserAttachThreadInput(0, 0, 1); | ||
+ else | ||
+ prev = retValueWindow; | ||
+ if (is_DragonAgeInquis) | ||
+ { | ||
+ if ((is_DragonAgeInquis == 1) || | ||
+ (is_DragonAgeInquis = ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690")))) | ||
+ { | ||
+ if (retValueWindow == 0 && prev != 0) | ||
+ NtUserAttachThreadInput(0, 0, 1); | ||
+ else | ||
+ prev = retValueWindow; | ||
+ } | ||
+ } | ||
+ | ||
+ return retValueWindow; | ||
} | ||
|
||
|
||
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c | ||
index d67f462359c..dee6c5acf57 100644 | ||
index 6268c978dab..1dbb6690c03 100644 | ||
--- a/dlls/win32u/input.c | ||
+++ b/dlls/win32u/input.c | ||
@@ -30,6 +30,8 @@ | ||
|
@@ -48,7 +94,7 @@ index d67f462359c..dee6c5acf57 100644 | |
#include "ntstatus.h" | ||
#define WIN32_NO_STATUS | ||
#include "win32u_private.h" | ||
@@ -596,6 +598,38 @@ HWND get_focus(void) | ||
@@ -596,6 +598,41 @@ HWND get_focus(void) | ||
BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ) | ||
{ | ||
BOOL ret; | ||
|
@@ -58,35 +104,38 @@ index d67f462359c..dee6c5acf57 100644 | |
+ static char processNameForHack[16]; | ||
+ static const char* DAIprocessName = "DragonAgeInquis"; | ||
+ static const char* DAIGameLoopName = "GameLoop"; | ||
+ static int is_DragonAgeInquis = -1; | ||
+ const char *sgi; | ||
+ | ||
+ if ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690")) | ||
+ if (is_DragonAgeInquis) | ||
+ { | ||
+ prctl(PR_GET_NAME, processNameForHack); | ||
+ | ||
+ TRACE("Process Name: %s\n", processNameForHack); | ||
+ | ||
+ if (strncmp(DAIprocessName, processNameForHack, 15) == 0 || strncmp(DAIGameLoopName, processNameForHack, 8) == 0) | ||
+ if ((is_DragonAgeInquis == 1) || | ||
+ (is_DragonAgeInquis = ((sgi = getenv("SteamGameId")) && !strcmp(sgi, "1222690")))) | ||
+ { | ||
+ if (!visited) | ||
+ prctl(PR_GET_NAME, processNameForHack); | ||
+ TRACE("Process Name: %s\n", processNameForHack); | ||
+ if (strncmp(DAIprocessName, processNameForHack, 15) == 0 || strncmp(DAIGameLoopName, processNameForHack, 8) == 0) | ||
+ { | ||
+ TRACE("First Visit Process Name: %s\n", processNameForHack); | ||
+ fromThreadForHack = from; | ||
+ toThreadForHack = to; | ||
+ visited = 1; | ||
+ } | ||
+ if (!visited) | ||
+ { | ||
+ TRACE("First Visit Process Name: %s\n", processNameForHack); | ||
+ fromThreadForHack = from; | ||
+ toThreadForHack = to; | ||
+ visited = 1; | ||
+ } | ||
+ | ||
+ if (from == 0 && to == 0 && visited) | ||
+ { | ||
+ TRACE("00 Process Name: %s\n", processNameForHack); | ||
+ from = fromThreadForHack; | ||
+ to = toThreadForHack; | ||
+ if (from == 0 && to == 0 && visited) | ||
+ { | ||
+ TRACE("00 Process Name: %s\n", processNameForHack); | ||
+ from = fromThreadForHack; | ||
+ to = toThreadForHack; | ||
+ } | ||
+ } | ||
+ } | ||
+ } | ||
|
||
SERVER_START_REQ( attach_thread_input ) | ||
{ | ||
-- | ||
2.45.2 | ||
2.48.1 | ||
|