Search code examples
python-3.xmultithreadingautomationpython-multiprocessingpyautogui

Multi - threading click macro / click recorder


I am working on a script that will listen to keystrokes till the 'q' button is pressed, afterwards it should stop the script and print out the mouse positions that were saved in 2 seconds intervals. I can't manage the threads and I am still learning this topic. Each time I run the code nothing happens but the process is running:

from pynput.keyboard import Listener
import pyautogui
from multiprocessing import Process

import time

mouse_positions = []
def func1():
while True:
    time.sleep(2)
    mouse_positions.append(pyautogui.position())

cordinates = []
quit_status = False
keystrokes = []
    
def on_press(key):
    if "q" in str(key) :
        print('q was pressed!')
        exit("Stopped running")
        #qprint(key)
    keystrokes.append(key)
    print(keystrokes)
        #print(keystrokes)

if __name__ == '__main__':
    p1 = Process(target=func1)
    p1.start()
    p1.join()
    with Listener(on_press=on_press) as listener:  # Create an instance of Listener
        listener.join()  # Join the listener thread to the main thread to keep waiting for keys

EDIT : To anyone intrested, here is a click macro I built, script I built previously was more like mouse capture movement. The script below will record your mouse clicks and afterwards will replay them. Much better.

from pynput.keyboard import Listener
import pyautogui
from pynput import mouse
import time

x_pos = []
y_pos = []
both_pos = []
pressed_key  = None

def on_click(x, y, button, pressed):
    if pressed:
        #print ("{0} {1}".format(x,y))
        print(pressed_key)
        if pressed_key == "1":
            both_pos.append("{0}".format(x,y))
            both_pos.append("{1}".format(x,y))
            #print("test" + x_pos + y_pos)
            print (x_pos + y_pos)
        else:
            pass
        if pressed_key == 'q':
            return False

def on_press(key):
    print("To replay press 'q' , to stop recording press '1' , to record again press '1' .")
    global pressed_key
    if 'Key.esc' in str(key):
        return False
    if '1' in str(key):
        pressed_key= None if pressed_key == '1' else '1'
    if 'q' in str(key):
        print("Replaying actions")
        print(str(len(both_pos)))
        for point in range(0,len(both_pos),2):
            time.sleep(3)
            print("clicking")
            pyautogui.click(x=int(both_pos[point]),y=int(both_pos[point+1]))
        print("done...")
        return False
        


mouse_listener = mouse.Listener(on_click=on_click)
mouse_listener.start()
with Listener(on_press=on_press) as listener:  # Create an instance of Listener
    listener.join()
    #print(mouse_listener.mouse_positions)

Solution

  • Hi you can use threading module. I have created class MouseListener which inherit from threading.Thread class. Everything what you want to run put into run method. As thread stopper I used still_run attribute. When you are typing, I pass to on_press function pressed key and mouse_listener. If q is pressed I set mouse_listener.still_run to False, what leads to stop the mouse listener.

    mouse_positions I moved from global scope to MouseListener.

    
    import threading
    
    from pynput.keyboard import Listener
    import pyautogui
    
    import time
    
    
    class MouseListener(threading.Thread):
        still_run = True
        mouse_positions = []
        def run(self):
            self.func()
    
        def func(self):
            while self.still_run:
                time.sleep(2)
                self.mouse_positions.append(pyautogui.position())
                print(self.mouse_positions)
    
    coordinates = []
    quit_status = False
    keystrokes = []
    
    
    def on_press(key, mouse_listener):
        print('kp')
        if "q" in str(key):
            print('q was pressed!')
            mouse_listener.still_run = False
            print(key)
            exit("Stopped running")
        keystrokes.append(key)
        print(keystrokes)
        print(keystrokes)
    
    
    if __name__ == '__main__':
        mouse_listener = MouseListener()
        mouse_listener.start()
        with Listener(on_press=lambda key: on_press(key, mouse_listener)) as listener:  # Create an instance of Listener
            listener.join()
        print(mouse_listener.mouse_positions)