Skip to content

Commit

Permalink
Merge pull request #131 from loathingKernel/gloriouseggroll_master_da…
Browse files Browse the repository at this point in the history
…i_xinput

patches: update Dragon Age Inquisition xinput patch
  • Loading branch information
GloriousEggroll authored Feb 9, 2025
2 parents dfb69db + bab60a6 commit f4d41b9
Showing 1 changed file with 83 additions and 34 deletions.
117 changes: 83 additions & 34 deletions patches/game-patches/dai_xinput.patch
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 @@
Expand All @@ -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;
Expand All @@ -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

0 comments on commit f4d41b9

Please sign in to comment.