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:
+15
-22
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user