Skill: leonlw824/wxwork-rpa (version 1.0.1)

# 企业微信桌面自动化工具 基于桌面端UI自动化的企业微信操作工具，支持Windows/macOS双平台，可实现企业微信窗口管理、联系人操作、消息收发、聊天记录提取及自动化智能回复。 ⚠️ **重要声明**：本工具仅用于个人合法合规的企业微信操作自动化，请勿用于批量群发、骚扰他人等违规场景。使用前请确保遵守企业微信用户协议及相关法律法规。 ## 支持平台 - ✅ Windows (支持企业微信Windows版所有主流版本) - ✅ macOS (支持企业微信macOS版) - ❌ Linux (暂不支持) ## 前提条件 ### 1. 环境依赖安装 ```bash # 基础核心依赖 pip install pyautogui pillow opencv-py numpy pyperclip requests psutil paddle # Windows 额外依赖 pip install pywin32 # macOS 额外依赖 pip install pyobjc-framework-Quartz pyobjc-core pyobjc ``` ### 2. 权限配置 - **Windows**：无需额外权限，确保企业微信已安装并登录 - **macOS**：授予终端/IDE"辅助功能"和"屏幕录制"权限： 系统设置 → 隐私与安全 → 辅助功能 → 添加终端/IDE 系统设置 → 隐私与安全 → 屏幕录制 → 添加终端/IDE ### 3. 企业微信准备 - 确保企业微信已安装并完成登录 - 建议将企业微信窗口最大化运行（提升定位准确性） - 关闭企业微信的"消息免打扰"等可能影响界面显示的设置 ### 4. 自动回复的Authentication 自动回复需要 CHAT_API_URL 和 CHAT_API_KEY 和模型名称CHAT_MODEL: ``` [REDACTED_SECRET] ``` **Environment Variable:** Set your API url as `CHAT_API_URL`，Set your API key as `CHAT_API_KEY`: ```bash export CHAT_API_URL="YOUR_API_URL" export CHAT_API_KEY="YOUR_API_KEY" export CHAT_MODEL="YOUR_CHAT_MODEL" ``` ## 使用方法 ### 启动企业微信 ```bash py wechat.py start ``` ### 激活企业微信窗口 ```bash py wechat.py activate ``` ### 搜索联系人并发送消息 ```bash py wechat.py search_and_send --contact 张三 --message "你好，这是自动发送的消息" ``` ### 获取聊天记录 ```bash py wechat.py get_history --contact 李四 --limit 10 ``` ### 自动处理联系人消息（智能回复） ```bash # 基础用法 py wechat.py auto_process --api_key "CHAT_API_KEY" --api_url "CHAT_API_URL" --model "CHAT_MODEL" ``` ### 暂停自动回复 ```bash py wechat.py stop_auto_process ``` ### 查看帮助 ```bash py wechat.py help ``` ## 命令参考 | 命令 | 功能 | 示例 | |------|--------------|--------------------------------------------------------------------------------------------------------| | `start` | 启动企业微信客户端 | `wechat.py start` | | `activate` | 激活并最大化企业微信窗口 | `wechat.py activate --title 企业微信` | | `search_and_send` | 搜索联系人并发送消息 | `wechat.py search_and_send --contact 张三 --message 您好` | | `get_history` | 获取指定联系人聊天记录 | `wechat.py get_history --contact 李四 --limit 15` | | `auto_process` | 自动轮询联系人并智能回复 | `wechat.py auto_process --polling_times 10 --api_key xxx --api_url xxx --model xxx --contact_list xxx` | | `stop_auto_process` | 停止自动回复 | `wechat.py stop_auto_process` | | `help` | 查看帮助信息 | `wechat.py help` | ## 核心功能说明 ### 1. 企业微信进程与窗口管理 | 功能 | 说明 | |------|------| | 进程检测 | 自动检测企业微信是否正在运行 | | 自动启动 | 查找企业微信安装路径并启动，支持多路径适配 | | 窗口激活 | 定位企业微信窗口并激活，支持最大化、前置显示 | | 区域定位 | 自动识别企业微信界面各功能区域（输入框、发送按钮等） | ### 2. 联系人操作 | 功能 | 说明 | |------|------| | 精准搜索 | 通过搜索框定位联系人，支持剪贴板输入避免输入失败 | | 列表点击 | 按索引点击联系人列表，支持边界检查 | | 状态记忆 | 记录当前打开的联系人，避免重复操作 | ### 3. 消息处理 | 功能 | 说明 | |------|------| | 安全输入 | 支持剪贴板粘贴和逐字符输入，避免输入异常 | | 消息发送 | 精准点击发送按钮，支持自然鼠标移动轨迹 | | 记录提取 | 通过OCR和右键复制提取聊天记录，区分收发方向 | | 新消息检测 | 自动识别最新收到的消息，过滤自己发送的内容 | ### 4. 自动化回复 | 功能 | 说明 | |------|------| | 轮询检测 | 循环检查多个联系人的新消息 | | AI接口集成 | 调用自定义AI接口获取回复内容 | | 批量发送 | 支持多条回复依次发送，可自定义发送间隔 | | 异常处理 | 失败自动重试，错误日志完整记录 | ## 配置说明 ### 界面区域配置 - 首次运行`activate`命令会自动生成`config/wechat_regions.json` - 包含企业微信界面各区域的坐标和尺寸参数 - 不同平台配置自动区分，避免混用 ### 自定义参数 | 参数 | 功能 | 示例 | |-------------------|----------|----------------------------| | `--contact` | 指定联系人名称 | `--contact 张三` | | `--message` | 发送的消息内容 | `--message "您好"` | | `--limit` | 聊天记录获取数量 | `--limit 10` | | `--polling_times` | 自动轮询次数 | `--polling_times 20` | | `--api_url` | AI接口地址 | `--api_url "your-api-url"` | | `--api_key` | AI接口密钥 | `--api_key "your-api-key"` | | `--model` | 模型名称 | `--model "your-chat-model"` | | `--contact_list` | 过滤联系人 | `--contact_list 张三 李四` | | `--title` | 企业微信窗口标题 | `--title "企业微信"` | ## 技术说明 ### 核心技术点 - **跨平台适配**：通过`platform`模块区分Windows/macOS，适配不同的窗口管理API - **精准定位**：基于企业微信界面固定布局计算各功能区域坐标，无需图像识别 - **人机模拟**：贝塞尔曲线模拟人类鼠标移动轨迹，随机偏移避免被检测 - **安全操作**：所有点击/输入操作均有异常处理，失败自动降级为基础操作 - **剪贴板管理**：使用前保存、使用后恢复剪贴板内容，避免覆盖用户数据 ### 关键模块说明 | 模块 | 功能 | |------|------| | `WeChatRegion` | 数据类，定义企业微信界面所有区域的参数和坐标 | | `WeChatAutomation` | 核心类，封装所有自动化操作方法 | | `_safe_click` | 安全点击方法，模拟人类操作行为 | | `_locate_message_bubbles` | 消息气泡定位，基于OpenCV识别消息区域 | | `auto_process_contacts` | 自动化主方法，实现轮询和智能回复 | ### 日志与调试 - 日志文件：`wechatmation.log`（包含详细操作记录） - 调试目录：`debug/`（存储截图等调试信息） - 所有关键操作均有日志输出，便于问题定位 ## 常见问题 **错误：无法激活企业微信窗口** → 确认企业微信已运行并登录，或先执行`start`命令启动企业微信 → macOS需授予辅助功能权限 **错误：点击位置不准确** → 确保企业微信窗口已最大化 → 删除`config/wechat_regions.json`重新生成区域配置 → 检查企业微信界面布局是否为默认样式 **错误：剪贴板操作失败** → Windows：安装`pywin32`库（`pip install pywin32`） → macOS：确保终端有剪贴板访问权限 **错误：消息发送成功但对方未收到** → 检查输入框是否真正获得焦点 → 增加发送后的等待时间（修改代码中`time.sleep`参数） **错误：AI接口调用失败** → 检查API地址和密钥是否正确 → 确认接口支持POST请求，且返回格式符合要求 → 检查网络连接和接口权限 **企业微信界面更新后工具失效** → 更新`WeChatRegion`中的尺寸参数 → 重新运行`activate`生成新的区域配置 ## 隐私与安全 - ✅ 所有操作均在本地完成，不上传任何数据到网络 - ✅ 仅访问企业微信界面，不读取企业微信数据库文件 - ✅ 剪贴板内容使用后自动恢复，避免信息泄露 - ✅ 操作日志仅保存在本地，可随时删除 - ⚠️ 自动化操作可能违反企业微信用户协议，请谨慎使用 - ⚠️ 请勿用于商业推广、垃圾信息发送等违规行为 ### 扩展功能 - 可添加文件发送功能（点击文件按钮→选择文件→确认发送） - 可添加图片识别功能（结合OCR提取图片中的文字） - 可添加定时发送功能（结合`schedule`库实现定时操作） ## 免责声明 本工具仅用于学习和研究目的，请勿用于商业或违规用途。使用本工具产生的一切后果由使用者自行承担，作者不承担任何责任。 ```

