From a5b6a441646d8525e91951e5aa5ae245f7c3dbbf Mon Sep 17 00:00:00 2001 From: z060142 Date: Mon, 12 May 2025 23:52:32 +0800 Subject: [PATCH] Replace always-on-top with foreground activation for game window focus --- ClaudeCode.md | 10 +++++++--- game_monitor.py | 45 ++++++++++++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/ClaudeCode.md b/ClaudeCode.md index c329354..fd0400b 100644 --- a/ClaudeCode.md +++ b/ClaudeCode.md @@ -606,9 +606,13 @@ Wolf Chat 是一個基於 MCP (Modular Capability Provider) 框架的聊天機 - **`game_monitor.py`**: - 在 `monitor_game_window` 函數的監控循環中,移除了使用 `win32gui.SetWindowPos` 和 `win32con.HWND_TOPMOST` 來檢查和設定 `WS_EX_TOPMOST` 樣式的程式碼。 - 替換為檢查當前前景視窗 (`win32gui.GetForegroundWindow()`) 是否為目標遊戲視窗 (`hwnd`)。 - - 如果不是,則調用 `win32gui.BringWindowToTop(hwnd)` 和 `win32gui.SetForegroundWindow(hwnd)` 來嘗試將遊戲視窗帶到前景並啟用。 - - 更新了相關的日誌訊息以反映新的行為。 -- **效果**:監控腳本現在會嘗試將失去焦點的遊戲視窗重新激活並帶到前景,而不是強制其覆蓋所有其他視窗。這更符合一般視窗的行為模式。 + - 如果不是,則嘗試以下步驟將視窗帶到前景並獲得焦點: + 1. 使用 `win32gui.SetWindowPos` 搭配 `win32con.HWND_TOP` 旗標,將視窗提升到所有非最上層視窗之上。 + 2. 呼叫 `win32gui.SetForegroundWindow(hwnd)` 嘗試將視窗設為前景並獲得焦點。 + 3. 短暫延遲後,檢查視窗是否成功成為前景視窗。 + 4. 如果 `SetForegroundWindow` 未成功,則嘗試使用 `pygetwindow` 庫提供的 `window.activate()` 方法作為備用方案。 + - 更新了相關的日誌訊息以反映新的行為和備用邏輯。 +- **效果**:監控腳本現在會使用更全面的方法嘗試將失去焦點的遊戲視窗重新激活並帶到前景,包括備用方案,以提高在不同 Windows 環境下獲取焦點的成功率。這取代了之前僅強制視覺覆蓋的行為。 ## 開發建議 diff --git a/game_monitor.py b/game_monitor.py index 8897517..a21c220 100644 --- a/game_monitor.py +++ b/game_monitor.py @@ -217,28 +217,43 @@ def monitor_game_window(): # monitor_logger.warning(f"Failed to adjust window. Current: {new_pos} {new_size}, Target: {target_pos} {target_size}") pass # Keep silent on failure for now - # 2. Check and Bring to Foreground/Activate + # 2. Check and Bring to Foreground/Activate (Improved Logic) current_foreground_hwnd = win32gui.GetForegroundWindow() if current_foreground_hwnd != hwnd: try: - # Attempt to bring to top and set foreground - # Note: SetForegroundWindow might fail if the calling process doesn't have foreground rights - win32gui.BringWindowToTop(hwnd) + # Use HWND_TOP instead of HWND_TOPMOST to bring it above others without forcing always-on-top + win32gui.SetWindowPos(hwnd, win32con.HWND_TOP, 0, 0, 0, 0, + win32con.SWP_NOMOVE | win32con.SWP_NOSIZE) + + # Make window the foreground window (with focus) + # Note: This might still fail due to Windows foreground restrictions win32gui.SetForegroundWindow(hwnd) - # Short delay to allow window manager to process - time.sleep(0.1) - # Verify if it became the foreground window - if win32gui.GetForegroundWindow() == hwnd: - current_message += "已將遊戲視窗帶到前景並啟用。(Brought game window to foreground and activated.) " + + # Verify window is active by checking foreground window + time.sleep(0.1) # Brief pause to let operation complete + foreground_hwnd = win32gui.GetForegroundWindow() + + if foreground_hwnd == hwnd: + current_message += "已將遊戲視窗提升到前景並設為焦點。(Brought game window to foreground with focus.) " adjustment_made = True else: - # Optional: Log if setting foreground failed, might happen if another app steals focus quickly - # monitor_logger.warning("嘗試將視窗設為前景後,它並未成為前景視窗。(Attempted to set window foreground, but it did not become the foreground window.)") - pass - except Exception as fg_err: - # This can happen if the window handle is invalid or other win32 errors occur - monitor_logger.warning(f"嘗試將視窗設為前景時出錯: {fg_err} (Error trying to set window foreground: {fg_err})") + # Optional: Add a fallback for versions of Windows with stricter foreground rules + monitor_logger.warning("SetForegroundWindow 未能成功,嘗試備用方法 window.activate()。(SetForegroundWindow failed, trying fallback window.activate())") + try: + window.activate() # Try pygetwindow's activate method as backup + time.sleep(0.1) # Pause after activate + if win32gui.GetForegroundWindow() == hwnd: + current_message += "已透過備用方法將遊戲視窗設為焦點。(Set game window focus via fallback method.) " + adjustment_made = True + else: + monitor_logger.warning("備用方法 window.activate() 也未能成功。(Fallback window.activate() also failed.)") + except Exception as activate_err: + monitor_logger.warning(f"備用方法 window.activate() 出錯: {activate_err}") + + except Exception as focus_err: + # Log errors during the focus attempt + monitor_logger.warning(f"設置視窗焦點時出錯: {focus_err}") except gw.PyGetWindowException as e: # Log PyGetWindowException specifically, might indicate window closed during check