diff --git a/source/MaaWin32ControlUnit/Base/ForegroundUtils.h b/source/MaaWin32ControlUnit/Base/ForegroundUtils.h new file mode 100644 index 0000000000..14213f25eb --- /dev/null +++ b/source/MaaWin32ControlUnit/Base/ForegroundUtils.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#include "MaaUtils/SafeWindows.hpp" + +#include "Common/Conf.h" + +MAA_CTRL_UNIT_NS_BEGIN + +inline void ensure_foreground_and_topmost(HWND hwnd) +{ + if (!hwnd) { + return; + } + + // 如果窗口不在前台,先将其置顶 + if (hwnd != GetForegroundWindow()) { + // 将窗口移到 Z 序顶部 + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + + // 尝试设置为前台窗口 + SetForegroundWindow(hwnd); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + // 再次检查,如果仍然不在前台,再次置顶 + if (hwnd != GetForegroundWindow()) { + SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + } +} + +inline bool ensure_foreground_with_cooldown(HWND hwnd) +{ + constexpr DWORD kForegroundRecoveryInterval = 5000; + static DWORD last_foreground_attempt = 0; + + if (!hwnd || !IsWindow(hwnd)) { + return false; + } + + if (hwnd == GetForegroundWindow()) { + return true; + } + + DWORD now = GetTickCount(); + if (last_foreground_attempt != 0 && now - last_foreground_attempt < kForegroundRecoveryInterval) { + return hwnd == GetForegroundWindow(); + } + + last_foreground_attempt = now; + ensure_foreground_and_topmost(hwnd); + return hwnd == GetForegroundWindow(); +} + +MAA_CTRL_UNIT_NS_END diff --git a/source/MaaWin32ControlUnit/Input/InputUtils.h b/source/MaaWin32ControlUnit/Input/InputUtils.h index 4e74b58a67..594764344a 100644 --- a/source/MaaWin32ControlUnit/Input/InputUtils.h +++ b/source/MaaWin32ControlUnit/Input/InputUtils.h @@ -1,8 +1,6 @@ #pragma once -#include -#include - +#include "Base/ForegroundUtils.h" #include "Common/Conf.h" #include "MaaControlUnit/ControlUnitAPI.h" #include "MaaUtils/SafeWindows.hpp" @@ -27,32 +25,6 @@ inline void send_activate_message(HWND hwnd, bool use_post = false) std::this_thread::sleep_for(std::chrono::milliseconds(10)); } -// 窗口激活并置顶工具函数(强化版本,用于需要前台的物理输入方式) -// 用于 LegacyEventInput 和 SeizeInput,因为它们使用 SendInput/mouse_event 等物理输入 API -inline void ensure_foreground_and_topmost(HWND hwnd) -{ - if (!hwnd) { - return; - } - - // 如果窗口不在前台,先将其置顶 - if (hwnd != GetForegroundWindow()) { - // 将窗口移到 Z 序顶部 - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - - // 尝试设置为前台窗口 - SetForegroundWindow(hwnd); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - - // 再次检查,如果仍然不在前台,再次置顶 - if (hwnd != GetForegroundWindow()) { - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - } -} - // Contact 到 WM_* 消息的转换结果 struct MouseMessageInfo { diff --git a/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.cpp b/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.cpp index 31d2b08914..dd6ff1b749 100644 --- a/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.cpp +++ b/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.cpp @@ -2,6 +2,7 @@ #include +#include "Base/ForegroundUtils.h" #include "HwndUtils.hpp" #include "MaaUtils/Logger.h" @@ -14,6 +15,10 @@ std::optional DesktopDupWindowScreencap::screencap() return std::nullopt; } + if (!ensure_foreground_with_cooldown(hwnd_)) { + LogWarn << "Failed to ensure foreground window before screencap"; + } + // Ensure the window is fully visible on the monitor before screencap if (!ensure_window_on_screen(hwnd_)) { LogWarn << "Failed to ensure window on screen"; @@ -110,4 +115,3 @@ RECT DesktopDupWindowScreencap::get_output_desktop_coordinates() const } MAA_CTRL_UNIT_NS_END - diff --git a/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.h b/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.h index e183473883..02ec93499d 100644 --- a/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.h +++ b/source/MaaWin32ControlUnit/Screencap/DesktopDupWindowScreencap.h @@ -27,4 +27,3 @@ class DesktopDupWindowScreencap : public DesktopDupScreencap }; MAA_CTRL_UNIT_NS_END - diff --git a/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.cpp b/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.cpp index 536b7be3fa..6f4da0f85c 100644 --- a/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.cpp +++ b/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.cpp @@ -1,5 +1,6 @@ #include "ScreenDCScreencap.h" +#include "Base/ForegroundUtils.h" #include "HwndUtils.hpp" #include "MaaUtils/Logger.h" @@ -12,6 +13,10 @@ std::optional ScreenDCScreencap::screencap() return std::nullopt; } + if (!ensure_foreground_with_cooldown(hwnd_)) { + LogWarn << "Failed to ensure foreground window before screencap"; + } + // Ensure the window is fully visible on the monitor before screencap if (!ensure_window_on_screen(hwnd_)) { LogWarn << "Failed to ensure window on screen"; @@ -107,4 +112,3 @@ std::optional ScreenDCScreencap::screencap() } MAA_CTRL_UNIT_NS_END - diff --git a/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.h b/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.h index 20d3e89ab6..a08e3de9d1 100644 --- a/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.h +++ b/source/MaaWin32ControlUnit/Screencap/ScreenDCScreencap.h @@ -25,4 +25,3 @@ class ScreenDCScreencap : public ScreencapBase }; MAA_CTRL_UNIT_NS_END -