You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.7 KiB
117 lines
3.7 KiB
"""微信窗口定位与基本交互 — 基于 uiautomation"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
import time
|
|
|
|
import uiautomation as uia
|
|
|
|
from ..config import Config
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class WeChatWindow:
|
|
"""封装微信主窗口的查找、激活、以及子面板获取"""
|
|
|
|
def __init__(self, config: Config) -> None:
|
|
self.config = config
|
|
self._window: uia.WindowControl | None = None
|
|
|
|
# ------------------------------------------------------------------
|
|
# 公开方法
|
|
# ------------------------------------------------------------------
|
|
|
|
def find_window(self) -> uia.WindowControl | None:
|
|
"""查找微信主窗口(不激活)"""
|
|
try:
|
|
win = uia.WindowControl(
|
|
searchDepth=1,
|
|
Name=self.config.wechat_title,
|
|
ClassName="WeChatMainWndForPC",
|
|
)
|
|
if win.Exists(maxSearchSeconds=2):
|
|
self._window = win
|
|
logger.info("找到微信窗口: %s", win.Name)
|
|
return win
|
|
except Exception:
|
|
logger.debug("通过 ClassName 查找失败,尝试按标题查找")
|
|
win = uia.WindowControl(
|
|
searchDepth=1,
|
|
Name=self.config.wechat_title,
|
|
)
|
|
if win.Exists(maxSearchSeconds=2):
|
|
self._window = win
|
|
logger.info("找到微信窗口: %s", win.Name)
|
|
return win
|
|
|
|
logger.warning("未找到微信窗口")
|
|
self._window = None
|
|
return None
|
|
|
|
def activate(self) -> bool:
|
|
"""激活(前置)微信窗口"""
|
|
win = self._window or self.find_window()
|
|
if win is None:
|
|
return False
|
|
try:
|
|
win.SetFocus()
|
|
time.sleep(0.3)
|
|
return True
|
|
except Exception:
|
|
logger.exception("激活微信窗口失败")
|
|
return False
|
|
|
|
def get_window(self) -> uia.WindowControl | None:
|
|
return self._window
|
|
|
|
def is_alive(self) -> bool:
|
|
"""窗口是否仍然存在"""
|
|
win = self._window
|
|
if win is None:
|
|
return False
|
|
try:
|
|
return win.Exists(maxSearchSeconds=1)
|
|
except Exception:
|
|
return False
|
|
|
|
def get_chat_panel(self) -> uia.Control | None:
|
|
"""获取当前聊天消息列表面板"""
|
|
win = self._window or self.find_window()
|
|
if win is None:
|
|
return None
|
|
# 聊天消息区域通常在 "ChatPanel" 或包含消息列表的 ListControl
|
|
try:
|
|
# 微信 PC 版的消息列表一般是一个 ListControl,ClassName 包含 "ChatMsgList"
|
|
panel = win.ListControl(searchDepth=8)
|
|
if panel.Exists(maxSearchSeconds=2):
|
|
return panel
|
|
except Exception:
|
|
logger.debug("通过 ListControl 查找聊天面板失败")
|
|
|
|
# 备选方案:搜索名称包含 "消息" 的控件
|
|
try:
|
|
panel = win.ListControl(Name="消息", searchDepth=8)
|
|
if panel.Exists(maxSearchSeconds=1):
|
|
return panel
|
|
except Exception:
|
|
pass
|
|
|
|
logger.warning("未找到聊天消息面板")
|
|
return None
|
|
|
|
def get_conversation_list_panel(self) -> uia.Control | None:
|
|
"""获取左侧会话列表面板"""
|
|
win = self._window or self.find_window()
|
|
if win is None:
|
|
return None
|
|
try:
|
|
# 会话列表通常在左侧,ClassName 包含 "SessionList"
|
|
panel = win.ListControl(searchDepth=8)
|
|
if panel.Exists(maxSearchSeconds=2):
|
|
return panel
|
|
except Exception:
|
|
pass
|
|
logger.warning("未找到会话列表面板")
|
|
return None
|
|
|