"""查明粘贴草稿后 _chat_surface_signature() 的哪个分量发生了变化。 会临时往输入框粘贴一段文字,测完立即 Ctrl+A + Backspace 清除,并还原剪贴板。 绝不按 Enter,不会发出任何消息。 """ import os import sys import time sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import numpy as np import pyautogui import pyperclip from PIL import Image import wechat_bot as bot_module _HERE = os.path.dirname(os.path.abspath(__file__)) _PROBE_DRAFT = "诊断用草稿请忽略" def measure(bot): """分别返回聊天区布局指纹、选中行预览指纹和整体指纹。""" full = bot._capture_full_window() list_x1 = max(0, int(bot._list_x)) list_y1 = max(0, int(bot._list_y)) list_x2 = min(full.shape[1], list_x1 + int(bot._list_w)) list_y2 = min(full.shape[0], list_y1 + int(bot._list_h)) chat_x1 = max(0, int(bot._chat_rel_x)) chat_y1 = max(0, int(bot._chat_rel_y)) chat_x2 = min(full.shape[1], chat_x1 + int(bot._chat_rel_w)) chat_y2 = min(full.shape[0], chat_y1 + int(bot._chat_rel_h)) session_list = full[list_y1:list_y2, list_x1:list_x2] chat = full[chat_y1:chat_y2, chat_x1:chat_x2] selected_y = bot.detect_selected_row(session_list) activity = ( bot._session_row_activity_signature(session_list, selected_y) if selected_y >= 0 else b"" ) return { "chat_layout": bot._chat_layout_signature(chat).hex(), "selected_y": selected_y, "row_preview": activity.hex(), "overall": bot._chat_surface_signature().hex(), "chat_box": (chat_x1, chat_y1, chat_x2, chat_y2), "session_list": session_list, "chat": chat, } def main(): bot = bot_module.WeChatBot() bot.safe_window_mode = True bot.auto_activate_window = True if not bot.connect(activate=False, wait_if_missing=False): print("[-] 未挂载到企业微信窗口") return if not bot._ensure_visible(): print("[-] 企业微信未能切到前台") return bot._refresh_message_geometry(bot._capture_full_window()) print(f"聊天区裁剪框(窗口内): x {bot._chat_rel_x}~{bot._chat_rel_x + bot._chat_rel_w}" f" y {bot._chat_rel_y}~{bot._chat_rel_y + bot._chat_rel_h}") print(f"_composer_rel_top : {bot._composer_rel_top}") before = measure(bot) print("\n[粘贴草稿前]") print(f" 聊天区布局 : {before['chat_layout']}") print(f" 选中行 y : {before['selected_y']}") print(f" 会话行预览 : {before['row_preview']}") print(f" 整体指纹 : {before['overall']}") old_clipboard = "" try: old_clipboard = pyperclip.paste() except Exception: pass try: pyperclip.copy(_PROBE_DRAFT) pyautogui.click(bot.input_x, bot.input_y) time.sleep(0.2) pyautogui.hotkey("ctrl", "v") time.sleep(0.6) after = measure(bot) print("\n[粘贴草稿后]") print(f" 聊天区布局 : {after['chat_layout']}" f" {'← 变化' if after['chat_layout'] != before['chat_layout'] else '(未变)'}") print(f" 选中行 y : {after['selected_y']}") print(f" 会话行预览 : {after['row_preview']}" f" {'← 变化' if after['row_preview'] != before['row_preview'] else '(未变)'}") print(f" 整体指纹 : {after['overall']}" f" {'← 变化' if after['overall'] != before['overall'] else '(未变)'}") print(f" _composer_rel_top 重算: " f"{bot_module.infer_composer_top(bot._capture_full_window(), int(bot._list_x + bot._list_w), bot.scale)}") Image.fromarray(before["chat"][:, :, :3][:, :, ::-1]).save( os.path.join(_HERE, "surface_chat_before.png") ) Image.fromarray(after["chat"][:, :, :3][:, :, ::-1]).save( os.path.join(_HERE, "surface_chat_after.png") ) Image.fromarray(after["session_list"][:, :, :3][:, :, ::-1]).save( os.path.join(_HERE, "surface_list_after.png") ) diff = np.abs( before["chat"][:, :, :3].astype(np.int16) - after["chat"][:, :, :3].astype(np.int16) ).max(axis=2) rows = np.flatnonzero((diff > 12).any(axis=1)) if rows.size: print(f" 聊天区裁剪内实际变化的行(裁剪内坐标): {rows.min()} ~ {rows.max()}" f" (裁剪高度 {diff.shape[0]})") else: print(" 聊天区裁剪内像素没有任何变化") print(" 已保存 tmp/surface_chat_before.png / surface_chat_after.png / surface_list_after.png") finally: pyautogui.hotkey("ctrl", "a") pyautogui.press("backspace") time.sleep(0.2) try: pyperclip.copy(old_clipboard) except Exception: pass print("\n[清理] 已清除诊断草稿并还原剪贴板。") if __name__ == "__main__": main()