Search code examples
pythonpython-3.xmacros

how do I store keyboard.record to a txt file and call it with keyboard.play


I am trying to create a macro that i can call in python , the macro would record what buttons i pressed , how long i pressed them for, and the time between button presses

i want to be able to store the macro in a txt file so i can call it back with another function later on in time

this was the basic idea i thought off since i can use rk = keyboard.record(until ='Esc') then after i done recording the macro i use keyboard.play(rk, speed_factor=1) , that concept i just described works wonderfull, but i want to be able to store the rk = keyboard.record(until ='Esc') into a txt file and then be able to read it from the file and play it

this code below is the idea i was trying to achieve but it doesn't work

from pynput.keyboard import Key, Listener
import keyboard
import time


def recorder():
    rk = keyboard.record(until ='Esc')
    file = open("test.txt", "a")
    for r in rk:
        data = str(r) + "\n"
        file.write(data)

def play_back():
    file = open("test.txt", "r")
    lists = []

    Lines = file.readlines()
    
    count = 0
    # Strips the newline character
    for line in Lines:
        count += 1
        if line[-1] == "\n":
            lists.append(line[:-1])
        else:
            lists.append(line)

    print(lists)

    keyboard.play(lists, speed_factor=1)

this is the error code that appears after i call on the play_back() function

['KeyboardEvent(s down)', 'KeyboardEvent(s up)', 'KeyboardEvent(s down)', 'KeyboardEvent(s up)', 'KeyboardEvent(a down)', 'KeyboardEvent(a up)', 'KeyboardEvent(a down)', 'KeyboardEvent(a up)', 'KeyboardEvent(d down)', 'KeyboardEvent(d up)', 'KeyboardEvent(d down)', 'KeyboardEvent(d up)', 'KeyboardEvent(backspace down)', 'KeyboardEvent(backspace up)', 'KeyboardEvent(backspace down)', 'KeyboardEvent(backspace up)', 'KeyboardEvent(backspace down)', 'KeyboardEvent(backspace up)', 'KeyboardEvent(backspace down)', 'KeyboardEvent(backspace up)', 'KeyboardEvent(backspace down)', 'KeyboardEvent(backspace up)', 'KeyboardEvent(backspace down)', 'KeyboardEvent(backspace up)', 'KeyboardEvent(esc down)', 'KeyboardEvent(left down)', 'KeyboardEvent(left up)', 'KeyboardEvent(down down)', 'KeyboardEvent(down up)', 'KeyboardEvent(right down)', 'KeyboardEvent(right up)', 'KeyboardEvent(right down)', 'KeyboardEvent(right up)', 'KeyboardEvent(s down)', 'KeyboardEvent(s up)', 'KeyboardEvent(s down)', 'KeyboardEvent(s up)', 'KeyboardEvent(d down)', 'KeyboardEvent(d up)', 'KeyboardEvent(a down)', 'KeyboardEvent(a up)', 'KeyboardEvent(s down)', 'KeyboardEvent(s up)', 'KeyboardEvent(esc down)']
Traceback (most recent call last):
  File "c:\Users\pc\Desktop\code\program1\testing122.py", line 33, in <module>
    play_back()
  File "c:\Users\pc\Desktop\code\program1\testing122.py", line 31, in play_back
    keyboard.play(lists, speed_factor=1)
  File "C:\Users\pc\Desktop\code\program1\venv001\Lib\site-packages\keyboard\__init__.py", line 1060, in play
    last_time = event.time
                ^^^^^^^^^^
AttributeError: 'str' object has no attribute 'time'. Did you mean: 'title'?

so just to summarize : I want to record a macro of my exact button presses including the timings within (how much I press a button for, how much time time between 2 button presses) i then want to be able to call that record with a function in python , my approach here might be wrong so i would love your inputs

Thanks in advance

update: with the help of LhasaDad he came up with this bit of code that records the keyboard inputs and puts them in a txt file and call them back with theplay_back() function

def recorder():
    rk = keyboard.record(until ='Esc')
    file = open("test.txt", "w")

    for r in rk:
        # serialize the object to json format
        data = r.to_json() + "\n"
        file.write(data)

    file.close()


def play_back():
    lists = []
    with open("test.txt", "r") as file:

        lines = file.readlines()

        # Strips the newline character
        for line in lines:
            # recreate the object from the json dict by loading the json and
            # use as keyword parameters to KeyboardEvent
            lists.append(keyboard.KeyboardEvent(**json.loads(line)))

    print(lists)

    keyboard.play(lists, speed_factor=1)

now the problem now is a wierd one if i run the code by calling therecorder() function followed by the play_back() like this

recorder()
play_back()

it works as intended but if i run the recorder() function first and record my inputs and let the recorder function finish and the program finish running all its code

example

recorder()

so am only running the recorder function that saves it to a file, then i try to run it later with the play_back after the first program is done

play_back()

it doesnot work


Solution

  • ok i have found the answer , it turns out there is a problem withing the keyboard.record and keyboard.play for some reason as mentioned in this stack overflow article over here

    keyboard.play function not working correctly

    here is the solution

    from pynput.keyboard import Key, Listener
    import keyboard
    import time
    import json
    import pickle
    
    
    def recorder():
        with open('keys.txt','wb') as f:
            pickle.dump(keyboard.record(until='*'),f)
    
    
    def play_back():
        keyboard.start_recording()
        keyboard.stop_recording()
    
        with open('keys.txt','rb') as f:
            keyboard.play(pickle.load(f))
    
    play_back()
    

    in the above example am using pickle and I have already used the record() function to record the actions keyboard.start_recording and keyboard.stop_recording donot impact the code but for some random reason it makes it work

    https://github.com/boppreh/keyboard/issues/283 This is an open issue on the keyboard repository. Looks like keyboard.play() does not initialize the OS-specific modules required to interface with the keyboard (or maybe there's something else going on, I'm not sure).