您当前的位置:首页 > 计算机 > 编程开发 > Python

使用Python实现一个按键精灵

时间:08-23来源:作者:点击数:

按键精灵想必很多人都玩过,使用录制功能将鼠标和键盘的操作录制下来,录制好后就可以通过回放自动执行之前录制的操作,可以设置重复执行的次数,这样就可以将一些重复的劳动交给脚本自动化去完成。使用Python编写一个和脚本精灵一样的程序非常简单,并且代码量足够少,好处是可以不再依赖按键精灵,像我这种有轻微洁癖的程序猿就喜欢自己动手实现,依赖Python的为所欲为的特性,可以任意编码让自己的按键精灵更加强大。

按键精灵的实现可以拆解分为录制和回放两个步骤,对应到Python程序的实现也可以分为两步:

1.监听鼠标键盘的事件和坐标,写入到文件中记录起来。

2.读取监听时写入的文件,执行文件中的坐标和事件操作。

要实现这两个功能,得先从基础开始。我把任务拆解成两大部分,鼠标和键盘属于不同的两个输入设备,所以分开实现“鼠标精灵”和“键盘精灵”两个程序,最后融合这两个模块实现一个相对完整的按键精灵。

Python操作键盘鼠标的库推荐pynput这个库、地址:

https://pypi.org/project/pynput/

鼠标事件监听
from pynput import mouse


# 鼠标移动事件
def on_move(x, y):
    print('[Move]', (x, y))


# 鼠标点击事件
def on_click(x, y, button, pressed):
    print('[Click]', (x, y, button.name, pressed))


# 鼠标滚动事件
def on_scroll(x, y, x_axis, y_axis):
    print('[Scroll]', (x, y, x_axis, y_axis))


# 监听事件绑定
with mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:
    listener.join()

onMove(x,y)函数接收鼠标当前的x轴和y轴坐标,启动程序并移动鼠标时,就会调用该方法。

on_click(x, y, button, pressed)函数接收鼠标的点击事件,x和y为当前点击事件的鼠标坐标,button参数对象的name属性值为left或者right,通过该属性值可以判断是鼠标的左键还是右键产生的点击事件,pressed参数值为True时表示当前鼠标左或右键按压,False时表示鼠标左或右键抬起事件。

on_scroll(x, y, x_axis, y_axis)接收四个参数,前两个参数依旧是当前事件的鼠标坐标轴,x_axis的值>0表示向上,<0表示向下,同样的y_axis的负值和正值代表左滑和右滑状态。

鼠标事件执行
from pynput.mouse import Button, Controller
import time

# 获取鼠标对象
mouse = Controller()

# 输出鼠标当前的坐标
print(mouse.position)

# 将新的坐标赋值给鼠标对象
mouse.position = (100, 500)

for index in range(0, 30):
    # 鼠标移动到指定坐标轴
    mouse.move(index, -index)
    print(mouse.position)
    time.sleep(0.01)

for index in range(0, 30):
    # 鼠标移动到指定坐标轴
    mouse.move(-index, index)
    print(mouse.position)
    time.sleep(0.01)

# 鼠标右键按下
mouse.press(Button.right)

time.sleep(0.01)

# 鼠标右键抬起
mouse.release(Button.right)

# 鼠标左键点击
mouse.click(Button.left, 1)

# 鼠标滚轮滚动距离500
mouse.scroll(0, 500)

和鼠标事件监听一样,对应的我们可以操作鼠标的各种事件:移动、左/右按压、左/右抬起、左/右点击、上下左右滚动

上面代码中的mouse.move(x,y)函数,表示从当前鼠标位置进行位移的距离,x和y的值是以当前位置为0点开始算的。

而且不能简单的用坐标轴去相减得到位移距离,所以后续的程序我会使用mouse.position = (x, y)这个函数来操作鼠标的移动,

