From 283251bad7c8d6cd5259e1e757940952dfc34206 Mon Sep 17 00:00:00 2001 From: Spencer Everly Date: Mon, 22 Jan 2024 13:36:58 -0600 Subject: [PATCH 1/5] Add onWindowUnocus/onWindowFocus events --- LunaDll/Globals.cpp | 3 ++ LunaDll/Globals.h | 3 ++ .../RuntimeHookHooks.cpp | 50 ++++++++++++++++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/LunaDll/Globals.cpp b/LunaDll/Globals.cpp index d3a5bf21..a0e6fa89 100644 --- a/LunaDll/Globals.cpp +++ b/LunaDll/Globals.cpp @@ -134,3 +134,6 @@ void printBoxA(const char *fmt, ...) std::string gEditorPlacedItem = "nil"; std::mutex g_editorIPCMutex; + +int gUnfocusTimer = 2; +int gFocusTimer = 2; diff --git a/LunaDll/Globals.h b/LunaDll/Globals.h index 7e037899..e5fa59bd 100644 --- a/LunaDll/Globals.h +++ b/LunaDll/Globals.h @@ -212,3 +212,6 @@ return; extern std::string gEditorPlacedItem; extern std::mutex g_editorIPCMutex; + +extern int gUnfocusTimer; +extern int gFocusTimer; diff --git a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp index 1a44d56a..e7eaaa9e 100644 --- a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp +++ b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp @@ -2804,17 +2804,51 @@ void __stdcall runtimeHookCheckWindowFocus() { if (!gMainWindowFocused && !LunaLoadScreenIsActive()) { - // During this block of code, pause music if it was playing - PGE_MusPlayer::DeferralLock musicPauseLock(true); + if(gUnfocusTimer > 0) + { + gUnfocusTimer-- + } + if(gUnfocusTimer == 1) + { + gFocusTimer = 2; + if (gLunaLua.isValid()) { + std::shared_ptr unfocusedEvent = std::make_shared("onUnfocusWindow", false); + unfocusedEvent->setDirectEventName("onUnfocusWindow"); + unfocusedEvent->setLoopable(false); + gLunaLua.callEvent(unfocusedEvent); + } + } + else if(gUnfocusTimer <= 0) + { + // During this block of code, pause music if it was playing + PGE_MusPlayer::DeferralLock musicPauseLock(true); - // Wait for focus - TestModeSendNotification("suspendWhileUnfocusedNotification"); - while (!gMainWindowFocused && !LunaLoadScreenIsActive()) + // Wait for focus + TestModeSendNotification("suspendWhileUnfocusedNotification"); + while (!gMainWindowFocused && !LunaLoadScreenIsActive()) + { + Sleep(100); + LunaDllWaitFrame(false); + } + TestModeSendNotification("resumeAfterUnfocusedNotification"); + } + } + else if (gMainWindowFocused && !LunaLoadScreenIsActive()) + { + if(gFocusTimer > 0) { - Sleep(100); - LunaDllWaitFrame(false); + gFocusTimer-- + } + if(gFocusTimer == 1) + { + gUnfocusTimer = 2; + if (gLunaLua.isValid()) { + std::shared_ptr focusedEvent = std::make_shared("onFocusWindow", false); + focusedEvent->setDirectEventName("onFocusWindow"); + focusedEvent->setLoopable(false); + gLunaLua.callEvent(focusedEvent); + } } - TestModeSendNotification("resumeAfterUnfocusedNotification"); } } From 7b42ee09a3e80ef6ec7493f3dd4b4765da10170d Mon Sep 17 00:00:00 2001 From: Spencer Everly Date: Sat, 27 Jan 2024 17:48:17 -0600 Subject: [PATCH 2/5] Fix keys and buttons still being pressed when the window is in the background while runWhenUnfocused is on --- LunaDll/Globals.cpp | 1 + LunaDll/Globals.h | 1 + LunaDll/Input/LunaGameController.cpp | 7 +++++-- .../Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp | 11 ++++++++++- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/LunaDll/Globals.cpp b/LunaDll/Globals.cpp index a0e6fa89..8b86b401 100644 --- a/LunaDll/Globals.cpp +++ b/LunaDll/Globals.cpp @@ -13,6 +13,7 @@ HINSTANCE gHInstance; HWND gMainWindowHwnd = NULL; bool gMainWindowFocused = false; +bool gMainWindowInBackground = false; // Global settings bool gLunaEnabled; diff --git a/LunaDll/Globals.h b/LunaDll/Globals.h index e5fa59bd..cf258112 100644 --- a/LunaDll/Globals.h +++ b/LunaDll/Globals.h @@ -90,6 +90,7 @@ extern HINSTANCE gHInstance; /// Global main window state extern HWND gMainWindowHwnd; extern bool gMainWindowFocused; +extern bool gMainWindowInBackground; /// Global settings extern bool gLunaEnabled; diff --git a/LunaDll/Input/LunaGameController.cpp b/LunaDll/Input/LunaGameController.cpp index b7072808..9a4e1e84 100644 --- a/LunaDll/Input/LunaGameController.cpp +++ b/LunaDll/Input/LunaGameController.cpp @@ -91,9 +91,12 @@ void LunaGameControllerManager::pollInputs() processSDLEvent(event); } - #if !defined(BUILDING_SMBXLAUNCHER) +#if !defined(BUILDING_SMBXLAUNCHER) + if(!gMainWindowInBackground) + { handleInputs(); - #endif // !defined(BUILDING_SMBXLAUNCHER) + } +#endif // !defined(BUILDING_SMBXLAUNCHER) } // Function to process an SDL event that is incoming diff --git a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp index 52d7ac49..899491b4 100644 --- a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp +++ b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp @@ -865,6 +865,7 @@ LRESULT CALLBACK HandleWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara // Our main window gained focus? Keep track of that. gMainWindowFocused = true; + gMainWindowInBackground = false; break; case WM_KILLFOCUS: // Unregister VK_SNAPSHOT hotkey handling when out of focus @@ -875,6 +876,10 @@ LRESULT CALLBACK HandleWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara { gMainWindowFocused = false; } + else + { + gMainWindowInBackground = true; + } break; case WM_DESTROY: // Our main window was destroyed? Clear hwnd and mark as unfocused @@ -884,6 +889,10 @@ LRESULT CALLBACK HandleWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara { gMainWindowFocused = false; } + else + { + gMainWindowInBackground = true; + } break; case WM_HOTKEY: if ((wParam == VK_SNAPSHOT) && g_GLEngine.IsEnabled()) @@ -921,7 +930,7 @@ LRESULT CALLBACK HandleWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara bool haveFocus = (wParam == RIM_INPUT); // Process the raw input - bool mainWindowFocus = haveFocus && gMainWindowFocused; + bool mainWindowFocus = haveFocus && gMainWindowFocused && !gMainWindowInBackground; ProcessRawInput(hwnd, reinterpret_cast(lParam), mainWindowFocus); // If we have focus, return via DefWindowProcW From cbf288583a70aaaa5682d3bfdfeb429e47f31223 Mon Sep 17 00:00:00 2001 From: Spencer Everly Date: Sat, 27 Jan 2024 17:52:23 -0600 Subject: [PATCH 3/5] Also fix mouse controlling when unfocused and running with runWhenUnfocused --- LunaDll/Input/MouseHandler.cpp | 40 +++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/LunaDll/Input/MouseHandler.cpp b/LunaDll/Input/MouseHandler.cpp index bda6e60d..de611943 100644 --- a/LunaDll/Input/MouseHandler.cpp +++ b/LunaDll/Input/MouseHandler.cpp @@ -8,7 +8,7 @@ MouseHandler gMouseHandler; void MouseHandler::OnMouseMove(int x, int y, uint8_t buttonState) { - if (mInClientArea && (mClientX == x) && (mClientY == y)) + if (mInClientArea && (mClientX == x) && (mClientY == y) && !gMainWindowInBackground) { // No change. return; @@ -34,16 +34,19 @@ void MouseHandler::OnMouseMove(int x, int y, uint8_t buttonState) void MouseHandler::OnMouseLeave() { - if (mInClientArea) + if(!gMainWindowInBackground) { - mInClientArea = false; - Recalculate(); + if (mInClientArea) + { + mInClientArea = false; + Recalculate(); + } } } void MouseHandler::OnMouseButtonEvent(ButtonEnum button, ButtonEvtEnum state) { - if (gLunaLua.isValid()) { + if (gLunaLua.isValid() && !gMainWindowInBackground) { std::shared_ptr event = std::make_shared("onMouseButtonEvent", false); event->setDirectEventName("onMouseButtonEvent"); event->setLoopable(false); @@ -53,7 +56,7 @@ void MouseHandler::OnMouseButtonEvent(ButtonEnum button, ButtonEvtEnum state) void MouseHandler::OnMouseWheelEvent(WheelEnum wheel, int delta) { - if (gLunaLua.isValid()) { + if (gLunaLua.isValid() && !gMainWindowInBackground) { std::shared_ptr event = std::make_shared("onMouseWheelEvent", false); event->setDirectEventName("onMouseWheelEvent"); event->setLoopable(false); @@ -64,17 +67,20 @@ void MouseHandler::OnMouseWheelEvent(WheelEnum wheel, int delta) // Recalculate FB coordinates void MouseHandler::Recalculate() { - if (mInClientArea) + if(!gMainWindowInBackground) { - double newX = mClientX; - double newY = mClientY; - gWindowSizeHandler.WindowToFramebuffer(newX, newY); - mFramebufferX = newX; - mFramebufferY = newY; - } - else - { - mFramebufferX = NAN; - mFramebufferY = NAN; + if (mInClientArea) + { + double newX = mClientX; + double newY = mClientY; + gWindowSizeHandler.WindowToFramebuffer(newX, newY); + mFramebufferX = newX; + mFramebufferY = newY; + } + else + { + mFramebufferX = NAN; + mFramebufferY = NAN; + } } } From 9814fc73efb3028b27b20e39fce273f5eafa0ed1 Mon Sep 17 00:00:00 2001 From: Spencer Everly Date: Sat, 27 Jan 2024 19:17:55 -0600 Subject: [PATCH 4/5] This should now be good to go --- LunaDll/Globals.cpp | 1 + LunaDll/Globals.h | 1 + LunaDll/Input/Input.cpp | 6 ++ LunaDll/Input/MouseHandler.cpp | 34 +++----- LunaDll/LuaMain/LuaProxyFFI.cpp | 11 +++ LunaDll/Misc/RuntimeHook.h | 7 ++ .../RuntimeHookGeneral.cpp | 31 +++---- .../RuntimeHookHooks.cpp | 86 ++++++++++++++++++- 8 files changed, 139 insertions(+), 38 deletions(-) diff --git a/LunaDll/Globals.cpp b/LunaDll/Globals.cpp index 8b86b401..2852ff5c 100644 --- a/LunaDll/Globals.cpp +++ b/LunaDll/Globals.cpp @@ -35,6 +35,7 @@ bool gDisablePlayerFilterBounceFix = false; // Other gameplay settings bool gLavaIsWeak = false; +bool gRunWhenUnfocused = false; // Flag for returning from gameover screen bool gDidGameOver = false; diff --git a/LunaDll/Globals.h b/LunaDll/Globals.h index cf258112..30ddb12d 100644 --- a/LunaDll/Globals.h +++ b/LunaDll/Globals.h @@ -108,6 +108,7 @@ extern bool gDisablePlayerFilterBounceFix; // Other gameplay settings extern bool gLavaIsWeak; +extern bool gRunWhenUnfocused; // Set to true when returning from gameover screen, read by lua to handle gameover-related stuff extern bool gDidGameOver; diff --git a/LunaDll/Input/Input.cpp b/LunaDll/Input/Input.cpp index 77a8d692..a03c21c1 100644 --- a/LunaDll/Input/Input.cpp +++ b/LunaDll/Input/Input.cpp @@ -80,6 +80,12 @@ void Input::ResetAll() { void Input::UpdateKeyRecords(PlayerMOB* pPlayer) { if(pPlayer == 0) return; + + if(!gMainWindowInBackground) + { + // the window is in the background, so return it + return; + } //wchar_t* dbg = L"Update keys debug"; diff --git a/LunaDll/Input/MouseHandler.cpp b/LunaDll/Input/MouseHandler.cpp index de611943..10303cd0 100644 --- a/LunaDll/Input/MouseHandler.cpp +++ b/LunaDll/Input/MouseHandler.cpp @@ -34,13 +34,10 @@ void MouseHandler::OnMouseMove(int x, int y, uint8_t buttonState) void MouseHandler::OnMouseLeave() { - if(!gMainWindowInBackground) + if (mInClientArea) { - if (mInClientArea) - { - mInClientArea = false; - Recalculate(); - } + mInClientArea = false; + Recalculate(); } } @@ -67,20 +64,17 @@ void MouseHandler::OnMouseWheelEvent(WheelEnum wheel, int delta) // Recalculate FB coordinates void MouseHandler::Recalculate() { - if(!gMainWindowInBackground) + if (mInClientArea) { - if (mInClientArea) - { - double newX = mClientX; - double newY = mClientY; - gWindowSizeHandler.WindowToFramebuffer(newX, newY); - mFramebufferX = newX; - mFramebufferY = newY; - } - else - { - mFramebufferX = NAN; - mFramebufferY = NAN; - } + double newX = mClientX; + double newY = mClientY; + gWindowSizeHandler.WindowToFramebuffer(newX, newY); + mFramebufferX = newX; + mFramebufferY = newY; + } + else + { + mFramebufferX = NAN; + mFramebufferY = NAN; } } diff --git a/LunaDll/LuaMain/LuaProxyFFI.cpp b/LunaDll/LuaMain/LuaProxyFFI.cpp index 3243be9a..ca775e44 100644 --- a/LunaDll/LuaMain/LuaProxyFFI.cpp +++ b/LunaDll/LuaMain/LuaProxyFFI.cpp @@ -899,3 +899,14 @@ extern "C" { return gLavaIsWeak; } } + +extern "C" { + FFI_EXPORT(void) LunaLuaRunWhenUnfocused(bool value) + { + gRunWhenUnfocused = value; + } + FFI_EXPORT(void) LunaLuaIsRunningWhenUnfocused(bool value) + { + return gRunWhenUnfocused; + } +} diff --git a/LunaDll/Misc/RuntimeHook.h b/LunaDll/Misc/RuntimeHook.h index aa2c59a7..17caef0d 100644 --- a/LunaDll/Misc/RuntimeHook.h +++ b/LunaDll/Misc/RuntimeHook.h @@ -340,7 +340,14 @@ void __stdcall runtimeHookNPCTerminalVelocityRaw(void); void __stdcall runtimeHookNPCHarmlessGrabRaw(void); void __stdcall runtimeHookNPCHarmlessThrownRaw(void); + +void __stdcall runtimeHookLegacyTitleScreenMouseUp(void); +void __stdcall runtimeHookLegacyTitleScreenMouseDown(void); +void __stdcall runtimeHookLegacyTitleScreenMouseMove(void); + +void __stdcall runtimeHookDoInput(void); void __stdcall runtimeHookCheckInputRaw(void); + void __stdcall runtimeHookSetHDCRaw(void); void __stdcall runtimeHookInitGameHDC(void); diff --git a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp index 899491b4..e2138098 100644 --- a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp +++ b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookGeneral.cpp @@ -604,11 +604,11 @@ static void ProcessRawInput(HWND hwnd, HRAWINPUT hRawInput, bool haveFocus) } // Send lua onRawKeyPress/Release events - if (!repeated) { + if (!repeated && !gMainWindowInBackground) { SendLuaRawKeyEvent(vkey, keyDown); } // If window is focused, and key is down, run keypress handling - if (haveFocus) { + if (haveFocus && !gMainWindowInBackground) { if (keyDown) { ProcessRawKeyPress(vkey, scanCode, repeated); } @@ -872,27 +872,21 @@ LRESULT CALLBACK HandleWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara UnregisterHotKey(hwnd, VK_SNAPSHOT); // Our main window lost focus? Keep track of that. - if (!gStartupSettings.runWhenUnfocused) + if (!gRunWhenUnfocused) { gMainWindowFocused = false; } - else - { - gMainWindowInBackground = true; - } + gMainWindowInBackground = true; break; case WM_DESTROY: // Our main window was destroyed? Clear hwnd and mark as unfocused UnregisterHotKey(hwnd, VK_SNAPSHOT); gMainWindowHwnd = NULL; - if (!gStartupSettings.runWhenUnfocused) + if (!gRunWhenUnfocused) { gMainWindowFocused = false; } - else - { - gMainWindowInBackground = true; - } + gMainWindowInBackground = true; break; case WM_HOTKEY: if ((wParam == VK_SNAPSHOT) && g_GLEngine.IsEnabled()) @@ -930,11 +924,14 @@ LRESULT CALLBACK HandleWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara bool haveFocus = (wParam == RIM_INPUT); // Process the raw input - bool mainWindowFocus = haveFocus && gMainWindowFocused && !gMainWindowInBackground; - ProcessRawInput(hwnd, reinterpret_cast(lParam), mainWindowFocus); + bool mainWindowFocus = haveFocus && gMainWindowFocused; + if(!gMainWindowInBackground) + { + ProcessRawInput(hwnd, reinterpret_cast(lParam), mainWindowFocus); + } // If we have focus, return via DefWindowProcW - if (haveFocus) + if (haveFocus && !gMainWindowInBackground) { return DefWindowProcW(hwnd, uMsg, wParam, lParam); } @@ -1211,6 +1208,7 @@ void ParseArgs(const std::vector& args) if (vecStrFind(args, L"--runWhenUnfocused")) { gStartupSettings.runWhenUnfocused = true; + gRunWhenUnfocused = true; gMainWindowFocused = true; } @@ -1724,6 +1722,9 @@ void TrySkipPatch() PATCH(0xA10136).JMP(runtimeHookNPCTerminalVelocityRaw).NOP_PAD_TO_SIZE<58>().Apply(); + PATCH(0x8BDE80).JMP(runtimeHookLegacyTitleScreenMouseDown).NOP_PAD_TO_SIZE<6>().Apply(); + + PATCH(0xA74910).JMP(runtimeHookDoInput).NOP_PAD_TO_SIZE<6>().Apply(); PATCH(0xA75079).JMP(runtimeHookCheckInputRaw).NOP_PAD_TO_SIZE<7>().Apply(); // Hooks for per-npc noblockcollision diff --git a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp index 09e23854..77f8c0fc 100644 --- a/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp +++ b/LunaDll/Misc/RuntimeHookComponents/RuntimeHookHooks.cpp @@ -2016,10 +2016,90 @@ _declspec(naked) void __stdcall runtimeHookNPCTerminalVelocityRaw() } } +__declspec(naked) void __stdcall legacyMouseUp_OrigFunc() +{ + __asm { + push ebp + mov ebp, esp + sub esp,0x0C + push 0x8BE086 + ret + } +} + +void __stdcall runtimeHookLegacyTitleScreenMouseUp() +{ + // Make sure that the mouse from the legacy title screen doesn't do anything when the window is in the background. This is used for running the game when unfocused. + if(!gMainWindowInBackground) + { + legacyMouseUp_OrigFunc(); + } +} + +__declspec(naked) void __stdcall legacyMouseDown_OrigFunc() +{ + __asm { + push ebp + mov ebp, esp + sub esp,0x0C + push 0x8BDE86 + ret + } +} + +void __stdcall runtimeHookLegacyTitleScreenMouseDown() +{ + // Make sure that the mouse from the legacy title screen doesn't do anything when the window is in the background. This is used for running the game when unfocused. + if(!gMainWindowInBackground) + { + legacyMouseDown_OrigFunc(); + } +} + +__declspec(naked) void __stdcall legacyMouseMove_OrigFunc() +{ + __asm { + push ebp + mov ebp, esp + sub esp,0x0C + push 0x8BDF16 + ret + } +} + +void __stdcall runtimeHookLegacyTitleScreenMouseMove() +{ + // Make sure that the mouse from the legacy title screen doesn't do anything when the window is in the background. This is used for running the game when unfocused. + if(!gMainWindowInBackground) + { + legacyMouseMove_OrigFunc(); + } +} + +__declspec(naked) void __stdcall startInput_OrigFunc() +{ + __asm { + push ebp + mov ebp, esp + sub esp, 0x8 + push 0xA74916 + ret + } +} + +void __stdcall runtimeHookDoInput() +{ + // Make sure that inputs don't do anything when the window is in the background. This is used for running the game when unfocused. + if(!gMainWindowInBackground) + { + startInput_OrigFunc(); + } +} + static void __stdcall runtimeHookCheckInput(int playerNum, int playerIdx, KeyMap* keymap) { // Test that player index is in range, and that it matches the true player number (ignore clones) - if ((playerIdx >= 0 && playerIdx <= 1) && ((playerIdx + 1) == playerNum)) + if (((playerIdx >= 0 && playerIdx <= 1) && ((playerIdx + 1) == playerNum))) { gRawKeymap[playerIdx+2] = gRawKeymap[playerIdx]; // Update prev values gRawKeymap[playerIdx] = *keymap; // Set new values @@ -2836,7 +2916,7 @@ void __stdcall runtimeHookCheckWindowFocus() { if(gUnfocusTimer > 0) { - gUnfocusTimer-- + gUnfocusTimer--; } if(gUnfocusTimer == 1) { @@ -2867,7 +2947,7 @@ void __stdcall runtimeHookCheckWindowFocus() { if(gFocusTimer > 0) { - gFocusTimer-- + gFocusTimer--; } if(gFocusTimer == 1) { From 3913d328c19eca21fb1e1e046524d828020b4eba Mon Sep 17 00:00:00 2001 From: Spencer Everly Date: Sat, 27 Jan 2024 19:18:56 -0600 Subject: [PATCH 5/5] Oops --- LunaDll/LuaMain/LuaProxyFFI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LunaDll/LuaMain/LuaProxyFFI.cpp b/LunaDll/LuaMain/LuaProxyFFI.cpp index ca775e44..3911c8ad 100644 --- a/LunaDll/LuaMain/LuaProxyFFI.cpp +++ b/LunaDll/LuaMain/LuaProxyFFI.cpp @@ -905,7 +905,7 @@ extern "C" { { gRunWhenUnfocused = value; } - FFI_EXPORT(void) LunaLuaIsRunningWhenUnfocused(bool value) + FFI_EXPORT(bool) LunaLuaIsRunningWhenUnfocused(bool value) { return gRunWhenUnfocused; }