path: _meta.json
content: ownerId: kn72qjc035302q9q7mv8a6gevh80d9ac
slug: wxwork-rpa
version: 1.0.0
publishedAt: 1772256879259

path: scripts/anti_detection.py
content: #!/usr/bin/env python3
"""
反检测策略
包含随机化、模式变化、行为伪装
"""

import time
import random
import hashlib
from typing import Dict, Any, Optional
import logging
from datetime import datetime, timedelta

logger = logging.getLogger(__name__)


class AntiDetection:
    """反检测策略管理器"""

    def __init__(self):
        self.behavior_fingerprint = self._generate_behavior_fingerprint()
        self.activity_log = []
        self.last_pattern_change = time.time()
        self.current_pattern = 'slow'

        # 行为模式配置
        self.behavior_patterns = {
            'normal': {
                'mouse_speed': 0.3,
                'typing_speed': 0.5,
                'click_delay': 0.2,
                'scroll_speed': 1.0
            },
            'slow': {
                'mouse_speed': 0.5,
                'typing_speed': 1,
                'click_delay': 0.4,
                'scroll_speed': 0.5
            },
            'fast': {
                'mouse_speed': 0.2,
                'typing_speed': 0.05,
                'click_delay': 0.1,
                'scroll_speed': 2.0
            },
            'random': {
                'mouse_speed': random.uniform(0.2, 0.5),
                'typing_speed': random.uniform(0.05, 0.2),
                'click_delay': random.uniform(0.1, 0.4),
                'scroll_speed': random.uniform(0.5, 2.0)
            }
        }

    def _generate_behavior_fingerprint(self) -> str:
        """生成行为指纹"""
        # 使用多个因素生成唯一指纹
        factors = [
            str(time.time()),
            str(random.random()),
            str(hashlib.md5(str(datetime.now()).encode()).hexdigest()[:8])
        ]

        fingerprint = hashlib.sha256(''.join(factors).encode()).hexdigest()[:16]
        logger.info(f"生成行为指纹: {fingerprint}")
        return fingerprint

    def should_change_pattern(self) -> bool:
        """判断是否需要改变行为模式"""
        current_time = time.time()

        # 每30-60分钟随机改变一次模式
        if current_time - self.last_pattern_change > random.randint(1800, 3600):
            return True

        # 或者根据活动频率决定
        recent_activities = self._get_recent_activities(minutes=5)
        if len(recent_activities) > 50:  # 5分钟内活动超过50次
            return True

        return False

    def get_next_pattern(self) -> str:
        """获取下一个行为模式"""
        patterns = list(self.behavior_patterns.keys())

        # 避免连续使用相同模式
        available_patterns = [p for p in patterns if p != self.current_pattern]

        if not available_patterns:
            available_patterns = patterns

        next_pattern = random.choice(available_patterns)
        self.current_pattern = next_pattern
        self.last_pattern_change = time.time()

        logger.info(f"切换行为模式: {next_pattern}")
        return next_pattern

    def get_pattern_config(self, pattern: Optional[str] = None) -> Dict[str, float]:
        """获取指定模式的配置"""
        if pattern is None:
            pattern = self.current_pattern

        config = self.behavior_patterns.get(pattern, self.behavior_patterns['normal'])

        # 添加微小随机变化
        randomized_config = {}
        for key, value in config.items():
            # ±10%的随机变化
            variation = value * random.uniform(-0.1, 0.1)
            randomized_config[key] = max(0.01, value + variation)

        return randomized_config

    def log_activity(self, activity_type: str, details: Dict[str, Any]):
        """记录活动日志"""
        activity = {
            'timestamp': datetime.now(),
            'type': activity_type,
            'details': details,
            'fingerprint': self.behavior_fingerprint
        }

        self.activity_log.append(activity)

        # 限制日志大小
        if len(self.activity_log) > 1000:
            self.activity_log = self.activity_log[-1000:]

    def _get_recent_activities(self, minutes: int = 5) -> list:
        """获取最近的活动"""
        cutoff_time = datetime.now() - timedelta(minutes=minutes)
        return [a for a in self.activity_log if a['timestamp'] > cutoff_time]

    def add_random_variation(self, value: float, variation_percent: float = 0.1) -> float:
        """添加随机变化"""
        variation = value * random.uniform(-variation_percent, variation_percent)
        return value + variation

    def simulate_human_imperfections(self):
        """模拟人类的不完美行为"""
        # 随机微小延迟
        tiny_delay = random.uniform(0.01, 0.05)
        time.sleep(tiny_delay)

        # 随机无效操作（概率很低）
        if random.random() < 0.001:
            # 模拟误点击或误操作
            self._simulate_mistake()

    def _simulate_mistake(self):
        """模拟误操作"""
        mistake_type = random.choice(['double_click', 'wrong_click', 'accidental_scroll'])

        if mistake_type == 'double_click':
            # 模拟意外双击
            logger.debug("模拟意外双击")
        elif mistake_type == 'wrong_click':
            # 模拟点错位置
            logger.debug("模拟点错位置")
        elif mistake_type == 'accidental_scroll':
            # 模拟意外滚动
            logger.debug("模拟意外滚动")

    def get_safe_delay(self, base_delay: float) -> float:
        """获取安全的延迟时间（避免规律性）"""
        # 使用随机分布，避免固定间隔
        if base_delay < 0.5:
            # 短延迟使用均匀分布
            delay = random.uniform(base_delay * 0.8, base_delay * 1.2)
        else:
            # 长延迟使用正态分布
            delay = random.normalvariate(base_delay, base_delay * 0.2)

        # 确保最小延迟
        return max(0.1, delay)

