# -*- coding: utf-8 -*-
import pyautogui
import random
import math
import time
import win32api
import win32con

# 计算贝塞尔曲线上的点
def bezier(t, points):
    n = len(points) - 1
    x = 0
    y = 0
    for i in range(n + 1):
        coefficient = math.comb(n, i) * (1 - t) ** (n - i) * t ** i
        x += points[i][0] * coefficient
        y += points[i][1] * coefficient
    return x, y

def get_durationAndSteps(distance):
    local_duration = 0
    local_steps = 0
    if distance < 500:
        local_duration = 150 + distance + random.randint(-100, 100)
        local_steps = 30  + local_duration / 10
    else:
        local_duration = 300 + distance / 2 + random.randint(-200, 200)
        local_steps = 60  + local_duration / 15
    
    return local_duration / 1000, int(local_steps)

#生成控制点,需在随机点添加正态分布
def generate_control_points(start_point, end_point, num_points):
    control_points = []
    control_points.append(start_point)
    
    # 计算起点和终点之间的距离
    distance = ((end_point[0] - start_point[0]) ** 2 + (end_point[1] - start_point[1]) ** 2) ** 0.5
    
    # 计算每个等分点的距离
    interval = distance / (num_points + 1)

    srcPoint = start_point
    
    for i in range(1, num_points + 1):
        # 计算当前等分点的位置
        t = i / (num_points + 1)

        dstPoint = ((end_point[0] - start_point[0]) / num_points * i + start_point[0], (end_point[1] - start_point[1]) / num_points * i + start_point[1])
        
        # 生成随机的控制点
        control_point = (
            random.uniform(srcPoint[0], dstPoint[0]),
            random.uniform(srcPoint[1], dstPoint[1])
        )

        srcPoint = dstPoint
        
        # 将控制点添加到列表中
        control_points.append(control_point)

    out_points = (((end_point[0] - start_point[0]) / num_points / 3 + end_point[0], (end_point[1] - start_point[1]) / num_points / 3 + end_point[1]))
    
    control_points.append(out_points)
    control_points.append(end_point)
    
    return control_points

class pcacc_mouse:
    def __init__(specifically):
        random.seed()

    @staticmethod
    def input_string(text):
        print("input string : " + str(text))
        for char in text:
            # 获取字符的虚拟键码（大写字母或数字）
            vk_code = win32api.VkKeyScan(char)
            
            # 按下键
            win32api.keybd_event(vk_code & 0xff, 0, 0, 0)
            time.sleep(0.05)  # 短暂延迟，确保系统处理
            
            # 释放键
            win32api.keybd_event(vk_code & 0xff, 0, win32con.KEYEVENTF_KEYUP, 0)
            time.sleep(0.05)

    @staticmethod
    def move_mouse(dst_x, dst_y, isQuick = False):
        random_range = 4
        # 获取当前鼠标位置作为起点
        start_x, start_y = pyautogui.position()
        if abs(dst_x - start_x) < 10 and abs(dst_y - start_y) < 10: #认为已经移到对应位置了
            return
        distance = math.sqrt((dst_x - start_x) ** 2 + (dst_y - start_y) ** 2)
        duration, steps = get_durationAndSteps(distance)
        points = generate_control_points((start_x, start_y), (dst_x, dst_y), 3)
        interval = duration / steps
        for i in range(steps + 1):
            t = i / steps
            x, y = bezier(t, points)
            
            # 添加随机性到坐标
            x += random.randint(-random_range, random_range)
            y += random.randint(-random_range, random_range)
            
            # 计算速度和加速度
            speed_factor = math.sin(t * math.pi)
            acceleration_factor = 2 * t * (1 - t)
            speed = speed_factor * (1 + acceleration_factor) * interval
            if isQuick:
                speed = speed / 2
            try:
                win32api.SetCursorPos((int(x), int(y)))
            finally:
                time.sleep(speed)  # 添加停顿时间

    @staticmethod
    def click(dst_x, dst_y):
        pcacc_mouse.move_mouse(dst_x, dst_y)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, dst_x, dst_y, 0, 0)
        cur_times = random.randint(0, 1)
        if cur_times == 0:
            time.sleep(1.0 / random.randint(60, 130))
        elif cur_times == 1:
            time.sleep(1.0 / random.randint(100, 200))
            dst_x = dst_x + random.randint(-3, 3)
            dst_y = dst_y + random.randint(-3, 3)
            win32api.SetCursorPos((dst_x, dst_y))
            time.sleep(1.0 / random.randint(100, 200))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, dst_x + random.randint(-3, 3), dst_y + random.randint(-3, 3), 0, 0)

    @staticmethod
    def quickclick(dst_x, dst_y):
        pcacc_mouse.move_mouse(dst_x, dst_y, True)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, dst_x, dst_y, 0, 0)
        time.sleep(1.0 / random.randint(300, 500))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, dst_x + random.randint(-3, 3), dst_y + random.randint(-3, 3), 0, 0)

    @staticmethod
    def quickclick_current():
        src_x, src_y = pyautogui.position()
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, src_x + random.randint(-3, 3), src_y + random.randint(-3, 3), 0, 0)
        time.sleep(1.0 / random.randint(300, 500))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, src_x + random.randint(-3, 3), src_y + random.randint(-3, 3), 0, 0)
    
    @staticmethod
    def drag_from(src_x, src_y, dst_x, dst_y):
        pcacc_mouse.move_mouse(src_x, src_y)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, src_x, src_y, 0, 0)
        pcacc_mouse.move_mouse(dst_x, dst_y)
        time.sleep(1.0 / random.randint(60, 130))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, dst_x, dst_y, 0, 0)

    @staticmethod
    def drag(dst_x, dst_y):
        src_x, src_y = pyautogui.position()
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, src_x, src_y, 0, 0)
        pcacc_mouse.move_mouse(dst_x, dst_y)
        time.sleep(1.0 / random.randint(60, 130))
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, dst_x, dst_y, 0, 0)

if __name__ == '__main__':
    # 移动鼠标
    pcacc_mouse.drag_from(500, 500, 100, 100)
