6
\$\begingroup\$

What do you think of my auto clicker script? Even though it's just for my own personal use, I'm thinking of using PyInstaller to turn it into an exe, so I know how to do that in the future.

import pyHook, threading
import tkinter as tk    
from pyautogui import click

t1token = 0
threadsRun = 1
ac = 0

def simplegui():

    def sunken():
        """keep startButton lowered and disabled.
            hook keyboard, start clicks function"""
        global threadsRun
        startButton.config(relief=tk.SUNKEN, state=tk.DISABLED, 
                           text="r=stop listening")
        hm.HookKeyboard()
        threadsRun = 1
        t1 = threading.Thread(target=clicks, args=(startButton,), 
                              name='clicks{}'.format(t1token))
        t1.start()

    def destroy():
        """exit program"""
        global threadsRun, ac
        ac = 0
        threadsRun = 0
        # Not sure if keyboard unhooks if press quit after press start
        root.destroy()

    startButton = tk.Button(root, text="Start", command=sunken, 
                            height=10, width=20)
    startButton.grid(row=1, column=0)

    quitButton = tk.Button(root, text="Quit", command=destroy, 
                           height=10, width=20)
    quitButton.grid(row=1, column=1)

def clicks(startButton):
    """right clicks the mouse at 1k clicks per minute
        also puts button back to normal state once done"""
    global t1token
    while threadsRun:
        while ac:
            click(clicks=17, interval=0.06, button='right')
    t1token += 1
    startButton.config(relief=tk.RAISED, state=tk.NORMAL, text="Start")

root = tk.Tk()

def OnKeyboardEvent(event):
    """A key was pressed"""
    global threadsRun, ac
    if event.Key == "R":
        ac = 0
        threadsRun = 0
        hm.UnhookKeyboard()
        return False
    if event.Key == "T":
        ac = not ac
        return False
    return True

hm = pyHook.HookManager()
hm.KeyDown = OnKeyboardEvent
simplegui()
root.mainloop()
\$\endgroup\$
2
  • \$\begingroup\$ Could you link to the modules please as I cant pip install them in command prompt \$\endgroup\$ Commented May 6, 2020 at 11:27
  • \$\begingroup\$ @DanHowe I'd try pip install pyhook3 pyautogui, as the pyhook package hasn't been updated since 2008. I can't vouch for any of these packages though. \$\endgroup\$ Commented May 6, 2020 at 16:38

1 Answer 1

4
\$\begingroup\$

The purpose of your code is somewhat unclear. You want to click. Sure. And a lot of it. But why the right mouse button and why at this speed? Have you measured whether you're actually clicking at the speed you think you do? Are you sure you don't want to automatically stop clicking after a while?

Not all code requires classes. But once you start using a GUI, find yourself attracted to globals and define nested functions (in your simplegui()), it's worth considering them anyway.

t1token = 0
threadsRun = 1
ac = 0

t1token and ac are terrible variable names. What are you doing, alternating clicking at a frequency of 0?

You use pyHook for your keyboard. That works*, but having to hook and unhook a keyboard manually is something we're moving away from. Instead, use context managers and the with statement or pick a library that do this for you. Such as pynput.keyboard.Listener.

*: pyHook was last updated in 2008. Based on the existence of PyHook3, I strongly suspect it was only ever working for Python 2 and (discounting the port) hasn't been under active development in years.

Roughly reworked:

import tkinter as tk
from pyautogui import click
import threading
from pynput import keyboard

class AutoClicker:
    """
    A class representing an autoclicker with a GUI.

    The autoclicker allows users to start and stop clicking using a GUI button.
    It listens for keyboard events to toggle clicking, to stop the autoclicker.

    Attributes:
        root (tk.Tk): The root window of the GUI.
        clicking (bool): A flag indicating whether the clicking is currently in progress.
        running (bool): A flag indicating whether the autoclicker is currently running.
        listener (keyboard.Listener): The keyboard listener object.
        start_button (tk.Button): The button to start the clicking.
        quit_button (tk.Button): The button to quit the autoclicker.
    """

    def __init__(self):
        """
        Initialize the autoclicker.

        Creates the window, sets up the keyboard listener, and initializes the flags.
        """
        self.root = tk.Tk()
        self.clicking = False
        self.running = False
        self.listener = None

        self.start_button = tk.Button(self.root, text="Start", command=self.start_clicking)
        self.start_button.grid(row=1, column=0)

        self.quit_button = tk.Button(self.root, text="Quit", command=self.destroy)
        self.quit_button.grid(row=1, column=1)

    def start_clicking(self):
        """
        Start clicking.

        Sets the running flag to True, configures the start button to display "Stop",
        and starts the keyboard listener and the clicking thread.
        """
        self.running = True
        self.start_button.config(relief=tk.SUNKEN, state=tk.DISABLED, text="Stop")
        self.listener = keyboard.Listener(on_press=self.on_key_press)
        self.listener.start()
        self.click_thread = threading.Thread(target=self.click_mouse)
        self.click_thread.start()

    def on_key_press(self, key):
        """
        Handle a keyboard event.

        If the pressed key is 't', toggles the clicking flag.
        If the pressed key is 'r', stops the autoclicker and the keyboard listener.

        Args:
            key (keyboard.Key): The pressed key.
        """
        try:
            if key.char.lower() == 't':
                # Toggle the clicking
                self.clicking = not self.clicking
            elif key.char.lower() == 'r':
                # Reset
                self.running = False
                self.listener.stop()
                self.start_button.config(relief=tk.RAISED, state=tk.NORMAL, text="Start")
        except AttributeError:
            # Ignore non-character keys (don't have a char attribute)
            pass

    def click_mouse(self):
        while self.running:
            while self.clicking:
                click(clicks=17, interval=0.06, button='right')

    def destroy(self):
        self.running = False
        if self.listener:
            self.listener.stop()
        self.root.destroy()

    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    autoclicker = AutoClicker()
    autoclicker.run()
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.