From 1c5bfbc9c3151b3c5bba36929a9ed7ab73c41740 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Apr 2026 16:05:20 +0000 Subject: [PATCH 1/3] Initial plan From 1f2082b0b7adc6e6b067bfdbdd4c5242bc5b7c88 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Apr 2026 16:23:40 +0000 Subject: [PATCH 2/3] fix: prevent popup close on foreground and use WindowFromPoint for background clicks Agent-Logs-Url: https://github.com/MaaXYZ/MaaFramework/sessions/dbbdb4f4-607d-460a-bfa9-2ad1e672d754 Co-authored-by: weinibuliu <122535155+weinibuliu@users.noreply.github.com> --- source/MaaWin32ControlUnit/Input/InputUtils.h | 14 ++++++ .../Input/MessageInput.cpp | 50 ++++++++++++++++++- .../MaaWin32ControlUnit/Input/MessageInput.h | 1 + 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/source/MaaWin32ControlUnit/Input/InputUtils.h b/source/MaaWin32ControlUnit/Input/InputUtils.h index 4e74b58a67..7a5d6a7185 100644 --- a/source/MaaWin32ControlUnit/Input/InputUtils.h +++ b/source/MaaWin32ControlUnit/Input/InputUtils.h @@ -37,6 +37,20 @@ inline void ensure_foreground_and_topmost(HWND hwnd) // 如果窗口不在前台,先将其置顶 if (hwnd != GetForegroundWindow()) { + // 检查当前前台窗口是否是 hwnd 拥有的弹出窗口(如下拉菜单、右键菜单等)。 + // 若是,则跳过置前操作:强制置前 hwnd 会令弹出窗口失去焦点并自动关闭, + // 导致后续点击落在错误的 UI 元素上。 + HWND fg = GetForegroundWindow(); + if (fg) { + HWND owner = GetWindow(fg, GW_OWNER); + while (owner) { + if (owner == hwnd) { + return; + } + owner = GetWindow(owner, GW_OWNER); + } + } + // 将窗口移到 Z 序顶部 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); std::this_thread::sleep_for(std::chrono::milliseconds(5)); diff --git a/source/MaaWin32ControlUnit/Input/MessageInput.cpp b/source/MaaWin32ControlUnit/Input/MessageInput.cpp index c2ee721a2f..e0cd5eb6b0 100644 --- a/source/MaaWin32ControlUnit/Input/MessageInput.cpp +++ b/source/MaaWin32ControlUnit/Input/MessageInput.cpp @@ -129,6 +129,37 @@ HWND MessageInput::get_active_hwnd() return hwnd_; } +HWND MessageInput::find_window_at_point(int x, int y) const +{ + if (!hwnd_) { + return nullptr; + } + + POINT screen_pt = { x, y }; + if (!ClientToScreen(hwnd_, &screen_pt)) { + return nullptr; + } + + HWND at_pos = WindowFromPoint(screen_pt); + if (!at_pos || at_pos == hwnd_) { + return nullptr; + } + if (!IsWindowVisible(at_pos)) { + return nullptr; + } + + // 仅对同进程的窗口(如同进程内的弹出菜单或子控件)启用此逻辑, + // 避免误点击属于无关进程的窗口。 + DWORD our_pid = 0, at_pid = 0; + GetWindowThreadProcessId(hwnd_, &our_pid); + GetWindowThreadProcessId(at_pos, &at_pid); + if (our_pid != at_pid) { + return nullptr; + } + + return at_pos; +} + LPARAM MessageInput::make_mouse_lparam(HWND target, int x, int y) { if (target == hwnd_) { @@ -748,7 +779,24 @@ bool MessageInput::touch_down(int contact, int x, int y, int pressure) return false; } - HWND target = send_activate(); + // 优先使用 WindowFromPoint 查找点击位置处实际存在的窗口(如覆盖在主窗口上方的弹出菜单)。 + // GetLastActivePopup 仅能感知所有者链中的弹出窗口,无法发现不在所有者链中的同进程覆盖窗口, + // 导致后台消息直接发送给主窗口,绕过了上层的弹出窗口。 + HWND window_at_pos = find_window_at_point(x, y); + HWND target; + if (window_at_pos) { + target = window_at_pos; + LogInfo << "Using window at point instead of active hwnd" << VAR(target); + // 若目标窗口已处于前台(如刚打开的下拉菜单),则不再发送 WM_ACTIVATE, + // 避免激活消息导致弹出窗口意外关闭。 + if (target != GetForegroundWindow()) { + bool use_post = (config_.mode == Mode::PostMessage); + ::MaaNS::CtrlUnitNs::send_activate_message(target, use_post); + } + } + else { + target = send_activate(); + } gesture_target_ = target; check_and_block_input(); diff --git a/source/MaaWin32ControlUnit/Input/MessageInput.h b/source/MaaWin32ControlUnit/Input/MessageInput.h index b999383dcb..880b071626 100644 --- a/source/MaaWin32ControlUnit/Input/MessageInput.h +++ b/source/MaaWin32ControlUnit/Input/MessageInput.h @@ -68,6 +68,7 @@ class MessageInput : public RelativeMoveInput bool send_or_post_w(HWND target, UINT message, WPARAM wParam, LPARAM lParam); HWND get_active_hwnd(); + HWND find_window_at_point(int x, int y) const; LPARAM make_mouse_lparam(HWND target, int x, int y); // 在发鼠标消息前把系统状态调整到目标窗口愿意接受的位置。 From 8dc7e6a1dfd2bffaacdeb4eb45edb76b47b10517 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 24 Apr 2026 16:27:39 +0000 Subject: [PATCH 3/3] Changes before error encountered Agent-Logs-Url: https://github.com/MaaXYZ/MaaFramework/sessions/dbbdb4f4-607d-460a-bfa9-2ad1e672d754 Co-authored-by: weinibuliu <122535155+weinibuliu@users.noreply.github.com> --- source/MaaWin32ControlUnit/Input/MessageInput.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/MaaWin32ControlUnit/Input/MessageInput.cpp b/source/MaaWin32ControlUnit/Input/MessageInput.cpp index e0cd5eb6b0..af4f7c7a0b 100644 --- a/source/MaaWin32ControlUnit/Input/MessageInput.cpp +++ b/source/MaaWin32ControlUnit/Input/MessageInput.cpp @@ -151,8 +151,10 @@ HWND MessageInput::find_window_at_point(int x, int y) const // 仅对同进程的窗口(如同进程内的弹出菜单或子控件)启用此逻辑, // 避免误点击属于无关进程的窗口。 DWORD our_pid = 0, at_pid = 0; - GetWindowThreadProcessId(hwnd_, &our_pid); - GetWindowThreadProcessId(at_pos, &at_pid); + if (!GetWindowThreadProcessId(hwnd_, &our_pid) || !GetWindowThreadProcessId(at_pos, &at_pid)) { + LogWarn << "GetWindowThreadProcessId failed in find_window_at_point" << VAR(GetLastError()); + return nullptr; + } if (our_pid != at_pid) { return nullptr; } @@ -786,7 +788,7 @@ bool MessageInput::touch_down(int contact, int x, int y, int pressure) HWND target; if (window_at_pos) { target = window_at_pos; - LogInfo << "Using window at point instead of active hwnd" << VAR(target); + LogInfo << "Using window at point instead of active HWND" << VAR(target); // 若目标窗口已处于前台(如刚打开的下拉菜单),则不再发送 WM_ACTIVATE, // 避免激活消息导致弹出窗口意外关闭。 if (target != GetForegroundWindow()) {