path: scripts/behavior_simulator.py
content: #!/usr/bin/env python3
"""
人类行为模拟增强
包含随机抖动、行为模式、反检测策略
"""

import time
import random
import math
from typing import List, Tuple, Dict, Any
import logging
from datetime import datetime

logger = logging.getLogger(__name__)


class BehaviorSimulator:
    """人类行为模拟器"""

    def __init__(self):
        self.behavior_patterns = self._load_behavior_patterns()
        self.last_activity_time = time.time()
        self.activity_history = []

    def _load_behavior_patterns(self) -> Dict[str, Any]:
        """加载行为模式"""
        return {
            'slow_typer': {
                'min_delay': 0.1,
                'max_delay': 0.3,
                'error_rate': 0.02,
                'backspace_rate': 0.01
            },
            'fast_typer': {
                'min_delay': 0.05,
                'max_delay': 0.15,
                'error_rate': 0.01,
                'backspace_rate': 0.005
            },
            'careful_typer': {
                'min_delay': 0.15,
                'max_delay': 0.4,
                'error_rate': 0.005,
                'backspace_rate': 0.002
            }
        }

    def get_mouse_trajectory(self, start_x: int, start_y: int,
                             end_x: int, end_y: int,
                             behavior_type: str = 'natural') -> List[Tuple[int, int]]:
        """
        生成模拟人类的鼠标轨迹
        """
        if behavior_type == 'natural':
            return self._natural_mouse_trajectory(start_x, start_y, end_x, end_y)
        elif behavior_type == 'direct':
            return self._direct_mouse_trajectory(start_x, start_y, end_x, end_y)
        elif behavior_type == 'hesitant':
            return self._hesitant_mouse_trajectory(start_x, start_y, end_x, end_y)
        else:
            return self._natural_mouse_trajectory(start_x, start_y, end_x, end_y)

    def _natural_mouse_trajectory(self, start_x: int, start_y: int,
                                  end_x: int, end_y: int) -> List[Tuple[int, int]]:
        """自然鼠标轨迹"""
        points = []

        # 计算距离
        distance = math.sqrt((end_x - start_x) ** 2 + (end_y - start_y) ** 2)

        # 根据距离确定点数
        num_points = max(10, int(distance / 5))

        # 使用改进的贝塞尔曲线
        control_points = self._generate_control_points(start_x, start_y, end_x, end_y)

        for i in range(num_points):
            t = i / (num_points - 1)

            # 计算贝塞尔曲线点
            x, y = self._bezier_point(t, start_x, start_y,
                                      control_points[0], control_points[1],
                                      control_points[2], control_points[3],
                                      end_x, end_y)

            # 添加物理抖动（模拟手部微颤）
            if i > 0 and i < num_points - 1:
                x += random.randint(-2, 2)
                y += random.randint(-2, 2)

            points.append((int(x), int(y)))

        # 在终点附近添加微调（模拟瞄准）
        for _ in range(3):
            adjust_x = end_x + random.randint(-3, 3)
            adjust_y = end_y + random.randint(-3, 3)
            points.append((adjust_x, adjust_y))

        points.append((end_x, end_y))

        return points

    def _generate_control_points(self, start_x: int, start_y: int,
                                 end_x: int, end_y: int) -> Tuple:
        """生成贝塞尔曲线控制点"""
        # 中点
        mid_x = (start_x + end_x) / 2
        mid_y = (start_y + end_y) / 2

        # 随机偏移量
        offset_x = (end_x - start_x) * random.uniform(0.1, 0.3)
        offset_y = (end_y - start_y) * random.uniform(0.1, 0.3)

        # 控制点1（靠近起点）
        cp1_x = start_x + offset_x * random.uniform(0.3, 0.7)
        cp1_y = start_y + offset_y * random.uniform(0.3, 0.7)

        # 控制点2（靠近终点）
        cp2_x = end_x - offset_x * random.uniform(0.3, 0.7)
        cp2_y = end_y - offset_y * random.uniform(0.3, 0.7)

        return (cp1_x, cp1_y, cp2_x, cp2_y)

    def _bezier_point(self, t: float, *points) -> Tuple[float, float]:
        """计算n阶贝塞尔曲线点"""
        n = len(points) // 2 - 1

        if n == 0:
            return points[0], points[1]

        new_points = []
        for i in range(n):
            x = (1 - t) * points[i * 2] + t * points[(i + 1) * 2]
            y = (1 - t) * points[i * 2 + 1] + t * points[(i + 1) * 2 + 1]
            new_points.extend([x, y])

        return self._bezier_point(t, *new_points)

    def simulate_typing_with_errors(self, text: str, pattern: str = 'natural') -> str:
        """
        模拟带错别字的打字
        返回实际输入的文本
        """
        if pattern == 'natural':
            error_rate = 0.01  # 1%的错误率
            backspace_rate = 0.005  # 0.5%的回退率
        else:
            pattern_config = self.behavior_patterns.get(pattern,
                                                        self.behavior_patterns['slow_typer'])
            error_rate = pattern_config['error_rate']
            backspace_rate = pattern_config['backspace_rate']

        result = []
        i = 0

        while i < len(text):
            char = text[i]

            # 判断是否输入错误
            if random.random() < error_rate:
                # 输入错别字
                typo = self._generate_typo(char)
                result.append(typo)

                # 判断是否立即修正
                if random.random() < 0.7:
                    # 立即修正
                    result.append('\b')  # 退格
                    result.append(char)
                else:
                    # 稍后修正（几个字符后）
                    pass
            else:
                result.append(char)

            # 随机回退（模拟删除重输）
            if random.random() < backspace_rate and len(result) > 1:
                backspace_count = random.randint(1, 3)
                for _ in range(min(backspace_count, len(result))):
                    result.append('\b')

            i += 1

        return ''.join(result)

    def _generate_typo(self, char: str) -> str:
        """生成常见错别字"""
        # 常见中文错别字映射
        chinese_typos = {
            '的': ['得', '地'],
            '在': ['再'],
            '是': ['时'],
            '和': ['或'],
            '了': ['啦', '咯'],
            '吗': ['嘛'],
            '吧': ['把'],
            '这': ['着'],
            '那': ['哪'],
            '他': ['她', '它'],
            '你': ['您'],
            '我': ['偶', '窝'],
        }

        # 常见英文错别字映射
        english_typos = {
            'a': 's', 'b': 'v', 'c': 'x', 'd': 's', 'e': 'r',
            'f': 'g', 'g': 'h', 'h': 'j', 'i': 'o', 'j': 'k',
            'k': 'l', 'l': 'k', 'm': 'n', 'n': 'm', 'o': 'p',
            'p': 'o', 'q': 'w', 'r': 't', 's': 'd', 't': 'r',
            'u': 'i', 'v': 'b', 'w': 'q', 'x': 'c', 'y': 'u',
            'z': 'x'
        }

        if '\u4e00' <= char <= '\u9fff':  # 中文字符
            return random.choice(chinese_typos.get(char, [char]))
        elif char.lower() in english_typos:
            return english_typos[char.lower()]
        else:
            return char

    def add_random_delay(self, base_delay: float = 1.0,
                         variation: float = 0.3) -> float:
        """
        添加随机延迟，模拟人类反应时间
        """
        # 使用正态分布，但限制在合理范围内
        delay = random.normalvariate(base_delay, variation * base_delay)
        delay = max(0.1, min(delay, base_delay * 2))

        # 记录活动时间
        self.last_activity_time = time.time()
        self.activity_history.append({
            'time': datetime.now(),
            'delay': delay,
            'type': 'wait'
        })

        return delay

    def simulate_thinking_time(self, text_length: int = 0) -> float:
        """
        模拟思考时间（根据文本长度）
        """
        if text_length == 0:
            # 随机思考时间
            think_time = random.uniform(0.5, 2.0)
        else:
            # 根据文本长度计算思考时间
            base_time = text_length * 0.1
            think_time = random.uniform(base_time * 0.5, base_time * 1.5)
            think_time = min(think_time, 5.0)  # 最多5秒

        time.sleep(think_time)
        return think_time

    def get_random_behavior_pattern(self) -> str:
        """获取随机行为模式"""
        patterns = list(self.behavior_patterns.keys())
        return random.choice(patterns)