这个函数可以将鼠标设置到指定位置,只要我们记录之前的鼠标移动轨迹,就可以通过读取之前的记录文件按顺序重新对鼠标进行赋值操作。达到回放的效果。

带录制回放功能的鼠标精灵

结合鼠标事件的监听和执行,并且将事件记录到文件中,再加上Python自带的GUI,就可以写出一个简单的鼠标精灵了。

实现思路:

  1. 定义一个json格式的对象来统一不同鼠标事件的内容格式
{
    "name":"mouse",
    "event":"click",
    "target":"left",
    "action":true,
    "location":{
        "x":"0",
        "y":"0"
    }
}

鼠标事件的name值为mouse,考虑到后续还有可能会有其他设备的事件,比如键盘事件。

鼠标的事件为点击事件,将event赋值为click

target表示目标,点击了鼠标左键,所以目标值为left

action表示动作,鼠标点击分为按压和抬起,true表示抬起。

location的值包含一个json对象,里面为当前事件鼠标的x和y坐标。

鼠标的移动和滑动事件以此类推,用同样的模板格式进行记录。

  1. 将记录的数据写入到文件中
  2. 执行回放时通过逐行读取文件,解析文件中的json数据通过nameeventlocation等值进行事件执行。

之所以选择json时因为解析起来比较方便。当然你也可以使用数据库,比如SQLite等,或者自己定义一套自己的格式。

json的存储方式有太多的冗余字符了,空间占用目前不是考虑的首要因素,这里先用最快的方式实现它。

GUI用了Python自带的tkinter库,为了防止UI阻塞,所以使用了多线程,同样是Python自带库threading

整个实现其实只用了一个三方库 pynput

鼠标事件的监听录制和执行回放的完整代码如下:

import json
import threading
import time
import tkinter

from pynput import mouse
from pynput.mouse import Button, Controller


# 鼠标动作模板
def mouse_action_template():
    return {
        "name": "mouse",
        "event": "default",
        "target": "default",
        "action": "default",
        "location": {
            "x": "0",
            "y": "0"
        }
    }


# 鼠标动作监听
class MouseActionListener(threading.Thread):

    def __init__(self, file_name):
        super().__init__()
        self.file_name = file_name

    def run(self):
        with open(self.file_name, 'w', encoding='utf-8') as file:
            # 鼠标移动事件
            def on_move(x, y):
                template = mouse_action_template()
                template['event'] = 'move'
                template['location']['x'] = x
                template['location']['y'] = y
                file.writelines(json.dumps(template) + "\n")
                file.flush()

            # 鼠标点击事件
            def on_click(x, y, button, pressed):
                template = mouse_action_template()
                template['event'] = 'click'
                template['target'] = button.name
                template['action'] = pressed
                template['location']['x'] = x
                template['location']['y'] = y
                file.writelines(json.dumps(template) + "\n")
                file.flush()

            # 鼠标滚动事件
            def on_scroll(x, y, x_axis, y_axis):
                template = mouse_action_template()
                template['event'] = 'scroll'
                template['location']['x'] = x_axis
                template['location']['y'] = y_axis
                file.writelines(json.dumps(template) + "\n")
                file.flush()

            with mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:
                listener.join()


# 鼠标动作执行
class MouseActionExecute(threading.Thread):

    def __init__(self, file_name):
        super().__init__()
        self.file_name = file_name

    def run(self):
        with open(self.file_name, 'r', encoding='utf-8') as file:
            mouse_exec = Controller()
            line = file.readline()
            time.sleep(0.01)
            while line:
                obj = json.loads(line)
                if obj['name'] == 'mouse':
                    if obj['event'] == 'move':
                        mouse_exec.position = (obj['location']['x'], obj['location']['y'])
                        time.sleep(0.01)
                    elif obj['event'] == 'click':
                        if obj['action']:
                            if obj['target'] == 'left':
                                mouse_exec.press(Button.left)
                            else:
                                mouse_exec.press(Button.right)
                        else:
                            if obj['target'] == 'left':
                                mouse_exec.release(Button.left)
                            else:
                                mouse_exec.release(Button.right)
                        time.sleep(0.01)
                    elif obj['event'] == 'scroll':
                        mouse_exec.scroll(obj['location']['x'], obj['location']['y'])
                        time.sleep(0.01)
                line = file.readline()


