spice2x / spice2x.github.io

🌶️ spice2x is a spicier fork of SpiceTools with hundreds of bug fixes and new features 🌶️
https://spice2x.github.io/
GNU General Public License v3.0
116 stars 2 forks source link

[TDJ] Enhancements to Windowed Subscreen #194

Closed guardianblue closed 4 months ago

guardianblue commented 4 months ago
  1. Fix incorrect touch hook setup in TDJ
  2. (TDJ/SDVX) Bring back minimize button, but make maximize button disabled
  3. (TDJ/SDVX) Prevent subscreen window from being closed

Tested with:

  1. TDJ windowed
  2. TDJ windowed no sub
  3. TDJ no sub
  4. SDVX windowed

wsub-fix2.patch

commit ee2c24d7be75fb88c90ce5da16a988547f91fa65
Author: guardianblue <a@example.com>
Date:   Wed Jul 10 22:03:58 2024 +0100

    TDJ/SDVX Add hook to Windowed Subscreen to prevent it from being closed

diff --git a/hooks/graphics/graphics.cpp b/hooks/graphics/graphics.cpp
index 32bea1d..c763594 100644
--- a/hooks/graphics/graphics.cpp
+++ b/hooks/graphics/graphics.cpp
@@ -31,12 +31,14 @@ struct CaptureData {
 };

 HWND TDJ_SUBSCREEN_WINDOW = nullptr;
+HWND SDVX_SUBSCREEN_WINDOW = nullptr;

 // icon
 static HICON WINDOW_ICON = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(MAINICON));

 // state
 static WNDPROC WNDPROC_ORIG = nullptr;
+static WNDPROC WSUB_WNDPROC_ORIG = nullptr;
 static std::vector<WNDPROC> WNDPROC_CUSTOM {};
 static bool GRAPHICS_SCREENSHOT_TRIGGER = false;
 static std::set<int> GRAPHICS_SCREENS { 0 };
@@ -240,6 +242,16 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
     return CallWindowProcA(WNDPROC_ORIG, hWnd, uMsg, wParam, lParam);
 }

+// window procedure for subscreen
+// this might be replaced by spicetouch hook later
+static LRESULT CALLBACK WsubWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+    if (uMsg == WM_CLOSE) {
+        log_misc("graphics", "ignore WM_CLOSE for subscreen window");
+        return false;
+    }
+    return CallWindowProcA(WSUB_WNDPROC_ORIG, hWnd, uMsg, wParam, lParam);
+}
+
 static LONG WINAPI ChangeDisplaySettingsA_hook(DEVMODEA *lpDevMode, DWORD dwflags) {
     log_misc("graphics", "ChangeDisplaySettingsA hook hit");

@@ -350,11 +362,11 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
     }

     bool is_tdj_sub_window = avs::game::is_model("LDJ") && GRAPHICS_WINDOWED && window_name.ends_with(" sub");
+    bool is_sdvx_sub_window = avs::game::is_model("KFC") && GRAPHICS_WINDOWED && window_name.ends_with(" Sub Screen");

-    // TDJ windowed mode with subscreen: hide system button to avoid accidentally closing it
-    if (is_tdj_sub_window && GRAPHICS_IIDX_WSUB) {
-        dwStyle &= ~(WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU | WS_MINIMIZE);
-        dwStyle |= WS_VISIBLE;
+    // TDJ windowed mode with subscreen: hide maximize button
+    if ((is_tdj_sub_window && GRAPHICS_IIDX_WSUB) || is_sdvx_sub_window) {
+        dwStyle &= ~(WS_MAXIMIZEBOX);
     }

     // call original
@@ -362,9 +374,20 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
             hWndParent, hMenu, hInstance, lpParam);
     GRAPHICS_WINDOWS.push_back(result);

-    // TDJ windowed mode: remember the subscreen window handle for later
     if (is_tdj_sub_window) {
+        // TDJ windowed mode: remember the subscreen window handle for later
         TDJ_SUBSCREEN_WINDOW = result;
+    
+        // hook for preventing the closing of subscreen window
+        if (GRAPHICS_IIDX_WSUB) {
+            graphics_hook_subscreen_window(TDJ_SUBSCREEN_WINDOW);
+        }
+    }
+
+    // hook for preventing the closing of subscreen window
+    if (is_sdvx_sub_window) {
+        SDVX_SUBSCREEN_WINDOW = result;
+        graphics_hook_subscreen_window(SDVX_SUBSCREEN_WINDOW);
     }

     return result;
@@ -827,6 +850,14 @@ void graphics_remove_wnd_proc(WNDPROC wndProc) {
     }
 }

