TIM修复: 跳过UIA深度遍历(返回会话列表)+PostMessage点击不跳光标

- QQ/TIM 路径跳过 _collect_filtered_texts(UIA只暴露会话列表)
- _click_message_area 改为 PostMessage WM_LBUTTONDOWN/UP, 不移动物理鼠标
- 点击位置从 width*0.65 改为 width*0.88 (TIM三栏布局,最右是消息区)
This commit is contained in:
youpaishidifu
2026-07-25 10:22:36 +08:00
parent 4349b5c176
commit 877a5b2afb
+15 -22
View File
@@ -210,10 +210,10 @@ class MessageMonitor:
logger.debug(f"[{platform}] 滚动到底失败: {e}")
def _click_message_area(self, platform: str):
"""点击窗口消息区(中右区域)聚焦消息列表,避免焦点在搜索框。
"""PostMessage 点击消息区(靠右)聚焦消息列表,不移动物理鼠标。
TIM Electron 消息区 UIA 不可遍历,剪贴板法会复制搜索框内容。
先点击消息区确保焦点在消息列表。
TIM 三栏布局: 联系人|会话列表|消息区 → 消息区在最右 ~12%。
用 PostMessage 发送点击消息,不跳光标。
"""
hwnd = self._cached_hwnd.get(platform)
if not hwnd:
@@ -227,14 +227,14 @@ class MessageMonitor:
height = bottom - top
if width < 100 or height < 100:
return
# 消息区大致在中右区域
click_x = left + int(width * 0.65)
click_y = top + int(height * 0.45)
win32api.SetCursorPos((click_x, click_y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, click_x, click_y, 0, 0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, click_x, click_y, 0, 0)
# 消息区在最右(TIM 三栏: 左~5% 联系人, 中~75% 会话, 右~20% 消息)
client_x = int(width * 0.88)
client_y = int(height * 0.50)
lparam = win32api.MAKELONG(client_x, client_y)
win32gui.PostMessage(hwnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lparam)
win32gui.PostMessage(hwnd, win32con.WM_LBUTTONUP, 0, lparam)
time.sleep(0.3)
logger.debug(f"[{platform}] 已点击消息区 ({click_x},{click_y})")
logger.debug(f"[{platform}] PostMessage 点击 ({client_x},{client_y})")
except Exception as e:
logger.debug(f"[{platform}] 聚焦消息区失败: {e}")
@@ -322,25 +322,18 @@ class MessageMonitor:
def _read_messages(self, window, platform: str = "") -> list:
"""每轮重新定位 ListControl。"""
if platform == "qq":
# TIM/QQ NT: Electron 应用,UIA 树很深且消息区内容不可遍历
# 策略A: 深度 UIA 遍历 + 过滤搜索框区域(非侵入)
# 策略B: 剪贴板法(可靠但切焦点)
# 策略C: Win32 EnumChildWindows 回退
# TIM/QQ NT: Electron 应用,UIA 消息区内容不可遍历。
# 跳过 UIA 深度遍历(只返回会话列表,非聊天内容)。
# 直接走剪贴板法。
self._force_scroll_bottom(platform)
# A: 深度 UIA 遍历(depth=12),按位置过滤搜索框区域
texts = self._collect_filtered_texts(window, platform)
if texts:
logger.debug(f"[QQ] 深度遍历 → {len(texts)} items, last=\"{texts[-1][:50]}\"")
return texts
# B: 聚焦消息区 → 剪贴板法(Electron 最可靠)
# B: PostMessage 点击消息区 → 剪贴板法(不移动物理鼠标)
self._click_message_area(platform)
texts = self._read_via_clipboard(platform)
if texts:
return texts
# C: Win32 回退
# C: Win32 回退(EnumChildWindows 绕过 UIA)
texts = self._read_win32_texts(platform)
if texts:
logger.debug(f"[QQ] Win32 窗口文本 → {len(texts)} items")