python实现建议连点器(支持动作链)

简介:
1.这是一个自动操作鼠标与键盘的程序,录入你的操作然后可以无限重复它
2.支持的特殊的按键有esc,tab,space,shift,ctrl,capslock,其他的可能不支持,
3.不支持鼠标滚轮与侧键操作
4.支持的组合键有ctrl+c,ctrl+v,ctrl+s,ctrl+a其他的不支持
5.建议的屏幕分辨率为1920x1080
6.在读取动作时连续按下两次esc键退出,在动作复现时按下一次esc键停止
7.动作链.txt文件里面记录着读取到的动作,你可以对其进行修改以对你的动作进行修正
8.你也可以新建一个文件以达成你想要的动作,格式为:
["mouse" / "keyboard", (x, y, key, "up" / "down") / (key / "up" / "down"), time]
9.新建建文件时请以
['keyboard', ('esc', 'down'), time]
['keyboard', ('esc', 'up'), time]
['keyboard', ('esc', 'down'), time]
来结尾,这是因为这是读取时自动创建的文件的标准结尾格式,否则你的最后三个动作将被舍弃
10.在复现按钮的右边的输入框里输入你想要重复的次数,留空或者输入非数字的内容可能会引起程序错误
11.在点击读取按钮后窗口会自动最小化到系统托盘,在连续按下两次esc后会重新出现并置顶窗口
12.在复现动作时请保证同级目录下有有一个名为"动作链.txt"的文件且里面的内容符合格式,否则可能引起程序错误
13.如果同级目录下已经存在名为"动作链.txt"的文件那么读取操作将会对其内容进行覆写,如果你想保留一组动作请将读取到的文件备份到其他地方

让我们开始吧!

导入必要的库:

import time
import tkinter
from sys import exit

import pyautogui
import pynput
from pynput.mouse import Controller
from copy import deepcopy

定义鼠标的操作:

def mouse_click(x, y, button, pressed):
    """
    监听鼠标点击时间,包括按下与松开
    :param x: 鼠标操作时的x轴坐标,计算方式与tk二维方式一样
    :param y: 鼠标操作时的y轴坐标,计算方式与tk二维方式一样
    :param button: 按下的是哪个键, left / right / middle
    :param pressed: 按下 / 松开, down / up
    :return: None
    """
    # 采用字典的形式可以节省代码量
    dict_mouse_key = {pynput.mouse.Button.left: "left", pynput.mouse.Button.right: "right",
                      pynput.mouse.Button.middle: "middle"}
    dict_key_pressed = {True: "down", False: "up"}
    time_now = float("%.2f" % (time.perf_counter() - time_start))
    list_action_chain.append(["mouse", (x, y, dict_mouse_key[button], dict_key_pressed[pressed]), time_now])

定义键盘的函数:

def key_press(key):
    """
    监听键盘按下的事件
    :param key: 按下的是哪个键
    :return: None
    """
    time_now = float("%.2f" % (time.perf_counter() - time_start))
    if str(key)[1:3] == r"\x":  # 组合键,实现的基本原理就是将\x转化回原本的内容
        if str(key) == r"'\x03'":
            list_action_chain.append(["keyboard", ("c", "down"), time_now])
        elif str(key) == r"'\x16'":
            list_action_chain.append(["keyboard", ("v", "down"), time_now])
        elif str(key) == r"'\x13'":
            list_action_chain.append(["keyboard", ("s", "down"), time_now])
        elif str(key) == r"'\x1'":
            list_action_chain.append(["keyboard", ("a", "down"), time_now])
    elif str(key)[0:4] == "Key.":  # 特殊按键则截取后面的部分
        if str(key)[4:] == 'caps_lock':  # 特殊情况特殊处理 两个库之间的按键名称转换
            list_action_chain.append(["keyboard", ("capslock", "down"), time_now])
        elif str(key)[4:] == 'cmd':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("win", "down"), time_now])
        elif str(key)[4:8] == 'ctrl':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("ctrl", "down"), time_now])
        elif str(key)[4:8] == 'shift':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("shift", "down"), time_now])
        elif str(key)[4:8] == 'enter':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("enter", "down"), time_now])
        else:
            list_action_chain.append(["keyboard", (str(key)[4:], "down"), time_now])
    else:  # 普通按键则直接截取按键名
        list_action_chain.append(["keyboard", (str(key)[1::-2], "down"), time_now])

    # 连续按下两次esc以退出
    pynput.keyboard.Listener(on_press=key_press, on_release=key_release).stop()  # 结束键盘监听
    pynput.mouse.Listener(on_click=mouse_click).stop()  # 结束鼠标监听
    if len(list_action_chain) > 2 and str(list_action_chain[-1][1][0]) == "esc" and str(  # 不是特别好的判断方式
            list_action_chain[-3][1][0]) == "esc" and list_action_chain[-1][-1] - list_action_chain[-2][-1] < 1:
        # 路径问题
        f1 = open("../主界面/path.txt", "r", encoding="UTF-8")
        main_path = f1.readline()
        f1.close()
        f1 = open(f"{main_path}\\键鼠精灵\\动作链.txt", "w", encoding="UTF-8")  # 写入文件
        for i in list_action_chain:
            f1.writelines(str(i) + "\n")
        f1.close()  # 记得关闭打开的文件
        screen.attributes('-topmost', 'true')  # 窗口置顶
        screen.deiconify()  # 解除最小化


def key_release(key):
    """
    监听键盘松开的事件
    :param key: 松开的是哪个键
    :return: None
    """
    time_now = float("%.2f" % (time.perf_counter() - time_start))
    if str(key)[1:3] == r"\x":  # 组合键,实现的基本原理就是将\x转化回原本的内容
        if str(key) == r"'\x03'":
            list_action_chain.append(["keyboard", ("c", "up"), time_now])
        elif str(key) == r"'\x16'":
            list_action_chain.append(["keyboard", ("v", "up"), time_now])
    elif str(key)[0:4] == "Key.":  # 特殊按键则截取后面的部分
        if str(key)[4:] == 'caps_lock':  # 特殊情况特殊处理 两个库之间的按键名称转换
            list_action_chain.append(["keyboard", ("capslock", "up"), time_now])
        elif str(key)[4:] == 'cmd':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("win", "up"), time_now])
        elif str(key)[4:8] == 'ctrl':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("ctrl", "up"), time_now])
        elif str(key)[4:8] == 'shift':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("shift", "up"), time_now])
        elif str(key)[4:8] == 'enter':  # 特殊情况特殊处理
            list_action_chain.append(["keyboard", ("enter", "up"), time_now])
        else:
            list_action_chain.append(["keyboard", (str(key)[4:], "up"), time_now])
    else:  # 普通按键则直接截取按键名
        list_action_chain.append(["keyboard", (str(key)[1::-2], "up"), time_now])


def keyboard_interrupt(key):
    """
    在复现的时候按下esc键退出
    :param key: 没什么用
    :return:None
    """
    global flag_over
    flag_over = 1  # 将flag_over设为1

读取动作链,调用以上函数就行复现:

def recurrence(list_action_chains, cycles):
    """
    读取动作链列表然后复现,只要有动作链列表,这个函数就可以单独使用
    :param list_action_chains: 动作链列表
    :param cycles: 循环次数
    :return: None
    """
    global flag_over  # 中途结束程序需要的用到的flag
    flag_over = 0
    pynput.keyboard.Listener(on_press=keyboard_interrupt).start()
    list_action_chains = list_action_chains[:-3]  # 去除最后的两次连续的esc
    for _ in range(cycles):
        time_start2 = float("%.2f" % (time.perf_counter()))  # 重置时间
        list_action_chain_copy = deepcopy(list_action_chains)  # 备份
        while len(list_action_chains) != 0:  # 依次处理动作链列表中的动作
            if flag_over:
                exit()
            time_now2 = float("%.2f" % (time.perf_counter() - time_start2))
            if time_now2 < list_action_chains[0][-1]:
                pass
            else:
                action = list_action_chains[0]  # 类似于弹栈一样处理
                if action[0] == "mouse":  # 还原鼠标操作
                    if action[1][3] == "down":
                        pyautogui.mouseDown(x=action[1][0], y=action[1][1], button=action[1][2])
                    elif action[1][3] == "up":
                        pyautogui.moveTo(x=action[1][0], y=action[1][1])  # 这行配合down使用达到拖拽的效果
                        pyautogui.mouseUp(x=action[1][0], y=action[1][1], button=action[1][2])
                elif action[0] == "keyboard":
                    if action[1][-1] == "down":
                        if action[1][0]=="enter":
                            pyautogui.keyDown("enter")
                        else:
                            pyautogui.keyDown(action[1][0])
                    elif action[1][-1] == "up":
                        if action[1][0]=="enter":
                            pyautogui.keyUp("enter")
                        else:
                            pyautogui.keyUp(action[1][0])
                del list_action_chains[0]  # 类似于弹栈一样处理
        list_action_chains = list_action_chain_copy  # 还原
    exit()

定义ui

def main(types=None, cycles=1):
    """
    主菜单界面
    :param types: mxt-7的经典tk递归操作
    :param cycles:  复现次数,所有操作在复现时默认仅操作1次
    :return: None
    """
    global screen
    if types is None:  # 主菜单UI设计
        screen = tkinter.Tk()  # 窗口初始化
        screen.title("键鼠精灵")  # 设置标题
        screen.geometry("500x300+250+120")  # 设置窗口大小与初始化位置
        screen.iconbitmap(r"../主界面/ironmouse.ico")  # 设置窗口图标
        screen.resizable(width=False, height=False)  # 禁止改变窗口大小!!!!!!
        font1 = ("SimSun", 20)  # 设置一种字体
        # 控件摆放
        tkinter.Canvas(screen, height=300, width=500, bg='grey').place(x=0, y=0)
        cycles_entry = tkinter.Entry(screen, width=10, font=font1, bg='#777777')
        cycles_entry.place(x=230, y=40)
        tkinter.Button(screen, text="读取", font=font1, command=lambda: main(types="读取"), bg='#777777',
                       activebackground='#777777').place(x=30, y=30)
        tkinter.Button(screen, text="复现", font=font1,
                       command=lambda: main(types="复现", cycles=int(cycles_entry.get())), bg='#777777',
                       activebackground='#777777').place(x=130, y=30)
        screen.mainloop()  # 保持窗口显示
    elif types == "读取":
        screen.iconify()  # 先最小化窗口
        # 全局设置
        global time_start, mouse, list_action_chain  # 将所有重要变量设置为全局变量
        time_start = float("%.2f" % (time.perf_counter()))  # 程序的起始时间
        mouse = Controller()  # 设置监听器
        list_action_chain = []  # 格式:[[鼠标/键盘,(x,y,key,up_or_down)/(key/up_or_down),time]...]
        pyautogui.FAILSAFE = False  # 禁用pyautogui的屏幕边缘安全保护机制
        pynput.keyboard.Listener(on_press=key_press, on_release=key_release).start()
        pynput.mouse.Listener(on_click=mouse_click).start()
    elif types == "复现":
        screen.iconify()  # 先最小化窗口
        list_action_temp = []  # 读取txt中的内容到这个临时列表里面作为动作链传参

        f1 = open("../主界面/path.txt", "r", encoding="UTF-8")
        main_path = f1.readline()
        f1.close()
        f2 = open(f"{main_path}\\键鼠精灵\\动作链.txt", "r", encoding="UTF-8")  # 写入文件
        # f2 = open("动作链.txt", "r", encoding="UTF-8")
        for i in f2.readlines():
            list_action_temp.append(eval(i[:-1]))
        f2.close()
        recurrence(list_action_temp, cycles)

最后运行main函数即可。有任何问题可联系我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值