path: scripts/hardware_simulator.py
content: #!/usr/bin/env python3
"""
硬件层模拟 - 使用HID设备直接模拟输入
支持Windows和macOS
"""

import time
import random
import threading
from typing import List, Tuple, Optional
import logging
import pyautogui
logger = logging.getLogger(__name__)


class HardwareSimulator:
    """硬件层模拟器"""

    def __init__(self):
        self.is_windows = False
        self.is_macos = False

        try:
            import platform
            system = platform.system()
            self.is_windows = system == "Windows"
            self.is_macos = system == "Darwin"

            # 根据平台初始化相应的硬件模拟
            if self.is_windows:
                self._init_windows_hid()
            elif self.is_macos:
                self._init_macos_hid()
            else:
                logger.warning(f"不支持的操作系统: {system}")

        except Exception as e:
            logger.error(f"硬件模拟初始化失败: {e}")

    def _init_windows_hid(self):
        """Windows HID模拟"""
        try:
            # 使用pywinusb或hidapi
            import hid
            self.hid_device = None

            # 尝试查找虚拟HID设备
            devices = hid.enumerate()
            for device in devices:
                # 寻找可用的HID设备
                if device['vendor_id'] == 0x1A2C or device['product_id'] == 0x6004:
                    self.hid_device = hid.device()
                    self.hid_device.open(device['vendor_id'], device['product_id'])
                    logger.info("找到HID设备")
                    break

            if not self.hid_device:
                logger.warning("未找到合适的HID设备，将使用软件模拟")

        except ImportError:
            logger.warning("未安装hid库，使用备用方案")

    def _init_macos_hid(self):
        """macOS HID模拟"""
        try:
            # macOS可以使用IOKit或pyobjc
            from Quartz import CGEventCreateKeyboardEvent, CGEventPost, kCGHIDEventTap
            from AppKit import NSEvent
            self.macos_available = True
            logger.info("macOS HID模拟可用")
        except ImportError:
            logger.warning("macOS HID模拟不可用，使用备用方案")
            self.macos_available = False

    def simulate_mouse_move(self, x: int, y: int, duration: float = 0.5):
        """
        硬件级鼠标移动模拟
        Args:
            x, y: 目标坐标
            duration: 移动持续时间
        """
        try:
            if self.is_windows and hasattr(self, 'hid_device') and self.hid_device:
                self._windows_hid_mouse_move(x, y, duration)
            elif self.is_macos and hasattr(self, 'macos_available') and self.macos_available:
                self._macos_hid_mouse_move(x, y, duration)
            else:
                self._software_mouse_move(x, y, duration)

        except Exception as e:
            logger.error(f"硬件鼠标移动失败: {e}")
            self._software_mouse_move(x, y, duration)

    def _windows_hid_mouse_move(self, x: int, y: int, duration: float):
        """Windows HID鼠标移动"""
        import win32api
        import win32con

        # 获取当前鼠标位置
        current_x, current_y = win32api.GetCursorPos()

        # 生成贝塞尔曲线路径
        points = self._generate_bezier_path(current_x, current_y, x, y, 50)

        # 计算每个点的间隔时间
        interval = duration / len(points)

        for point_x, point_y in points:
            # 使用绝对坐标移动
            win32api.mouse_event(
                win32con.MOUSEEVENTF_MOVE | win32con.MOUSEEVENTF_ABSOLUTE,
                int(point_x * 65535 / 1920),  # 假设屏幕宽度1920
                int(point_y * 65535 / 1080),  # 假设屏幕高度1080
                0, 0
            )
            time.sleep(interval)

    def _macos_hid_mouse_move(self, x: int, y: int, duration: float):
        """macOS HID鼠标移动"""
        try:
            from Quartz import (
                CGEventCreateMouseEvent, CGEventPost, kCGHIDEventTap,
                kCGEventMouseMoved, kCGMouseButtonLeft
            )

            # 创建鼠标移动事件
            event = CGEventCreateMouseEvent(
                None,
                kCGEventMouseMoved,
                (x, y),
                kCGMouseButtonLeft
            )

            # 分步移动，模拟人类行为
            steps = 20
            for i in range(steps):
                progress = (i + 1) / steps
                current_x = x * progress
                current_y = y * progress

                # 更新事件位置
                event = CGEventCreateMouseEvent(
                    None,
                    kCGEventMouseMoved,
                    (current_x, current_y),
                    kCGMouseButtonLeft
                )
                CGEventPost(kCGHIDEventTap, event)
                time.sleep(duration / steps)

        except Exception as e:
            logger.error(f"macOS HID鼠标移动失败: {e}")
            raise

    def _software_mouse_move(self, x: int, y: int, duration: float):
        """软件模拟鼠标移动（备用方案）"""
        import pyautogui

        # 使用带人类行为的移动
        pyautogui.moveTo(x, y, duration=duration,
                         tween=pyautogui.easeInOutQuad)

    def simulate_keyboard_input(self, text: str, min_delay: float = 0.05, max_delay: float = 0.15):
        """
        硬件级键盘输入模拟
        Args:
            text: 要输入的文本
            min_delay, max_delay: 按键延迟范围
        """
        try:
            if self.is_windows and hasattr(self, 'hid_device') and self.hid_device:
                self._windows_hid_keyboard_input(text, min_delay, max_delay)
            elif self.is_macos and hasattr(self, 'macos_available') and self.macos_available:
                self._macos_hid_keyboard_input(text, min_delay, max_delay)
            else:
                self._software_keyboard_input(text, min_delay, max_delay)

        except Exception as e:
            logger.error(f"硬件键盘输入失败: {e}")
            self._software_keyboard_input(text, min_delay, max_delay)

    def _software_keyboard_input(self, text: str, min_delay: float = 0.05, max_delay: float = 0.15):
        """
        软件模拟键盘输入（备用方案）- 修改为复制粘贴方式
        """
        logger.info("使用软件模拟键盘输入")

        # 分段输入，模拟人类打字
        segments = self._split_text_by_punctuation(text)

        for segment in segments:
            # 模拟思考时间
            think_time = random.uniform(0.1, 0.3)
            time.sleep(think_time)

            # 使用复制粘贴方式输入每个片段
            try:
                # 复制当前片段到剪贴板
                import pyperclip
                pyperclip.copy(segment)
                time.sleep(0.1)  # 确保复制完成

                # 发送粘贴快捷键
                import pyautogui
                if self.is_windows:
                    pyautogui.hotkey('ctrl', 'v')
                elif self.is_macos:
                    pyautogui.hotkey('command', 'v')
                else:
                    pyautogui.hotkey('ctrl', 'v')  # 默认用Ctrl

                # 随机延迟，模拟人类打字速度
                delay = random.uniform(min_delay, max_delay)
                time.sleep(delay)

                # 偶尔添加额外延迟（模拟犹豫）
                if random.random() < 0.05:
                    time.sleep(random.uniform(0.1, 0.2))

            except Exception as e:
                logger.warning(f"复制粘贴输入失败: {e}, 尝试逐字输入")
                # 如果复制粘贴失败，尝试原始的逐字输入（作为最后的手段）
                try:
                    for char in segment:
                        delay = random.uniform(min_delay, max_delay)
                        pyautogui.typewrite(char, interval=delay)
                        if random.random() < 0.05:
                            time.sleep(random.uniform(0.1, 0.2))
                except Exception as e2:
                    logger.error(f"逐字输入也失败: {e2}")

    def _windows_hid_keyboard_input(self, text: str, min_delay: float, max_delay: float):
        """Windows HID键盘输入 - 支持中文"""
        import pyperclip
        import pyautogui
        import win32api
        import win32con

        # 检查文本是否包含中文
        has_chinese = any('\u4e00' <= char <= '\u9fff' for char in text)

        if has_chinese or len(text) > 20:
            # 对于中文或长文本，使用复制粘贴方式
            logger.info("检测到中文或长文本，使用复制粘贴方式")

            # 分段处理
            segments = self._split_text_by_punctuation(text)

            for segment in segments:
                if not segment.strip():
                    continue

                # 模拟思考时间
                think_time = random.uniform(0.1, 0.3)
                time.sleep(think_time)

                # 复制到剪贴板
                pyperclip.copy(segment)
                time.sleep(0.1)

                # 发送Ctrl+V粘贴
                win32api.keybd_event(win32con.VK_CONTROL, 0, 0, 0)
                time.sleep(0.01)
                win32api.keybd_event(ord('V'), 0, 0, 0)
                time.sleep(0.01)
                win32api.keybd_event(ord('V'), 0, win32con.KEYEVENTF_KEYUP, 0)
                win32api.keybd_event(win32con.VK_CONTROL, 0, win32con.KEYEVENTF_KEYUP, 0)

                # 随机延迟
                delay = random.uniform(min_delay, max_delay)
                time.sleep(delay)
        else:
            # 对于英文短文本，可以使用直接按键
            logger.info("英文短文本，使用直接按键方式")
            for char in text:
                delay = random.uniform(min_delay, max_delay)
                time.sleep(delay)

                if char.isupper():
                    win32api.keybd_event(win32con.VK_SHIFT, 0, 0, 0)
                    time.sleep(0.01)

                vk_code = self._char_to_vk(char)
                if vk_code:
                    win32api.keybd_event(vk_code, 0, 0, 0)
                    time.sleep(0.01)
                    win32api.keybd_event(vk_code, 0, win32con.KEYEVENTF_KEYUP, 0)

                if char.isupper():
                    win32api.keybd_event(win32con.VK_SHIFT, 0, win32con.KEYEVENTF_KEYUP, 0)
                    time.sleep(0.01)

    def _char_to_vk(self, char: str) -> Optional[int]:
        """字符转虚拟键码 - 支持更多字符"""
        import win32con

        if not char:
            return None

        char_lower = char.lower()

        # 字母
        if 'a' <= char_lower <= 'z':
            return ord(char_lower.upper())

        # 数字
        elif '0' <= char_lower <= '9':
            return ord(char_lower)

        # 特殊字符映射
        special_chars = {
            ' ': win32con.VK_SPACE,
            '\n': win32con.VK_RETURN,
            '\t': win32con.VK_TAB,
            '.': win32con.VK_OEM_PERIOD,
            ',': win32con.VK_OEM_COMMA,
            ';': win32con.VK_OEM_1,
            '/': win32con.VK_OEM_2,
            '`': win32con.VK_OEM_3,
            '[': win32con.VK_OEM_4,
            '\\': win32con.VK_OEM_5,
            ']': win32con.VK_OEM_6,
            "'": win32con.VK_OEM_7,
            '-': win32con.VK_OEM_MINUS,
            '=': win32con.VK_OEM_PLUS,
        }

        if char in special_chars:
            return special_chars[char]

        # 中文或其他Unicode字符返回None，使用复制粘贴方式
        return None

    def _generate_bezier_path(self, start_x: int, start_y: int,
                              end_x: int, end_y: int,
                              num_points: int = 20) -> List[Tuple[int, int]]:
        """
        生成贝塞尔曲线路径
        返回一系列坐标点
        """
        import numpy as np

        # 生成控制点
        control1_x = start_x + (end_x - start_x) * random.uniform(0.2, 0.4)
        control1_y = start_y + (end_y - start_y) * random.uniform(0.2, 0.4)

        control2_x = start_x + (end_x - start_x) * random.uniform(0.6, 0.8)
        control2_y = start_y + (end_y - start_y) * random.uniform(0.6, 0.8)

        points = []
        for i in range(num_points):
            t = i / (num_points - 1)

            # 三次贝塞尔曲线
            x = (1 - t) ** 3 * start_x + \
                3 * (1 - t) ** 2 * t * control1_x + \
                3 * (1 - t) * t ** 2 * control2_x + \
                t ** 3 * end_x

            y = (1 - t) ** 3 * start_y + \
                3 * (1 - t) ** 2 * t * control1_y + \
                3 * (1 - t) * t ** 2 * control2_y + \
                t ** 3 * end_y

            # 添加随机抖动
            x += random.randint(-1, 1)
            y += random.randint(-1, 1)

            points.append((int(x), int(y)))

        return points

    def simulate_human_behavior(self, behavior_type: str, **kwargs):
        """
        模拟人类行为模式
        Args:
            behavior_type: 行为类型（'typing', 'scrolling', 'clicking'）
        """
        if behavior_type == 'typing':
            self._simulate_human_typing(**kwargs)
        elif behavior_type == 'scrolling':
            self._simulate_human_scrolling(**kwargs)
        elif behavior_type == 'clicking':
            self._simulate_human_clicking(**kwargs)

    def _simulate_human_typing(self, text: str):
        """模拟人类打字行为"""
        # 分段输入
        segments = self._split_text_by_punctuation(text)

        for segment in segments:
            # 模拟思考时间
            think_time = random.uniform(0.1, 0.5)
            time.sleep(think_time)

            # 输入片段
            for char in segment:
                # 随机按键速度
                key_delay = random.uniform(0.05, 0.15)

                # 模拟按键
                self.simulate_keyboard_input(char, key_delay, key_delay)

                # 偶尔停顿（模拟犹豫）
                if random.random() < 0.05:
                    time.sleep(random.uniform(0.1, 0.3))

            # 片段后的停顿
            if segment and segment[-1] in '，。！？；：':
                time.sleep(random.uniform(0.2, 0.4))

    def _split_text_by_punctuation(self, text: str) -> List[str]:
        """按标点符号和随机逻辑分割文本 - 更慢更真实"""
        if not text:
            return []

        segments = []
        current_segment = ""

        for i, char in enumerate(text):
            current_segment += char

            # 中文标点后强制分段（较长停顿）
            if char in '，。！？；：':
                segments.append(current_segment)
                current_segment = ""
                continue

            # 英文标点后强制分段（中等停顿）
            elif char in ',.!?;:':
                segments.append(current_segment)
                current_segment = ""
                continue

            # 空格后有一定概率分段（模拟换行思考）
            elif char == ' ' and random.random() < 0.3:
                segments.append(current_segment)
                current_segment = ""
                continue

            # 随机分段逻辑 - 让打字速度变化更大
            segment_length = len(current_segment)

            # 短句子：3-8个字符，有30%概率分段
            if 3 <= segment_length <= 8 and random.random() < 0.3:
                segments.append(current_segment)
                current_segment = ""
                continue

            # 中等句子：9-15个字符，有50%概率分段
            elif 9 <= segment_length <= 15 and random.random() < 0.5:
                segments.append(current_segment)
                current_segment = ""
                continue

            # 长句子：超过15个字符，强制分段（避免太长）
            elif segment_length > 15:
                # 寻找最近的标点或空格分段
                last_break_pos = -1
                for j in range(len(current_segment) - 1, -1, -1):
                    if current_segment[j] in '，。！？；：,.!?;: ':
                        last_break_pos = j
                        break

                if last_break_pos > 0:
                    segments.append(current_segment[:last_break_pos + 1])
                    current_segment = current_segment[last_break_pos + 1:]
                else:
                    segments.append(current_segment)
                    current_segment = ""
                continue

        if current_segment:
            segments.append(current_segment)

        # 记录分段统计
        if segments:
            avg_len = sum(len(s) for s in segments) / len(segments)
            logger.debug(f"文本分段: 总字符={len(text)}, 段数={len(segments)}, 平均段长={avg_len:.1f}")

        return segments

path: .clawhub/origin.json
content: version: 1
registry: https://clawhub.com
slug: wxwork-rpa
installedVersion: 1.0.0
installedAt: 1770624000000

Security scan verdicts — ClawScan: suspicious | static analysis:  | VirusTotal: malicious | SkillSpector: suspicious (CRITICAL)