This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
EasyChat is a Windows-only PC WeChat automation assistant that uses UI automation to control the WeChat desktop client. It provides scheduled messaging, bulk messaging, and contact extraction through a PyQt5 GUI. The project uses uiautomation to interact with WeChat's UI controls since web WeChat is no longer available.
Multi-version support: As of 2026/04/17, the project supports multiple WeChat versions through a plugin-like architecture. Each WeChat version has its own implementation module in the versions/ directory.
Current supported versions: 4.1.9.21 (default), 4.1.8.107. Earlier versions (3.9, 4.0) are no longer supported.
Unimplemented methods: check_new_msg(), get_dialogs(), save_dialog_pictures(), and get_dialogs_by_time_blocks() are stub methods that raise NotImplementedError — they have not been adapted to WeChat 4.1+ and cannot be called.
CRITICAL: Windows Narrator (讲述人) must be enabled for uiautomation to detect WeChat UI controls. This is the #1 cause of runtime failures.
WeChat hotkey: The default hotkey to open WeChat is Ctrl+Alt+W. Users can configure a custom hotkey in the GUI settings (added 2026/04/19). The hotkey is stored in wechat_config.json and used by the automation engine to open WeChat without triggering the login popup.
# Setup
pip install -r requirements.txt # requirements.txt is UTF-16 encoded; pip handles it fine
# Run GUI
python wechat_gui.py
# Build standalone .exe (output: dist/wechat_gui.exe)
# Note: pack.py contains hardcoded paths; run from the project root
python pack.py
# Internally uses: pyinstaller.exe -Fw --noupx --collect-submodules versions wechat_gui.py
# Inspect WeChat's live UI control tree (use when WeChat updates break automation)
python automation.py [-t delay] [-d depth] [-r root] [-c cursor]
# Output also written to @AutomationLog.txtTesting core automation: Edit the __main__ block in version-specific modules (e.g., versions/wechat_4_1_9_21.py), set your WeChat path, and uncomment specific test calls. No test framework is used.
The application layers are:
wechat_gui.py ← PyQt5 UI, config persistence, hotkey handling, version loader
│
├── module.py ← ClockThread (scheduler), custom widgets
│
├── wechat_locale.py ← Localized UI element names (shared utility)
│
├── clipboard.py ← File clipboard operations (shared utility)
│
└── versions/ ← Version-specific WeChat automation implementations
├── __init__.py ← Version registry (VERSIONS dict, helper functions)
├── wechat_4_1_9_21.py ← WeChat 4.1.9.21 automation engine
└── wechat_4_1_8_107.py ← WeChat 4.1.8.107 automation engine
The project now supports multiple WeChat versions through dynamic module loading:
-
Version registry (
versions/__init__.py): DefinesVERSIONSdict mapping user-friendly labels (e.g., "微信 4.1.9.21") to module paths (e.g., "versions.wechat_4_1_9_21"). New versions are registered here; list newest first soget_default_version()returns the latest. -
Version loader (
wechat_gui.py:_load_wechat_class()): Usesimportlibto dynamically import theWeChatclass from the selected version module. -
Version selection: Users select their WeChat version in the GUI settings. The selection is stored in
wechat_config.jsonundersettings.system_version. -
Version switching: When the user changes versions,
_reinit_wechat()reloads the appropriateWeChatclass and rebinds theprevent_offlinemethod toClockThread.
The WeChat class wraps uiautomation to control WeChat's desktop UI. Key design decisions:
- UI control depths are hardcoded (e.g.,
Depth=15for search box). These break when WeChat updates its UI structure. Useautomation.pyto re-inspect the control tree after any WeChat update. - All text input uses clipboard paste (
pyperclip→ Ctrl+V) instead of direct typing, for reliability. The 0.3s delays after clipboard operations are critical — removing them causes paste failures. - WeChat is opened via Ctrl+Alt+W (not by launching the
.exedirectly). This avoids triggering the new login popup (2026/03/09 fix). Do not change the startup logic without understanding this workaround. - Contact search skips
XTableCellitems to avoid selecting groups instead of contacts (2025/12/02 fix).search_waitis a[min, max]range (default[0.3, 0.3]); each search picks a random value within the range to vary timing like a human. - Folded group chats (折叠群聊) are now supported as of 2026/05/18. Previously, messages couldn't be sent to folded group chats.
find_all_contacts()returns a pandas DataFrame. It usesrsplit(" ", maxsplit=2)to parse contact info, which fails if names or notes contain spaces.
WechatGUI(QWidget) owns the main window. Every user action (add/delete contacts, messages, schedules) auto-saves to wechat_config.json immediately — there is no manual save.
Config structure:
{
"settings": {
"wechat_path": "",
"send_interval": [3.0, 8.0],
"search_wait": [0.3, 0.8],
"system_version": "微信 4.1.9.21",
"language": "zh-CN"
},
"contacts": ["1:name1", "2:name2"],
"messages": ["1:text:all::content", "2:file:1,2::path"],
"schedules": ["2026 4 9 16 11 1-1"]
}Timing ranges: send_interval and search_wait are stored as [min, max] lists. When a range is set (min ≠ max), the actual wait time is a random value chosen uniformly from the range on each use. Setting min = max gives deterministic (non-random) behavior.
Interrupt hotkey: Ctrl+Alt+Q sets hotkey_pressed = True via the keyboard library global hook. Sending loops should check this flag to stop mid-process. The hotkey is registered in wechat_gui.py using keyboard.add_hotkey() and remains active throughout the application lifecycle.
ClockThread(QThread) polls every second and fires scheduled tasks within a 60-second execution window (prevents duplicate fires). It also drives the anti-auto-logout feature (triggers every 60 minutes). It emits error_signal when a scheduled task fails.
Custom widgets: MyListWidget (double-click to edit), MySpinBox, MyDoubleSpinBox, MultiInputDialog, FileDialog.
WeChatLocale maps UI element names to localized strings for zh-CN, zh-TW, and en-US WeChat clients. Required when locating controls by name.
setClipboardFiles(paths) uses the Windows win32clipboard API with a DROPFILES structure to stage files for Ctrl+V sending.
Message strings (stored in config and displayed in list widgets):
- Text:
{rank}:text:{to}:{at_names}:{content} - File:
{rank}:file:{to}:{path} to="all"or comma-separated contact indices ("1,2,3")contentsupports\nfor newlines
Schedule strings: {year} {month} {day} {hour} {min} {start}-{end}
start-end= message index range to send (1-based)
Bulk TXT loading:
- Users: one contact name per line
- Content:
all:messageor1,2,3:messageper line (text only, no files)
-
WeChat UI updates break hardcoded depths: Re-run
automation.pyon the live WeChat window to find new control depths after any WeChat update. Each version module has its own hardcoded depths. -
Do not touch WeChat launch logic: The Ctrl+Alt+W approach (not spawning
Weixin.exe) is a deliberate workaround for the new-login popup introduced in 2026/03/09. The hotkey is configurable in GUI settings but must be set before WeChat is opened. -
Clipboard timing: The 0.3s sleeps after
pyperclip.copy()andsetClipboardFiles()are load-bearing. Don't remove them. -
NotImplementedErrormethods: Callingcheck_new_msg(),get_dialogs(),save_dialog_pictures(), orget_dialogs_by_time_blocks()will raise immediately — they are not stubs with silent fallbacks. -
Backup files:
ui_auto_wechat-4.0备份.py,gui_cp.py,module_cp.pyare historical backups, not active code. The originalui_auto_wechat.pywas moved toversions/wechat_4_1_9_21.pyin commit 2ba08a4. -
PyInstaller data files: When building the .exe, the
versions/directory must be included with--collect-submodules versions(seepack.py). The pack.py script contains hardcoded absolute paths and must be run from the project root. -
requirements.txt encoding: The file is UTF-16 encoded (visible as spaced characters when viewed). pip handles this automatically, but text editors may display it incorrectly. Don't "fix" the encoding unless you understand the implications.
- Chinese comments and variable names are mixed with English throughout.
- Error handling is minimal; high-level
try/exceptcatches most failures. - GUI layouts are built programmatically with
QVBoxLayout/QHBoxLayout— no.uifiles or Qt Designer.
To add support for a new WeChat version:
- Create a new module in
versions/(e.g.,wechat_4_2_0.py) by copying an existing version module. - Update hardcoded UI control depths using
automation.pyto inspect the new WeChat UI structure. - Register the new version in
versions/__init__.pyby adding an entry to theVERSIONSdict. - Update
pack.pyif the build process needs changes. - Test thoroughly - UI automation is fragile and breaks easily with WeChat updates.