import pydirectinput
import time
import random
from typing import Tuple, Optional

class AutoClicker:
    def __init__(self):
        # 初始化自动点击器
        # 设置 pydirectinput 参数
        pydirectinput.FAILSAFE = True  # 启用故障安全(移动鼠标到左上角停止)
        pydirectinput.PAUSE = 0.1  # 操作间隔时间
        
    def click_at_position(self, x: int, y: int, button: str = "left", clicks: int = 1):
        """
        在指定位置点击
        
        Args:
            x: X 坐标
            y: Y 坐标
            button: 鼠标按钮 ("left", "right", "middle")
            clicks: 点击次数
        """
        try:
            pydirectinput.click(x, y, button=button, clicks=clicks)
            print(f"在位置 ({x}, {y}) 点击了 {clicks} 次 {button} 键")
        except Exception as e:
            print(f"点击失败: {e}")
    
    def move_to_position(self, x: int, y: int):
        """
        移动鼠标到指定位置
        
        Args:
            x: X 坐标
            y: Y 坐标
        """
        try:
            pydirectinput.moveTo(x, y)
            print(f"鼠标移动到位置 ({x}, {y})")
        except Exception as e:
            print(f"移动鼠标失败: {e}")
    
    def drag_and_drop(self, start_x: int, start_y: int, end_x: int, end_y: int):
        """
        拖拽操作
        
        Args:
            start_x: 起始 X 坐标
            start_y: 起始 Y 坐标
            end_x: 结束 X 坐标
            end_y: 结束 Y 坐标
        """
        try:
            pydirectinput.moveTo(start_x, start_y)
            pydirectinput.mouseDown(button="left")
            time.sleep(0.1)
            pydirectinput.moveTo(end_x, end_y)
            time.sleep(0.1)
            pydirectinput.mouseUp(button="left")
            print(f"从 ({start_x}, {start_y}) 拖拽到 ({end_x}, {end_y})")
        except Exception as e:
            print(f"拖拽失败: {e}")
    
    def double_click(self, x: int, y: int):
        """
        在指定位置双击
        
        Args:
            x: X 坐标
            y: Y 坐标
        """
        self.click_at_position(x, y, clicks=2)
    
    def right_click(self, x: int, y: int):
        """
        在指定位置右键点击
        
        Args:
            x: X 坐标
            y: Y 坐标
        """
        self.click_at_position(x, y, button="right")
    
    def scroll(self, x: int, y: int, direction: str = "down", clicks: int = 3):
        """
        在指定位置滚动
        
        Args:
            x: X 坐标
            y: Y 坐标
            direction: 滚动方向 ("up" 或 "down")
            clicks: 滚动次数
        """
        try:
            pydirectinput.moveTo(x, y)
            if direction == "down":
                pydirectinput.scroll(-clicks)  # 向下滚动
            else:
                pydirectinput.scroll(clicks)   # 向上滚动
            print(f"在位置 ({x}, {y}) {direction} 滚动了 {clicks} 次")
        except Exception as e:
            print(f"滚动失败: {e}")
    
    def get_mouse_position(self) -> Tuple[int, int]:
        """
        获取当前鼠标位置
        
        Returns:
            鼠标坐标 (x, y)
        """
        try:
            x, y = pydirectinput.position()
            return (x, y)
        except Exception as e:
            print(f"获取鼠标位置失败: {e}")
            return (0, 0)
    
    def click_sequence(self, positions: list, delay: float = 1.0):
        """
        按顺序点击多个位置
        
        Args:
            positions: 位置列表,每个元素为 (x, y) 或 (x, y, button, clicks)
            delay: 每次点击之间的延迟时间
        """
        print(f"开始执行点击序列,共 {len(positions)} 个位置")
        for i, pos in enumerate(positions):
            if len(pos) == 2:
                x, y = pos
                self.click_at_position(x, y)
            elif len(pos) == 4:
                x, y, button, clicks = pos
                self.click_at_position(x, y, button, clicks)
            
            if i < len(positions) - 1:  # 不是最后一个位置
                time.sleep(delay)
                print(f"等待 {delay} 秒...")
        
        print("点击序列执行完成")

def demo_usage():
    """演示使用方法"""
    print("=== PyDirectInput 自动点击程序演示 ===")
    print("注意:移动鼠标到屏幕左上角可以停止程序")
    
    # 创建自动点击器实例
    clicker = AutoClicker()
    
    # 等待用户准备
    print("\n程序将在 3 秒后开始演示...")
    time.sleep(3)
    
    # 获取当前鼠标位置
    current_pos = clicker.get_mouse_position()
    print(f"当前鼠标位置: {current_pos}")
    
    # 演示各种操作
    print("\n1. 移动鼠标到屏幕中央")
    clicker.move_to_position(960, 540)  # 假设 1920x1080 屏幕
    
    print("\n2. 左键点击")
    clicker.click_at_position(960, 540)
    
    print("\n3. 右键点击")
    clicker.right_click(1000, 540)
    
    print("\n4. 双击")
    clicker.double_click(1040, 540)
    
    print("\n5. 拖拽操作")
    clicker.drag_and_drop(800, 400, 1100, 600)
    
    print("\n6. 滚动操作")
    clicker.scroll(960, 540, "down", 5)
    
    print("\n7. 执行点击序列")
    positions = [
        (800, 400),
        (900, 400),
        (1000, 400),
        (1100, 400),
        (1200, 400)
    ]
    clicker.click_sequence(positions, delay=0.5)
    
    print("\n演示完成!")

def custom_clicking():
    """自定义点击功能"""
    clicker = AutoClicker()
    
    print("\n=== 自定义点击模式 ===")
    print("输入坐标进行点击,输入 'q' 退出")
    
    while True:
        try:
            user_input = input("\n请输入坐标 (格式: x,y 或 x,y,button,clicks): ").strip()
            
            if user_input.lower() == 'q':
                print("退出程序")
                break
            
            # 解析输入
            parts = user_input.split(',')
            if len(parts) == 2:
                x, y = map(int, parts)
                clicker.click_at_position(x, y)
            elif len(parts) == 4:
                x, y, button, clicks = int(parts[0]), int(parts[1]), parts[2], int(parts[3])
                clicker.click_at_position(x, y, button, clicks)
            else:
                print("格式错误!请使用 x,y 或 x,y,button,clicks 格式")
                
        except ValueError:
            print("输入格式错误!请输入有效的数字")
        except KeyboardInterrupt:
            print("\n程序被中断")
            break

if __name__ == "__main__":
    try:
        # 运行演示
        demo_usage()
        
        # 询问是否继续自定义点击
        choice = input("\n是否继续自定义点击?(y/n): ").strip().lower()
        if choice == 'y':
            custom_clicking()
            
    except Exception as e:
        print(f"程序运行出错: {e}")
        print("请确保已安装 pydirectinput: pip install pydirectinput")

标签: none

添加新评论