def button_onClick(action):

    m1 = MouseActionListener(file_name='mouse.action')
    m2 = MouseActionExecute(file_name='mouse.action')

    if action == 'listener':
        if startListenerBtn['text'] == '录制':
            m1.start()
            startListenerBtn['text'] = '录制中...关闭程序停止录制'
            startListenerBtn['state'] = 'disabled'

    elif action == 'execute':
        if startExecuteBtn['text'] == '回放':
            m2.start()
            startExecuteBtn['text'] = '回放中...关闭程序停止回放'
            startExecuteBtn['state'] = 'disabled'


if __name__ == '__main__':

    root = tkinter.Tk()
    root.title('鼠标精灵-蓝士钦')
    root.geometry('200x200+400+100')

    startListenerBtn = tkinter.Button(root, text="录制", command=lambda: button_onClick('listener'))
    startListenerBtn.place(x=10, y=10, width=180, height=80)

    startExecuteBtn = tkinter.Button(root, text="回放", command=lambda: button_onClick('execute'))
    startExecuteBtn.place(x=10, y=110, width=180, height=80)
    root.mainloop()

按键精灵的鼠标部分到这里就基本完成了。

运行程序,点击录制,然后就可以用你的鼠标在屏幕上一顿操作。然后关闭本程序。

接着重新打开程序,点击回放,就会发现鼠标可以按照之前录制的动作进行自动工作了。

记住千万不要在录制时,还没关闭程序的时候就点击回放,这样会陷入无限循环里面,会导致不停的录制不停的回放。

还有键盘的程序后续补上,程序待完善中,未完待续。

键盘事件监听
from pynput import keyboard


# 按键按下监听
def on_press(key):
    try:
        print('press key {0}, vk: {1}'.format(key.char, key.vk))
    except AttributeError:
        print('special press key {0}, vk: {1}'.format(key, key.value.vk))


# 按键释放监听
def on_release(key):

    if key == keyboard.Key.esc:
        # 停止监听
        return False

    try:
        print('release key {0}, vk: {1}'.format(key.char, key.vk))
    except AttributeError:
        print('special release key {0}, vk: {1}'.format(key, key.value.vk))


# 键盘监听
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
    listener.join()

键盘监听相对于鼠标监听来说,回调的函数只有两个on_press按键按下 和on_release按键释放。

由于pynput这个库对键盘的不同按键事件封装进行了区分,比如普通的数字和字母键按下会进入on_press方法,通过传入的key.char属性值可以得到按键对应在键盘上的字符,但如果是Shift等其他特殊键,就没有char属性,会产生异常。

只要捕获异常后直接通过key就可以取到特殊键对应的字符。我觉得这是pynput做得有点不够优雅的地方。

普通的键有key.vk属性值,代表键盘上字符对应的编码值,特殊键的编码值要通过key.value.vk来取。

键盘事件执行
from pynput.keyboard import Key, Controller, KeyCode

# 键盘控制对象
keyboard = Controller()

# 按下 a 键
keyboard.press('a')
# 释放 a 键
keyboard.release('a')

# 按下 Shift 键
keyboard.press(Key.shift)
keyboard.press('b')
keyboard.release('b')
keyboard.press('c')
keyboard.release('c')
# 释放 Shift 键
keyboard.release(Key.esc)

# 按下 Shift 键,然后依次按下其他按键,完成后Shift键自动释放
with keyboard.pressed(Key.shift):
    keyboard.press('d')
    keyboard.release('d')
    keyboard.press('e')
    keyboard.release('e')