+void graphics_hook_subscreen_window(HWND hWnd) {
+    // hook window procedure
+    if (WSUB_WNDPROC_ORIG == nullptr) {
+        WSUB_WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
+        SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WsubWindowProc));
+    }
+}
+
 void graphics_screens_register(int screen) {
     std::lock_guard<std::mutex> lock(GRAPHICS_SCREENS_M);

diff --git a/hooks/graphics/graphics.h b/hooks/graphics/graphics.h
index e70816a..bcd2040 100644
--- a/hooks/graphics/graphics.h
+++ b/hooks/graphics/graphics.h
@@ -51,6 +51,7 @@ extern int GRAPHICS_IIDX_WSUB_HEIGHT;
 extern int GRAPHICS_IIDX_WSUB_X;
 extern int GRAPHICS_IIDX_WSUB_Y;
 extern HWND TDJ_SUBSCREEN_WINDOW;
+extern HWND SDVX_SUBSCREEN_WINDOW;

 extern bool SUBSCREEN_FORCE_REDRAW;

@@ -67,6 +68,7 @@ void graphics_init();
 void graphics_hook_window(HWND hWnd, D3DPRESENT_PARAMETERS *pPresentationParameters);
 void graphics_add_wnd_proc(WNDPROC wndProc);
 void graphics_remove_wnd_proc(WNDPROC wndProc);
+void graphics_hook_subscreen_window(HWND hWnd);
 void graphics_screens_register(int screen);
 void graphics_screens_unregister(int screen);
 void graphics_screens_get(std::vector<int> &screens);
diff --git a/misc/wintouchemu.cpp b/misc/wintouchemu.cpp
index df72056..f12afc1 100644
--- a/misc/wintouchemu.cpp
+++ b/misc/wintouchemu.cpp
@@ -340,17 +340,24 @@ namespace wintouchemu {
                 return;
             }

-            bool should_create_touch_window = GRAPHICS_WINDOWED;
-            if (avs::game::is_model("LDJ")) {
-                should_create_touch_window &= !GRAPHICS_IIDX_WSUB;
-            }
-
             // check if windowed
-            if (should_create_touch_window) {
-                log_info("wintouchemu", "activating window hooks");
-                // create touch window - create overlay if not yet existing at this point
-                touch_create_wnd(hWnd, overlay::ENABLED && !overlay::OVERLAY);
-                USE_MOUSE = !GRAPHICS_IIDX_WSUB && !GENERIC_SUB_WINDOW_FULLSIZE;
+            if (GRAPHICS_WINDOWED) {
+                if (avs::game::is_model("LDJ") && GRAPHICS_IIDX_WSUB) {
+                    // no handling is needed here
+                    // graphics::MoveWindow_hook will attach hook to windowed subscreen
+                    log_info("wintouchemu", "attach touch hook to windowed subscreen");
+                    USE_MOUSE = false;
+                } else if (avs::game::is_model("LDJ") && !GENERIC_SUB_WINDOW_FULLSIZE) {
+                    // overlay subscreen in IIDX
+                    // use mouse position as ImGui overlay will block the touch window  
+                    log_info("wintouchemu", "use mouse cursor API for overlay subscreen");
+                    USE_MOUSE = true;
+                } else {
+                    // create touch window - create overlay if not yet existing at this point
+                    log_info("wintouchemu", "create touch window relative to main game window");
+                    touch_create_wnd(hWnd, overlay::ENABLED && !overlay::OVERLAY);
+                    USE_MOUSE = false;
+                }
             } else if (INJECT_MOUSE_AS_WM_TOUCH) {
                 log_info(
                     "wintouchemu",
diff --git a/touch/touch.cpp b/touch/touch.cpp
index 954578f..e902354 100644
--- a/touch/touch.cpp
+++ b/touch/touch.cpp
@@ -220,6 +220,16 @@ static LRESULT CALLBACK SpiceTouchWndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
         rawinput::touch::display_update();
     }

+    if (msg == WM_CLOSE) { 
+        if (
+            (GRAPHICS_IIDX_WSUB && hWnd == TDJ_SUBSCREEN_WINDOW) || 
+            (hWnd == SDVX_SUBSCREEN_WINDOW)
+        ) {
+            log_misc("touch", "ignore WM_CLOSE for subscreen window");
+            return false;
+        }
+    }
+
     // check messages for dedicated window
     if (SPICETOUCH_TOUCH_THREAD != nullptr) {
sp2xdev commented 4 months ago

Would be great if we can reuse this for voltex subscreen as well.

sp2xdev commented 4 months ago

By the way, I noticed that mouse clicks stop working after signing in with windowed subscreen, which is a problem. The PIN pad always works reliably, but when you try to click on other menu items, it works about 10% of the time. You still get the touch indicators (circle splash effect) but the menu items can't actually be clicked.

Not entirely sure why this happens, but when I try to adjust the EQ sliders, I see phantom touches... I also noticed that clicking on the primary window also registers touches. I'm thinking that maybe multiple touches are being detected by the game, causing some UI elements to not detect them.

edit: enabling overlay in the main window (press f12 for example) "fixes" this problem so it's definitely mouse clicks being passed to the game and interfering with touch emulation...

guardianblue commented 4 months ago

Looks like when using Windowed subscreen both the touch and mouse code paths of wintouchemu are invoked, and might have caused some race condition.

I will fix that as well.

sp2xdev commented 4 months ago

Yeah, in wintouchemu.cpp, in the if statement starting at line 144

if (touch_event) {
...
} else if (USE_MOUSE && !mouse_used) {
..
} else {
...
}

I see all three paths being exercised. If I force it so that the elseif and else part never runs, the problem goes away.

guardianblue commented 4 months ago

The patch should have fixed it.

sp2xdev commented 4 months ago

Thanks for a quick turnaround. Only thing I noticed so far is that I was able to close the sub window in SDVX. Nothing logged in the log, it just closes when I press X

guardianblue commented 4 months ago

Yeah sorry, the patch was wrong (silly me did git commit amend without adding). Updated the patch and it should work.

Related note, the touch emu hooking seems to be a bit chaotic at the moment, I will try to refactor that a bit later.

sp2xdev commented 4 months ago

I'm still having issues clicking around in TDJ subscreen. Trying to click on menus work maybe half the time.

I think your previous change was working better - did you mean to drop the changes in wintouchemu.cpp around line 245?

guardianblue commented 4 months ago

I was dropping the change in line 245 because it wasn't making a difference on my side

Might as well just put it back.

sp2xdev commented 4 months ago

Sure - I can just put it back and integrate it momentarily. I'd like to release a new version to address the touch issue.

sp2xdev commented 4 months ago

Done. Thanks for the contributions!