Vincent Olindo
Vincent Olindo

Reputation: 31

Python 3 Autoclicker On/Off Hotkey

I'm new to Python and I figured I'd make a simple autoclicker as a cool starter project.

I want a user to be able to specify a click interval and then turn the automatic clicking on and off with a hotkey.

I am aware of Ctrl-C, and you'll see that in my current code, but I want the program to work so that the hotkey doesn't have to be activated in the python window.

import pyautogui, sys

print("Press Ctrl + C to quit.")

interval = float(input("Please give me an interval for between clicks in seconds: "))

try:
    while True:
        pyautogui.click()
except KeyboardInterrupt:
print("\n")

Do I need to make a tkinter message box to make the switch or can I use a hotkey?

Thanks for the help.

Update

import multiprocessing
import time
import pyHook, pyautogui, pythoncom
import queue

click_interval = float(input("Please give an interval between clicks in seconds: "))

class AutoClicker(multiprocessing.Process):
    def __init__(self, queue, interval):
        multiprocessing.Process.__init__(self)
        self.queue = queue
        self.click_interval = click_interval

    def run(self):
        while True:
            try:
                task = self.queue.get(block=False)
                if task == "Start":
                    print("Clicking...")
                    pyautogui.click(interval == click_interval)

            except task == "Exit":
                print("Exiting")
                self.queue.task_done()
                break
        return

def OnKeyboardEvent(event):

    key = event.Key

    if key == "F3":
        print("Starting auto clicker")
        # Start consumers
        queue.put("Start")
        queue.join
    elif key == "F4":
        print("Stopping auto clicker")
        # Add exit message to queue
        queue.put("Exit")
        # Wait for all of the tasks to finish
        queue.join()

    # return True to pass the event to other handlers
    return True

if __name__ == '__main__':
    # Establish communication queues
    queue = multiprocessing.JoinableQueue()
    # create a hook manager
    hm = pyHook.HookManager()
    # watch for all mouse events
    hm.KeyDown = OnKeyboardEvent
    # set the hook
    hm.HookKeyboard()
    # wait forever
    pythoncom.PumpMessages()


AutoClicker.run(self)

Upvotes: 2

Views: 6312

Answers (1)

Tom
Tom

Reputation: 1686

First of all if you want to monitor global input outside the Python window you will need pyHook or something similar. It will allow you to monitor keyboard events. I chose to act upon the F3 and F4 key-presses, which are used for starting and stopping the autoclicker.

To accomplish what you've asked, the best way I'm aware of is to create a process which will do the clicking, and to communicate with it through the use of a Queue. When the F4 key is pressed, it will add an "Exit" string to the queue. The autoclicker will recognize this and then return.

Before the F4 key has been pressed, the queue will remain empty and the queue.Empty exception will continually occur. This will execute a single mouse click.

import multiprocessing
import time
import pyHook, pyautogui, pythoncom
import queue

class AutoClicker(multiprocessing.Process):
    def __init__(self, queue, interval):
        multiprocessing.Process.__init__(self)
        self.queue = queue
        self.click_interval = interval

    def run(self):
        while True:
            try:
                task = self.queue.get(block=False)
                if task == "Exit":
                    print("Exiting")
                    self.queue.task_done()
                    break

            except queue.Empty:
                time.sleep(self.click_interval)
                print("Clicking...")
                pyautogui.click()
        return

def OnKeyboardEvent(event):

    key = event.Key

    if key == "F3":
        print("Starting auto clicker")
        # Start consumers
        clicker = AutoClicker(queue, 0.1)
        clicker.start()
    elif key == "F4":
        print("Stopping auto clicker")
        # Add exit message to queue
        queue.put("Exit")
        # Wait for all of the tasks to finish
        queue.join()

    # return True to pass the event to other handlers
    return True

if __name__ == '__main__':
    # Establish communication queues
    queue = multiprocessing.JoinableQueue()
    # create a hook manager
    hm = pyHook.HookManager()
    # watch for all mouse events
    hm.KeyDown = OnKeyboardEvent
    # set the hook
    hm.HookKeyboard()
    # wait forever
    pythoncom.PumpMessages()

Keep in mind this implementation is far from perfect, but hopefully it's helpful as a starting point.

Why can't I use a simple while loop or if/else statement?

A while loop is blocking, which means when the loop is running it blocks all other code from executing.

So once the clicker loop starts it will be stuck in that loop indefinitely. You can't check for F4 key presses while this is happening because the loop will block any other code from executing (ie. the code that checks for key-presses). Since we want the auto-clicker clicks and the key-press checks to occur simultaneously, they need to be separate processes (so they don't block each other).

The main process which checks for key presses needs to be able to communicate somehow with the auto-clicker process. So when the F4 key is pressed we want the clicking process to exit. Using a queue is one way to communicate (there are others). The auto-clicker can continuously check the queue from inside the while loop. When we want to stop the clicking we can add an "Exit" string to the queue from the main process. The next time the clicker process reads the queue it will see this and break.

Upvotes: 1

Related Questions