# 依次按下 python (包括前面的空格)
keyboard.type(' python')

# 按下 vk值为56的键 shift 键
keyboard.touch(KeyCode.from_vk(56), True)
keyboard.touch('a', True)
keyboard.touch('a', False)
# 释放 shift 键
keyboard.touch(Key.shift, False)

和监听方法对应,执行键盘的按键方法有press(key)按压 release(key)释放。

除此之外还有touch(key,is_press)函数,key表示要操作的键,is_press 为True时表示按压,为False时表示释放。

无论是哪种按压事件,Key都可以通过其他方式构造,比如知道Shift的vk值为56,那么就可以通过KeyCode.from_vk(56)来构造一个Shift的Key。

通过VK编码构造Key的方式很有用,因为当你要按出一个@符号时,需要同时按住Shift2。通过on_press(key)监听得到的值是一个@符号,如果录制程序录制了一个@符号将无法通过keyboard.press('@')这种方式直接执行。

所以接下来的键盘录制回放程序我将通过定义一个键盘动作模板,然后通过VK值准确的记录每个键以及每个组合键的编码。然后通过keyboard.press(KeyCode.from_vk(vk))进行回放。

带录制回放功能的键盘精灵
import json
import threading
import time
import tkinter

from pynput import keyboard
from pynput.keyboard import Controller, KeyCode


# 键盘动作模板
def keyboard_action_template():
    return {
        "name": "keyboard",
        "event": "default",
        "vk": "default"
    }


# 键盘动作监听
class KeyboardActionListener(threading.Thread):

    def __init__(self, file_name):
        super().__init__()
        self.file_name = file_name

    def run(self):
        with open(self.file_name, 'w', encoding='utf-8') as file:
            # 键盘按下监听
            def on_press(key):
                template = keyboard_action_template()
                template['event'] = 'press'
                try:
                    template['vk'] = key.vk
                except AttributeError:
                    template['vk'] = key.value.vk
                finally:
                    file.writelines(json.dumps(template) + "\n")
                    file.flush()

            # 键盘抬起监听
            def on_release(key):
                if key == keyboard.Key.esc:
                    # 停止监听
                    startListenerBtn['text'] = '录制'
                    startListenerBtn['state'] = 'normal'
                    return False
                template = keyboard_action_template()
                template['event'] = 'release'
                try:
                    template['vk'] = key.vk
                except AttributeError:
                    template['vk'] = key.value.vk
                finally:
                    file.writelines(json.dumps(template) + "\n")
                    file.flush()

            # 键盘监听
            with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
                listener.join()


# 键盘动作执行
class KeyboardActionExecute(threading.Thread):

    def __init__(self, file_name):
        super().__init__()
        self.file_name = file_name

    def run(self):
        with open(self.file_name, 'r', encoding='utf-8') as file:
            keyboard_exec = Controller()
            line = file.readline()
            time.sleep(3)
            while line:
                obj = json.loads(line)
                if obj['name'] == 'keyboard':
                    if obj['event'] == 'press':
                        keyboard_exec.press(KeyCode.from_vk(obj['vk']))
                        time.sleep(0.01)

                    elif obj['event'] == 'release':
                        keyboard_exec.release(KeyCode.from_vk(obj['vk']))
                        time.sleep(0.01)
                line = file.readline()
            startExecuteBtn['text'] = '回放'
            startExecuteBtn['state'] = 'normal'


def button_onClick(action):
    m1 = KeyboardActionListener(file_name='keyboard.action')
    m2 = KeyboardActionExecute(file_name='keyboard.action')

    if action == 'listener':
        if startListenerBtn['text'] == '录制':
            m1.start()
            startListenerBtn['text'] = '录制中...esc停止录制'
            startListenerBtn['state'] = 'disabled'

    elif action == 'execute':
    	startListenerBtn.place(x=10, y=10, width=180, height=80)
    	startExecuteBtn = tkinter.Button(root, text="回放", command=lambda: button_onClick('execute'))
    	startExecuteBtn.place(x=10, y=110, width=180, height=80)
    	root.mainloop()

