From e942bbad589c16f94dfb452c587fe9c5ec142c7d Mon Sep 17 00:00:00 2001 From: Helios Agent Date: Tue, 3 Mar 2026 15:29:14 +0100 Subject: [PATCH] fix(client): force-foreground with fake Alt key, filter visible-only windows --- crates/client/src/windows_mgmt.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/client/src/windows_mgmt.rs b/crates/client/src/windows_mgmt.rs index 465cb96..ebc895e 100644 --- a/crates/client/src/windows_mgmt.rs +++ b/crates/client/src/windows_mgmt.rs @@ -9,7 +9,10 @@ mod win_impl { use windows::Win32::Foundation::{BOOL, HWND, LPARAM}; use windows::Win32::UI::WindowsAndMessaging::{ BringWindowToTop, EnumWindows, GetWindowTextW, IsWindowVisible, SetForegroundWindow, - ShowWindow, SW_MAXIMIZE, SW_MINIMIZE, SHOW_WINDOW_CMD, + ShowWindow, SW_MAXIMIZE, SW_MINIMIZE, SW_RESTORE, SHOW_WINDOW_CMD, + }; + use windows::Win32::UI::Input::KeyboardAndMouse::{ + keybd_event, KEYEVENTF_KEYUP, VK_MENU, }; // Collect HWNDs via EnumWindows callback @@ -68,12 +71,20 @@ mod win_impl { Ok(()) } + /// Bypass Windows Focus Stealing Prevention by sending a fake Alt keypress + /// before calling SetForegroundWindow. Without this, SetForegroundWindow + /// silently fails when the calling thread is not in the foreground. + unsafe fn force_foreground(hwnd: HWND) { + keybd_event(VK_MENU.0 as u8, 0, Default::default(), 0); + keybd_event(VK_MENU.0 as u8, 0, KEYEVENTF_KEYUP, 0); + ShowWindow(hwnd, SW_RESTORE); + BringWindowToTop(hwnd).ok(); + SetForegroundWindow(hwnd); + } + pub fn focus_window(window_id: u64) -> Result<(), String> { let hwnd = HWND(window_id as isize); - unsafe { - BringWindowToTop(hwnd).map_err(|e| format!("BringWindowToTop failed: {e}"))?; - SetForegroundWindow(hwnd); - } + unsafe { force_foreground(hwnd); } Ok(()) } @@ -81,8 +92,7 @@ mod win_impl { let hwnd = HWND(window_id as isize); unsafe { ShowWindow(hwnd, SW_MAXIMIZE); - BringWindowToTop(hwnd).map_err(|e| format!("BringWindowToTop failed: {e}"))?; - SetForegroundWindow(hwnd); + force_foreground(hwnd); } Ok(()) }