一,安装pynput库
使用Python对键盘鼠标进行监听我们一般使用 pynput 库中的 pynput.keyboard 和 pynput.mouse
所以我们首先需要安装pynput 库
pip install pynput
二,鼠标键盘控制
1,鼠标控制:
实例化鼠标对象:
from pynput import mouse
contro = mouse.Controller()
控制鼠标的方法:
from pynput import mouse
# 实列化对象
control2 = mouse.Controller()
#鼠标移动,相当于X坐标加10,Y坐标加10
control2.move(10, 10)
#鼠标直接到 (100, 100)的位置
control2.position(100, 100)
#鼠标点击 .click(Button, count)
#左键 mouse.Button.left
#右键 mouse.Button.right
#中键 mouse.Button.middle
#count 点击的次数
control2.click(mouse.Button.left, 1)
#按住鼠标按键
control2.press(mouse.Button.left)
#松开鼠标按键
control2.release(mouse.Button.left)
#控制鼠标滑轮 control2.scroll(dx, int) dx 为滑动的距离, 第二个参数是上下
control2.scroll(10, -1)
2,键盘控制:
键盘和鼠标控制是大同小异的,也就一下参数的变化。
实例化键盘对象:
# 导入pynput库
from pynput import keyboard
# 实列化键盘控制对象
control1 = keyboard.Controller()
键盘控制的方法:
# 导入pynput库
from pynput import keyboard
# 实列化键盘控制对象
control1 = keyboard.Controller()
# 控制键盘按下 a 键
control1.press('a')
# 控制键盘松开 a 键
control1.release('a')
# 控制键盘执行一次按下和松开
control1.pressed('a')
三, 键盘鼠标的监听
1,键盘监听
监听键盘呢只监听两个事件,一个是按键按下,一个是按键松开。
# 导入pynput库
from pynput import keyboard
# 定义两个函数,当监听到按键按下或按键松开时执行
def key_press(event):
print(f"{event.key} 被按下了!!")
def key_release(event):
print(f"{event.key} 被松开了!!")
# 重点---------非阻塞型监听 这里是调用函数对象,不能带有括号
my_listener = keyboard.Listener(on_press=key_press, on_release=key_release)
# 这种监听就像是你喊开始就开始,你喊结束他就结束
# 监听开始
print("监听开始了")
my_listener.start()
# 监听结束
my_listener.stop()
print("监听结束了")
# 按ESC退出阻塞型监听
def on_down(event):
if event == keyboard.Key.esc:
sys.exit()
# 阻塞型监听 相当于一个While 循环,一直在监听,这个监听没退出不会执行后面的代码
with keyboard.Listener(on_press= on_down) as listener:
listener.join()
print("监听结束了")
2,鼠标监听
鼠标的话有三个事件进行监听,分别是移动,按键,滑轮。
from pynput import mouse
# 定义三个函数对应鼠标的三个监听事件
def on_move(self, x, y):
print(f"鼠标移动到了 {x},{y} 的位置")
def on_m_scroll(self, x, y, dx, dy):
print("滑动了滑轮.")
def on_m_click(self, x, y, button, pressed):
if button == mouse.Button.left:
print("鼠标左键按下")
elif button == mouse.Button.right:
printt("鼠标右键按下")
# 非阻塞型监听
my_listener = mouse.Listener(on_move=on_move, on_scroll=on_m_scroll, on_click=on_m_click)
# 监听开始
print("监听开始了....")
my_listener.start()
# 监听结束
print("监听结束了")
my_listener.stop()
# 阻塞型监听
with mouse.Listener(on_move=on_move, on_scroll=on_m_scroll, on_click=on_m_click) as listener:
listener.join()
四,自己写的键盘鼠标监听记录,并实现执行记录的操作。
其中找监听结束的方法消耗我不少时间,因为我一开始一直使用的是阻塞型监听方法,所以开始记录后无法结束记录,尝试过多线程和多进程结束方法都不行,原因是监听对象本身就是一个线程。
import sys
import tkinter
from tkinter import filedialog
from tkinter import messagebox
from pynput import keyboard
from pynput import mouse
import threading
import time
import inspect
import ctypes
win = tkinter.Tk()
win.title("宏录制")
win.geometry("260x100")
special_key = {
"Key.backspace": keyboard.Key.backspace,
"Key.enter": keyboard.Key.enter,
"Key.space": keyboard.Key.space,
"Key.shift_r": keyboard.Key.shift_r,
"Key.ctrl_r": keyboard.Key.ctrl_r,
"Key.alt_l": keyboard.Key.alt_l,
"Key.ctrl_l": keyboard.Key.ctrl_l,
"Key.shift": keyboard.Key.shift,
"Key.caps_lock": keyboard.Key.caps_lock,
"Key.tab": keyboard.Key.tab,
"Key.page_down": keyboard.Key.page_down,
"Key.page_up": keyboard.Key.page_up,
"Key.end": keyboard.Key.end,
"Key.home": keyboard.Key.home
}
mouse_key = {
"Button.left": mouse.Button.left,
"Button.right": mouse.Button.right
}
def select_file():
txt_path = filedialog.askopenfilename(
title='请选择文件',
# 筛选常见图片文件
filetypes=[('文本', '.txt .TXT')],
)
if txt_path and txt_path.endswith(('.txt', '.TXT')):
file_path_entry["state"] = "normal"
# 图像路径
file_path_entry.delete(0, "end")
file_path_entry.insert(0, txt_path)
# def _async_raise(tid, exctype):
# """raises the exception, performs cleanup if needed"""
# tid = ctypes.c_long(tid)
# if not inspect.isclass(exctype):
# exctype = type(exctype)
# res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
#
# if res == 0:
# raise ValueError("invalid thread id")
# elif res != 1:
# # """if it returns a number greater than one, you're in trouble,
# # and you should call it again with exc=NULL to revert the effect"""
# ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
# raise SystemError("PyThreadState_SetAsyncExc failed")
#
#
# def stop_thread(thread):
# _async_raise(thread.ident, SystemExit)
#
def do_it():
file_path = file_path_entry.get()
last_time = 0
if file_path:
with open(file_path, "r") as f:
do_list = f.read().split("\n")
if do_list[0] != "hello world!!":
messagebox.showinfo("文件选择错误!!", "文件选择错误!!")
else:
control1 = keyboard.Controller()
control2 = mouse.Controller()
print(len(do_list))
s = 0
for i in do_list[1:-1]:
do = i.split(" ")
s += 1
last_time = float(do[0]) - last_time
if last_time < 0.001:
pass
else:
time.sleep(last_time)
if do[1] == "on_down":
if "Key" in do[2]:
control1.press(special_key[do[2]])
else:
control1.press(do[2].replace("'", ""))
elif do[1] == "on_up":
if "Key" in do[2]:
control1.release(special_key[do[2]])
else:
control1.release(do[2].replace("'", ""))
elif do[1] == "on_move":
coordinate = do[2].split(",")
control2.position = (int(coordinate[0]), int(coordinate[1]))
elif do[1] == "on_m_scroll":
control2.scroll(0, int(do[2]))
elif do[1] == "on_m_click":
if do[3] == "True":
control2.press(mouse_key[do[2]])
else:
control2.release(mouse_key[do[2]])
last_time = float(do[0])
messagebox.showinfo("提示", "执行完成!!")
class my_do:
def __init__(self):
self.start = 0
self.file_name = 0
self.m_l = 0
self.k_l = 0
def on_down(self, event):
s = (time.time() - self.start)
with open(f"{self.file_name}.txt", 'a') as f:
f.write(f"{s} on_down {event}\n")
def on_up(self, event):
s = (time.time() - self.start)
with open(f"{self.file_name}.txt", 'a') as f:
f.write(f"{s} on_up {event}\n")
def on_move(self, x, y):
print(1)
s = (time.time() - self.start)
with open(f"{self.file_name}.txt", 'a') as f:
f.write(f"{s} on_move {x},{y}\n")
def on_m_scroll(self, x, y, dx, dy):
s = (time.time() - self.start)
with open(f"{self.file_name}.txt", 'a') as f:
f.write(f"{s} on_m_scroll {dy}\n")
def on_m_click(self, x, y, button, pressed):
s = (time.time() - self.start)
with open(f"{self.file_name}.txt", 'a') as f:
f.write(f"{s} on_m_click {button} {pressed}\n")
dodo = my_do()
def make_do():
dodo.file_name = time.strftime("%Y.%m.%d %H.%M", time.localtime())
# 开始时间
dodo.start = time.time()
bg_button["state"] = "disable"
end_button["state"] = "normal"
with open(f"{dodo.file_name}.txt", 'a') as f:
f.write("hello world!!\n")
dodo.m_l = mouse.Listener(on_move=dodo.on_move, on_scroll=dodo.on_m_scroll, on_click=dodo.on_m_click)
dodo.k_l = keyboard.Listener(on_press=dodo.on_down, on_release=dodo.on_up)
dodo.m_l.start()
dodo.k_l.start()
def write_do():
make_do()
end_button["state"] = "normal"
bg_button["state"] = "disable"
def write_end():
dodo.m_l.stop()
dodo.k_l.stop()
end_button["state"] = "disable"
bg_button["state"] = "normal"
bg_button = tkinter.Button(win, text="开始录制", font=("kaiti", 15), fg="blue", command=write_do)
end_button = tkinter.Button(win, text="结束录制", font=("kaiti", 15), fg="red", state="disable", command=write_end)
bg_do_button = tkinter.Button(win, text="开始执行", font=("kaiti", 15), command=do_it)
file_path_entry = tkinter.Entry(win, width=10, font=("kaiti", 18), state="disable")
select_file_entry = tkinter.Button(win, width=1, text="▼", font=("kaiti", 12), command=select_file)
bg_button.place(x=10, y=10)
end_button.place(x=152, y=10)
bg_do_button.place(x=152, y=50)
file_path_entry.place(x=10, y=56)
select_file_entry.place(x=115, y=56)
if __name__ == "__main__":
win.mainloop()