键盘精灵的录制和回放程序到这里以及算是一个基础版本了,可以正常使用。并且新增了esc键监听,当用户点击esc时将会结束录制。

鼠标精灵键盘精灵都可以单独的运行使用。

大多数场景下这两者的功能都会使用到,所以接下来我要实现一个完成的按键精灵,同时包含鼠标和键盘的录制回放功能。

在之前的代码基础上进一步封装。

考虑的基本要素如下:

  1. 记录鼠标和记录键盘的事件采用不同的json模板进行定义,采用响应式对用户的操作进行监听,用户静止不动则不会写入文件。
  2. 同时监听鼠标和键盘,为了避免多线程写同一个文件的锁操作,我将鼠标和键盘的录制记录分为两个不同的文件。
  3. 录制和回放的操作通常都需要有一个等待时间的设置,所以代码里加上了GUI的设置部分,GUI没有设计所以后续这块代码要优化。
  4. 考虑录制和回放倒计时需要UI提示用户并且定时触发线程执行,所以封装了一个UI更新线程的类。

按键精灵0.1版本完整代码如下:

键鼠录制的按键精灵0.1版本
import json
import threading
import time
import tkinter

from pynput import keyboard, mouse
from pynput.keyboard import Controller as KeyBoardController, KeyCode
from pynput.mouse import Button, Controller as MouseController


# 键盘动作模板
def keyboard_action_template():
    return {
        "name": "keyboard",
        "event": "default",
        "vk": "default"
    }


# 鼠标动作模板
def mouse_action_template():
    return {
        "name": "mouse",
        "event": "default",
        "target": "default",
        "action": "default",
        "location": {
            "x": "0",
            "y": "0"
        }
    }


# 倒计时监听,更新UI触发自定义线程对象
class UIUpdateCutDownExecute(threading.Thread):
    def __init__(self, cut_down_time, custom_thread_list):
        super().__init__()
        self.cut_down_time = cut_down_time
        self.custom_thread_list = custom_thread_list

    def run(self):
        while self.cut_down_time > 0:
            for custom_thread in self.custom_thread_list:
                if custom_thread['obj_ui'] is not None:
                    custom_thread['obj_ui']['text'] = str(self.cut_down_time)
                    custom_thread['obj_ui']['state'] = 'disabled'
                    self.cut_down_time = self.cut_down_time - 1
            time.sleep(1)
        else:
            for custom_thread in self.custom_thread_list:
                if custom_thread['obj_ui'] is not None:
                    custom_thread['obj_ui']['text'] = custom_thread['final_text']
                    custom_thread['obj_ui']['state'] = 'disabled'
                if custom_thread['obj_thread'] is not None:
                    custom_thread['obj_thread'].start()
                    time.sleep(1)


# 键盘动作监听
class KeyboardActionListener(threading.Thread):

    def __init__(self, file_name='keyboard.action'):
        super().__init__()
        self.file_name = file_name

    def run(self):
        with open(self.file_name, 'w', encoding='utf-8') as file:
            # 键盘按下监听
            def on_press(key):
                template = keyboard_action_template()
                template['event'] = 'press'
                try:
                    template['vk'] = key.vk
                except AttributeError:
                    template['vk'] = key.value.vk
                finally:
                    file.writelines(json.dumps(template) + "\n")
                    file.flush()

            # 键盘抬起监听
            def on_release(key):
                if key == keyboard.Key.esc:
                    # 停止监听
                    startListenerBtn['text'] = '开始录制'
                    startListenerBtn['state'] = 'normal'
                    keyboardListener.stop()
                    return False
                template = keyboard_action_template()
                template['event'] = 'release'
                try:
                    template['vk'] = key.vk
                except AttributeError:
                    template['vk'] = key.value.vk
                finally:
                    file.writelines(json.dumps(template) + "\n")
                    file.flush()

            # 键盘监听
            with keyboard.Listener(on_press=on_press, on_release=on_release) as keyboardListener:
                keyboardListener.join()


