简介: 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函数即可。有任何问题可联系我。