Tag: Autoclicker

  • Auto-clicker skrevet i Python med Gemini

    Auto-clicker skrevet i Python med Gemini

    Jeg elsker clicker- og idle-spil – spil der ofte involverer en masse klikkeri med musen. Og sådan noget kan automatiseres. Der findes allerede et hav af forskellige småprogrammer, der løser “problemet”, men jeg synes det kunne være sjovt at se om Gemini kunne spytte en autoclicker-app up.

    Første prompt til Gemini 3 i Pro indstilling:

    Jeg vil gerne lave en autoclicker-app til windows 11. Hjælp mig med at gøre det.

    Det resulterede i lidt Python-kode, og med udviklerens vigtigste værktøj (CTRL-C + CTRL-V) fik jeg smidt koden i Visual Studio Code for en testkørsel. Allerede første version er faktisk ganske anstændig:

    Meeeeen, den måde at indstille intervallet mellem klikkene er ikke lige min kop te, så det skal på plads:

    Lad mig indstille intervallet mere nøjagtigt. Timer, minutter, sekunder og millisekunder mellem hvert klik.
    Lav en "start" og "stop" knap.

    Efter den rettelse ser app’en sådan ud:

    Gemini foreslog at lave en “Pick Location”-funktion:

    Would you like me to add the "Pick location" feature next, so you can tell the mouse exactly where to click on the screen?

    Interessant og god idé, men så kan vi ligeså godt gøre det endnu sjovere:

    Ja tak, jeg vil gerne have en pick location, men den skal være mere avanceret.
    Det skal være muligt at tilføje flere locations, som så klikkes i rækkefølge i løkke med det valgte interval.

    Det var faktisk nok til at lave en brugbar app, der gør lige præcis hvad jeg har brug for:

    [autoclicker.py]
    import tkinter as tk
    from tkinter import ttk
    import threading
    import time
    import pyautogui
    import keyboard
    
    class AutoClickerApp:
        def __init__(self, root):
            self.root = root
            self.root.title("Advanced Auto Clicker")
            self.root.geometry("600x350") # Gjort bredere for at gøre plads til listen
            self.root.resizable(False, False)
    
            # State variables
            self.running = False
            self.interval = 0.1
            self.coordinates = [] # Liste over (x, y) punkter
            self.coord_index = 0  # Hvilket punkt er vi nået til?
            
            # Variabel til Radiobuttons (0 = Current Location, 1 = Coordinate List)
            self.click_mode = tk.IntVar(value=0)
    
            # UI Setup
            self.setup_ui()
            
            # Start background thread
            self.click_thread = threading.Thread(target=self.clicker_logic)
            self.click_thread.daemon = True
            self.click_thread.start()
    
            # Hotkeys
            keyboard.add_hotkey('F6', self.toggle_clicking)
            keyboard.add_hotkey('F7', self.add_current_location) # Ny hotkey til at gemme punkt
    
        def setup_ui(self):
            # --- Left Side: Settings ---
            left_frame = ttk.Frame(self.root)
            left_frame.pack(side="left", fill="both", expand=True, padx=10, pady=10)
    
            # 1. Click Interval
            interval_frame = ttk.LabelFrame(left_frame, text="Click interval")
            interval_frame.pack(fill="x", pady=5)
            
            input_container = ttk.Frame(interval_frame)
            input_container.pack(padx=5, pady=10)
    
            self.ent_hours = self.create_time_input(input_container, "hours", "0")
            self.ent_mins = self.create_time_input(input_container, "mins", "0")
            self.ent_secs = self.create_time_input(input_container, "secs", "0")
            self.ent_ms = self.create_time_input(input_container, "ms", "100")
    
            # 2. Click Options / Mode
            mode_frame = ttk.LabelFrame(left_frame, text="Cursor position")
            mode_frame.pack(fill="x", pady=10)
    
            rb_current = ttk.Radiobutton(mode_frame, text="Current location", variable=self.click_mode, value=0)
            rb_current.pack(anchor="w", padx=10, pady=2)
    
            rb_list = ttk.Radiobutton(mode_frame, text="Coordinate List (Sequence)", variable=self.click_mode, value=1)
            rb_list.pack(anchor="w", padx=10, pady=2)
    
            # 3. Status & Start/Stop
            control_frame = ttk.Frame(left_frame)
            control_frame.pack(pady=20)
    
            self.status_label = ttk.Label(control_frame, text="Status: STOPPED", foreground="red", font=("Segoe UI", 10, "bold"))
            self.status_label.pack(pady=5)
    
            btn_frame = ttk.Frame(left_frame)
            btn_frame.pack()
    
            self.btn_start = ttk.Button(btn_frame, text="Start (F6)", command=self.start_clicking)
            self.btn_start.pack(side="left", padx=5, ipadx=5)
    
            self.btn_stop = ttk.Button(btn_frame, text="Stop (F6)", command=self.stop_clicking)
            self.btn_stop.pack(side="left", padx=5, ipadx=5)
            self.btn_stop.state(['disabled'])
    
            # --- Right Side: Coordinate List ---
            right_frame = ttk.LabelFrame(self.root, text="Location List")
            right_frame.pack(side="right", fill="both", padx=10, pady=10, expand=True)
    
            # Listbox with Scrollbar
            list_scroll = ttk.Scrollbar(right_frame)
            list_scroll.pack(side="right", fill="y")
    
            self.lst_coords = tk.Listbox(right_frame, yscrollcommand=list_scroll.set, height=10)
            self.lst_coords.pack(side="left", fill="both", expand=True, padx=5, pady=5)
            list_scroll.config(command=self.lst_coords.yview)
    
            # List Controls
            lbl_instr = ttk.Label(right_frame, text="Hover & Press F7 to add", foreground="gray", font=("Segoe UI", 8))
            lbl_instr.pack(side="bottom", pady=2)
    
            btn_clear = ttk.Button(right_frame, text="Clear List", command=self.clear_locations)
            btn_clear.pack(side="bottom", fill="x", padx=5, pady=5)
    
        def create_time_input(self, parent, label_text, default_val):
            frame = ttk.Frame(parent)
            frame.pack(side="left", padx=2)
            entry = ttk.Entry(frame, width=4, justify='right')
            entry.insert(0, default_val)
            entry.pack(side="left")
            lbl = ttk.Label(frame, text=label_text)
            lbl.pack(side="left")
            return entry
    
        def get_total_seconds(self):
            try:
                h = int(self.ent_hours.get() or 0)
                m = int(self.ent_mins.get() or 0)
                s = int(self.ent_secs.get() or 0)
                ms = int(self.ent_ms.get() or 0)
                return (h * 3600) + (m * 60) + s + (ms / 1000.0)
            except ValueError:
                return 0.1
    
        def add_current_location(self):
            """Adds the current mouse x,y to the list"""
            x, y = pyautogui.position()
            self.coordinates.append((x, y))
            self.lst_coords.insert(tk.END, f"Point {len(self.coordinates)}: X={x}, Y={y}")
            # Auto-select the radio button for list mode if user starts adding points
            self.click_mode.set(1) 
    
        def clear_locations(self):
            self.coordinates = []
            self.lst_coords.delete(0, tk.END)
            self.coord_index = 0
    
        def start_clicking(self):
            if not self.running:
                self.interval = self.get_total_seconds()
                self.running = True
                self.status_label.config(text="Status: RUNNING", foreground="green")
                self.btn_start.state(['disabled'])
                self.btn_stop.state(['!disabled'])
    
        def stop_clicking(self):
            if self.running:
                self.running = False
                self.status_label.config(text="Status: STOPPED", foreground="red")
                self.btn_start.state(['!disabled'])
                self.btn_stop.state(['disabled'])
    
        def toggle_clicking(self):
            if self.running:
                self.stop_clicking()
            else:
                self.start_clicking()
    
        def clicker_logic(self):
            while True:
                if self.running:
                    # Mode 1: Coordinate List
                    if self.click_mode.get() == 1 and self.coordinates:
                        # Get current target
                        target_x, target_y = self.coordinates[self.coord_index]
                        
                        pyautogui.click(target_x, target_y)
                        
                        # Move to next point in list, loop back to 0 if at end
                        self.coord_index = (self.coord_index + 1) % len(self.coordinates)
                    
                    # Mode 0: Current Location (or List is empty)
                    else:
                        pyautogui.click()
                    
                    time.sleep(self.interval)
                else:
                    time.sleep(0.01)
    
    if __name__ == "__main__":
        root = tk.Tk()
        try:
            from ctypes import windll
            windll.shcore.SetProcessDpiAwareness(1)
        except:
            pass
        app = AutoClickerApp(root)
        root.mainloop()
    [### Sådan bruger du den nye "Pick Location" funktion:
    
    Start scriptet.
    
    Bevæg musen hen over det sted på skærmen, du vil klikke på.
    
    Tryk på F7. Du vil se koordinaterne (f.eks. X=500, Y=300) dukke op i listen til højre.
    
    Gentag for så mange punkter, du vil.
    
    Sørg for, at "Coordinate List" er valgt (det sker automatisk, når du tilføjer punkter).
    
    Tryk Start (F6).
    
    Nu vil musen hoppe til Punkt 1, klikke, vente tiden ud, hoppe til Punkt 2, klikke, osv. Når den når bunden af listen, starter den forfra ved Punkt 1.]

    Den “færdige” app (den kan jo stadig forbedres) skrevet på 5 minutter i Google Gemini 3 Pro. Og nu skal jeg lige finde et spil frem, og snyde som en gris!