# 键盘动作执行
class KeyboardActionExecute(threading.Thread):

    def __init__(self, file_name='keyboard.action', execute_count=0):
        super().__init__()
        self.file_name = file_name
        self.execute_count = execute_count

    def run(self):
        while self.execute_count > 0:
            with open(self.file_name, 'r', encoding='utf-8') as file:
                keyboard_exec = KeyBoardController()
                line = file.readline()
                while line:
                    obj = json.loads(line)
                    if obj['name'] == 'keyboard':
                        if obj['event'] == 'press':
                            keyboard_exec.press(KeyCode.from_vk(obj['vk']))
                            time.sleep(0.01)

                        elif obj['event'] == 'release':
                            keyboard_exec.release(KeyCode.from_vk(obj['vk']))
                            time.sleep(0.01)
                    line = file.readline()
                startExecuteBtn['text'] = '开始回放'
                startExecuteBtn['state'] = 'normal'
            self.execute_count = self.execute_count - 1


# 鼠标动作监听
class MouseActionListener(threading.Thread):

    def __init__(self, file_name='mouse.action'):
        super().__init__()
        self.file_name = file_name

    def run(self):
        with open(self.file_name, 'w', encoding='utf-8') as file:
            # 鼠标移动事件
            def on_move(x, y):
                template = mouse_action_template()
                template['event'] = 'move'
                template['location']['x'] = x
                template['location']['y'] = y
                file.writelines(json.dumps(template) + "\n")
                file.flush()

            # 鼠标点击事件
            def on_click(x, y, button, pressed):
                template = mouse_action_template()
                template['event'] = 'click'
                template['target'] = button.name
                template['action'] = pressed
                template['location']['x'] = x
                template['location']['y'] = y
                file.writelines(json.dumps(template) + "\n")
                file.flush()

            # 鼠标滚动事件
            def on_scroll(x, y, x_axis, y_axis):
                template = mouse_action_template()
                template['event'] = 'scroll'
                template['location']['x'] = x_axis
                template['location']['y'] = y_axis
                file.writelines(json.dumps(template) + "\n")
                file.flush()

            with mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as mouseListener:
                mouseListener.join()


# 鼠标动作执行
class MouseActionExecute(threading.Thread):

    def __init__(self, file_name='mouse.action', execute_count=0):
        super().__init__()
        self.file_name = file_name
        self.execute_count = execute_count

    def run(self):
        while self.execute_count > 0:
            with open(self.file_name, 'r', encoding='utf-8') as file:
                mouse_exec = MouseController()
                line = file.readline()
                while line:
                    obj = json.loads(line)
                    if obj['name'] == 'mouse':
                        if obj['event'] == 'move':
                            mouse_exec.position = (obj['location']['x'], obj['location']['y'])
                            time.sleep(0.01)
                        elif obj['event'] == 'click':
                            if obj['action']:
                                if obj['target'] == 'left':
                                    mouse_exec.press(Button.left)
                                else:
                                    mouse_exec.press(Button.right)
                            else:
                                if obj['target'] == 'left':
                                    mouse_exec.release(Button.left)
                                else:
                                    mouse_exec.release(Button.right)
                            time.sleep(0.01)
                        elif obj['event'] == 'scroll':
                            mouse_exec.scroll(obj['location']['x'], obj['location']['y'])
                            time.sleep(0.01)
                    line = file.readline()


def command_adapter(action):
    if action == 'listener':
        if startListenerBtn['text'] == '开始录制':
            custom_thread_list = [
                {
                    'obj_thread': KeyboardActionListener(),
                    'obj_ui': startListenerBtn,
                    'final_text': '录制中...esc停止录制'
                },
                {
                    'obj_thread': MouseActionListener(),
                    'obj_ui': None,
                    'final_text': None
                }
            ]
            UIUpdateCutDownExecute(startTime.get(), custom_thread_list).start()

    elif action == 'execute':
        if startExecuteBtn['text'] == '开始回放':
            custom_thread_list = [
                {
                    'obj_thread': KeyboardActionExecute(execute_count=playCount.get()),
                    'obj_ui': startExecuteBtn,
                    'final_text': '回放中...关闭程序停止回放'
                },
                {
                    'obj_thread': MouseActionExecute(execute_count=playCount.get()),
                    'obj_ui': None,
                    'final_text': None
                }
            ]
            UIUpdateCutDownExecute(endTime.get(), custom_thread_list).start()


def isNumber(content):
    if content.isdigit() or content == "":
        return True
    else:
        return False


if __name__ == '__main__':
    root = tkinter.Tk()
    root.title('按键精灵-蓝士钦')
    root.geometry('200x200+400+100')

    listenerStartLabel = tkinter.Label(root, text='录制倒计时')
    listenerStartLabel.place(x=10, y=10, width=80, height=20)
    startTime = tkinter.IntVar()
    listenerStartEdit = tkinter.Entry(root, textvariable=startTime)
    listenerStartEdit.place(x=100, y=10, width=60, height=20)
    startTime.set(3)

    listenerTipLabel = tkinter.Label(root, text='秒')
    listenerTipLabel.place(x=160, y=10, width=20, height=20)

    startListenerBtn = tkinter.Button(root, text="开始录制", command=lambda: command_adapter('listener'))
    startListenerBtn.place(x=10, y=45, width=180, height=30)

    executeEndLabel = tkinter.Label(root, text='回放倒计时')
    executeEndLabel.place(x=10, y=85, width=80, height=20)
    endTime = tkinter.IntVar()
    executeEndEdit = tkinter.Entry(root, textvariable=endTime)
    executeEndEdit.place(x=100, y=85, width=60, height=20)
    endTime.set(6)

    executeTipLabel = tkinter.Label(root, text='秒')
    executeTipLabel.place(x=160, y=85, width=20, height=20)

    playCountLabel = tkinter.Label(root, text='回放次数')
    playCountLabel.place(x=10, y=115, width=80, height=20)
    playCount = tkinter.IntVar()
    playCountEdit = tkinter.Entry(root, textvariable=playCount)
    playCountEdit.place(x=100, y=115, width=60, height=20)
    playCount.set(1)

    playCountTipLabel = tkinter.Label(root, text='次')
    playCountTipLabel.place(x=160, y=115, width=20, height=20)

    startExecuteBtn = tkinter.Button(root, text="开始回放", command=lambda: command_adapter('execute'))
    startExecuteBtn.place(x=10, y=145, width=180, height=30)
    root.mainloop()

脚本精灵0.1版本完成?

image

还需要考虑的点:

  1. 键盘事件没有记录用户每个动作之间的延迟时间,无法准确重放用户的输入节奏,后续考虑记录时间间隔点。
  2. 鼠标事件用户移动的越快,产生的点位变化也就越频繁,所以鼠标在回放时的速度与用户的操作基本一致。
  3. 鼠标没有停止回放的快捷键,要考虑如何停止回放鼠标事件。
  4. 输入法切换可能导致重放键盘按键时输入不准确,需要录制时是什么输入状态,重放时也要对应的键盘属性和状态
  5. …还有很多需要考虑的点(原本只是想简单的做个示例程序)

程序只在MacOS平台上实验过,其他平台还未实验,一个相对完整的按键精灵在录制时应该获取更多的信息,这样在回放的时候才足够准确,后续考虑做一个更加精确的按键精灵,比如加入获取屏幕像素点,回放时通过采样比对,达到为所欲为功能。

GitHub地址:

https://github.com/lanshiqin/JerryMouse

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