Skip to content

Commit 6162bc3

Browse files
authored
Add files via upload
1 parent 88718a4 commit 6162bc3

File tree

6 files changed

+391
-0
lines changed

6 files changed

+391
-0
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Agalar911 Autoclicker
2+
3+
A simple, feature-rich autoclicker.
4+
5+
## How to Use
6+
1. Run `Agalar911_Autoclicker.exe`.
7+
2. Press **F6** to Start/Stop.
8+
3. Press **ESC** to Exit.
9+
10+
## Features
11+
- **Left/Right Click** modes.
12+
- **Jitter** for human-like clicking.
13+
- **Window Lock**: Click only in your game window.
14+
15+
> **Note**: For games, run the application as **Administrator**.
16+

build_release.bat

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@echo off
2+
pushd %~dp0
3+
echo Installing PyInstaller...
4+
pip install pyinstaller
5+
6+
echo Converting Icon...
7+
python convert_icon.py
8+
9+
echo Building EXE...
10+
python -m PyInstaller --clean --noconsole --onefile --icon="folder.ico" --name "Agalar911_Autoclicker" src/main.py
11+
12+
echo Build Complete! Check the 'dist' folder.
13+
pause

convert_icon.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from PIL import Image
2+
import os
3+
4+
# Source path (uploaded metadata)
5+
src = r"C:/Users/pc/.gemini/antigravity/brain/a998267b-cda4-4eb5-9324-170a4f7948e4/uploaded_media_1770204431115.png"
6+
# Destination path for folder icon
7+
dst = r"c:\Users\pc\.gemini\antigravity\scratch\autoclicker\folder.ico"
8+
9+
try:
10+
img = Image.open(src)
11+
img.save(dst, format='ICO')
12+
print(f"Successfully converted {src} to {dst}")
13+
except Exception as e:
14+
print(f"Error converting icon: {e}")

folder.ico

43.2 KB
Binary file not shown.

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pynput
2+
pygetwindow
3+
pyrect

src/main.py

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
import time
2+
import threading
3+
import random
4+
import sys
5+
import subprocess
6+
import tkinter as tk
7+
from tkinter import messagebox, ttk
8+
9+
# --- AUTO-INSTALL DEPENDENCIES ---
10+
def install_and_import(package, import_name=None):
11+
import_name = import_name or package
12+
try:
13+
__import__(import_name)
14+
except ImportError:
15+
print(f"Installing {package}...")
16+
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
17+
try:
18+
__import__(import_name)
19+
except ImportError:
20+
messagebox.showerror("Error", f"Failed to install {package}. Please run 'pip install -r requirements.txt' manually.")
21+
sys.exit(1)
22+
23+
install_and_import("pynput")
24+
install_and_import("pygetwindow")
25+
install_and_import("pyrect")
26+
27+
from pynput.mouse import Button, Controller, Listener as MouseListener
28+
from pynput.keyboard import Listener as KeyListener, KeyCode, Key
29+
import pygetwindow as gw
30+
31+
class AutoclickerApp:
32+
def __init__(self, root):
33+
self.root = root
34+
self.root.title("Agalar911 AutoClicker")
35+
self.root.geometry("400x780")
36+
self.root.resizable(False, False)
37+
38+
# --- PROFESSIONAL DARK THEME ---
39+
self.bg_black = "#0b0c10"
40+
self.bg_card = "#1f2833"
41+
self.accent_blue = "#66fcf1"
42+
self.accent_dim = "#45a29e"
43+
self.fg_white = "#c5c6c7"
44+
self.btn_bg = "#121212"
45+
self.kill_red = "#f7768e"
46+
47+
self.root.configure(bg=self.bg_black)
48+
49+
self.mouse = Controller()
50+
self.running = False
51+
self.binding_mode = None
52+
self.picking_pos = False
53+
54+
# --- STATE VARIABLES ---
55+
self.unit_var = tk.StringVar(value="ms")
56+
self.button_var = tk.StringVar(value="left")
57+
self.click_type_var = tk.StringVar(value="single")
58+
59+
self.jitter_var = tk.BooleanVar(value=False)
60+
self.always_on_top_var = tk.BooleanVar(value=False)
61+
self.click_limit_enabled = tk.BooleanVar(value=False)
62+
self.timer_enabled = tk.BooleanVar(value=False)
63+
self.lock_pos_enabled = tk.BooleanVar(value=False)
64+
self.lock_window_enabled = tk.BooleanVar(value=False)
65+
66+
self.click_limit_val = tk.StringVar(value="1000")
67+
self.timer_min_val = tk.StringVar(value="10")
68+
self.target_pos = None
69+
self.target_window_title = tk.StringVar(value="No Window Captured")
70+
71+
self.hotkey_start_stop = Key.f6
72+
self.hotkey_kill = Key.esc
73+
74+
self.clicks_done = 0
75+
self.start_time = 0
76+
77+
self.setup_ui()
78+
79+
# Separate listeners
80+
self.key_listener = KeyListener(on_press=self.on_press)
81+
self.mouse_listener = MouseListener(on_click=self.on_click_global)
82+
self.key_listener.start()
83+
self.mouse_listener.start()
84+
85+
self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
86+
87+
def setup_ui(self):
88+
title_font = ("Segoe UI", 24, "bold")
89+
header_font = ("Segoe UI", 10, "bold")
90+
label_font = ("Segoe UI", 10)
91+
92+
def create_card(parent, text):
93+
frame = tk.LabelFrame(parent, text=f" {text} ", bg=self.bg_black, fg=self.accent_blue,
94+
font=header_font, padx=15, pady=10, borderwidth=1, relief="flat", highlightthickness=1)
95+
frame.config(highlightbackground="#1f2833", highlightcolor=self.accent_blue)
96+
return frame
97+
98+
# Header
99+
tk.Label(self.root, text="AGALAR911", font=title_font, bg=self.bg_black, fg="#ffffff").pack(pady=(25, 10))
100+
101+
# Main Layout Container
102+
main_container = tk.Frame(self.root, bg=self.bg_black)
103+
main_container.pack(fill="both", expand=True, padx=25)
104+
105+
radio_style = {"bg": self.bg_black, "fg": self.fg_white, "selectcolor": self.bg_black,
106+
"activebackground": self.bg_black, "activeforeground": self.accent_blue,
107+
"font": label_font, "padx": 5}
108+
109+
# --- INTERVAL SECTION ---
110+
frame_speed = create_card(main_container, "CLICK INTERVAL")
111+
frame_speed.pack(fill="x", pady=5)
112+
113+
speed_row = tk.Frame(frame_speed, bg=self.bg_black)
114+
speed_row.pack(fill="x")
115+
self.interval_entry = tk.Entry(speed_row, width=8, justify='center', bg=self.btn_bg, fg="#ffffff", borderwidth=0, font=("Segoe UI", 12))
116+
self.interval_entry.insert(0, "100")
117+
self.interval_entry.pack(side=tk.LEFT, padx=(0, 10))
118+
119+
tk.Radiobutton(speed_row, text="ms", variable=self.unit_var, value="ms", **radio_style).pack(side=tk.LEFT)
120+
tk.Radiobutton(speed_row, text="sec", variable=self.unit_var, value="sec", **radio_style).pack(side=tk.LEFT)
121+
tk.Radiobutton(speed_row, text="CPS", variable=self.unit_var, value="cps", **radio_style).pack(side=tk.LEFT)
122+
123+
# --- MOUSE SECTION ---
124+
frame_mouse = create_card(main_container, "MOUSE SETTINGS")
125+
frame_mouse.pack(fill="x", pady=5)
126+
127+
m_row1 = tk.Frame(frame_mouse, bg=self.bg_black)
128+
m_row1.pack(fill="x")
129+
tk.Label(m_row1, text="Button:", bg=self.bg_black, fg=self.accent_dim, width=8, anchor="w").pack(side=tk.LEFT)
130+
tk.Radiobutton(m_row1, text="Left", variable=self.button_var, value="left", **radio_style).pack(side=tk.LEFT)
131+
tk.Radiobutton(m_row1, text="Right", variable=self.button_var, value="right", **radio_style).pack(side=tk.LEFT)
132+
tk.Radiobutton(m_row1, text="Mid", variable=self.button_var, value="middle", **radio_style).pack(side=tk.LEFT)
133+
134+
m_row2 = tk.Frame(frame_mouse, bg=self.bg_black)
135+
m_row2.pack(fill="x", pady=(5,0))
136+
tk.Label(m_row2, text="Type:", bg=self.bg_black, fg=self.accent_dim, width=8, anchor="w").pack(side=tk.LEFT)
137+
tk.Radiobutton(m_row2, text="Single", variable=self.click_type_var, value="single", **radio_style).pack(side=tk.LEFT)
138+
tk.Radiobutton(m_row2, text="Double", variable=self.click_type_var, value="double", **radio_style).pack(side=tk.LEFT)
139+
140+
# --- AUTOMATION SECTION ---
141+
frame_auto = create_card(main_container, "AUTO-STOP CONDITIONS")
142+
frame_auto.pack(fill="x", pady=5)
143+
144+
limit_row = tk.Frame(frame_auto, bg=self.bg_black)
145+
limit_row.pack(fill="x")
146+
tk.Checkbutton(limit_row, text="Max Clicks:", variable=self.click_limit_enabled, **radio_style).pack(side=tk.LEFT)
147+
tk.Entry(limit_row, textvariable=self.click_limit_val, width=10, bg=self.btn_bg, fg="#ffffff", borderwidth=0).pack(side=tk.RIGHT)
148+
149+
timer_row = tk.Frame(frame_auto, bg=self.bg_black)
150+
timer_row.pack(fill="x", pady=(5,0))
151+
tk.Checkbutton(timer_row, text="Stop Timer (min):", variable=self.timer_enabled, **radio_style).pack(side=tk.LEFT)
152+
tk.Entry(timer_row, textvariable=self.timer_min_val, width=10, bg=self.btn_bg, fg="#ffffff", borderwidth=0).pack(side=tk.RIGHT)
153+
154+
# --- LOCKS SECTION ---
155+
frame_locks = create_card(main_container, "POSITIONAL LOCKS")
156+
frame_locks.pack(fill="x", pady=5)
157+
158+
l_row1 = tk.Frame(frame_locks, bg=self.bg_black)
159+
l_row1.pack(fill="x")
160+
tk.Checkbutton(l_row1, text="Lock Coordinates", variable=self.lock_pos_enabled, **radio_style).pack(side=tk.LEFT)
161+
tk.Button(l_row1, text="Select Spot", command=self.start_picking_pos, bg=self.bg_card, fg=self.accent_blue, borderwidth=0, padx=8).pack(side=tk.RIGHT)
162+
163+
l_row2 = tk.Frame(frame_locks, bg=self.bg_black)
164+
l_row2.pack(fill="x", pady=(5,0))
165+
tk.Checkbutton(l_row2, text="Lock Target Window", variable=self.lock_window_enabled, **radio_style).pack(side=tk.LEFT)
166+
tk.Button(l_row2, text="Capture", command=self.pick_active_window, bg=self.bg_card, fg=self.accent_blue, borderwidth=0, padx=8).pack(side=tk.RIGHT)
167+
168+
tk.Label(frame_locks, textvariable=self.target_window_title, bg=self.bg_black, fg=self.accent_dim, font=("Segoe UI", 7), wraplength=300).pack(fill="x", pady=(5,0))
169+
170+
# --- HOTKEYS SECTION ---
171+
frame_keys = create_card(main_container, "HOTKEYS")
172+
frame_keys.pack(fill="x", pady=5)
173+
174+
self.btn_bind_start = tk.Button(frame_keys, text=f"Toggle: {self.format_key(self.hotkey_start_stop)}",
175+
command=lambda: self.start_binding('start_stop'), bg=self.btn_bg, fg=self.accent_blue, borderwidth=1, relief="solid", pady=6)
176+
self.btn_bind_start.pack(fill="x", pady=2)
177+
178+
self.btn_bind_kill = tk.Button(frame_keys, text=f"Exit App: {self.format_key(self.hotkey_kill)}",
179+
command=lambda: self.start_binding('kill'), bg=self.btn_bg, fg=self.kill_red, borderwidth=1, relief="solid", pady=6)
180+
self.btn_bind_kill.pack(fill="x")
181+
182+
# --- FOOTER OPTIONS ---
183+
tk.Checkbutton(main_container, text="Humanize (Random Jitter/Offset)", variable=self.jitter_var, **radio_style).pack(anchor="w", pady=(10, 0))
184+
tk.Checkbutton(main_container, text="Always On Top", variable=self.always_on_top_var, command=self.toggle_on_top, **radio_style).pack(anchor="w")
185+
186+
# --- STATUS FOOTER ---
187+
self.status_bar = tk.Frame(self.root, bg=self.btn_bg, pady=12)
188+
self.status_bar.pack(fill="x", side="bottom")
189+
self.status_label = tk.Label(self.status_bar, text="STATUS: READY", font=("Segoe UI", 10, "bold"), bg=self.btn_bg, fg=self.accent_blue)
190+
self.status_label.pack()
191+
192+
tk.Label(self.root, text="Developed by KenzoNight", font=("Segoe UI", 7), bg=self.bg_black, fg="#313244").pack(side="bottom", pady=5)
193+
194+
def toggle_on_top(self):
195+
self.root.attributes("-topmost", self.always_on_top_var.get())
196+
197+
def start_picking_pos(self):
198+
self.picking_pos = True
199+
self.status_label.config(text="STATUS: CLICK TO LOCK POS", fg="#ffffff")
200+
201+
def pick_active_window(self):
202+
def countdown(count):
203+
if count > 0:
204+
self.status_label.config(text=f"STATUS: FOCUS TARGET IN {count}s...", fg=self.kill_red)
205+
self.root.after(1000, lambda: countdown(count - 1))
206+
else:
207+
try:
208+
active = gw.getActiveWindow()
209+
if active:
210+
self.target_window_title.set(active.title)
211+
self.status_label.config(text="STATUS: WINDOW CAPTURED", fg=self.accent_blue)
212+
else:
213+
self.status_label.config(text="STATUS: CAPTURE FAILED", fg=self.kill_red)
214+
except:
215+
self.status_label.config(text="STATUS: CAPTURE ERROR", fg=self.kill_red)
216+
217+
countdown(3)
218+
219+
def start_binding(self, mode):
220+
self.binding_mode = mode
221+
btn = self.btn_bind_start if mode == 'start_stop' else self.btn_bind_kill
222+
btn.config(text="... PRESS ANY KEY ...", fg="#ffffff")
223+
self.status_label.config(text="STATUS: LISTENING FOR KEY", fg="#ffffff")
224+
225+
def format_key(self, key):
226+
if isinstance(key, Key): return key.name.upper()
227+
if isinstance(key, KeyCode): return str(key.char).upper() if key.char else f"K:{key.vk}"
228+
return str(key)
229+
230+
def get_sleep_interval(self):
231+
try:
232+
val = float(self.interval_entry.get())
233+
unit = self.unit_var.get()
234+
interval = val if unit == "sec" else (val / 1000.0 if unit == "ms" else 1.0 / max(0.1, val))
235+
except: interval = 0.1
236+
if self.jitter_var.get(): interval += random.uniform(-interval*0.15, interval*0.15)
237+
return max(0.001, interval)
238+
239+
def clicker_loop(self):
240+
button_map = {"left": Button.left, "right": Button.right, "middle": Button.middle}
241+
btn = button_map.get(self.button_var.get(), Button.left)
242+
is_double = self.click_type_var.get() == "double"
243+
244+
while self.running:
245+
try:
246+
if self.click_limit_enabled.get() and self.clicks_done >= int(self.click_limit_val.get()):
247+
self.root.after(0, self.stop_clicking)
248+
break
249+
if self.timer_enabled.get() and (time.time() - self.start_time) >= float(self.timer_min_val.get()) * 60:
250+
self.root.after(0, self.stop_clicking)
251+
break
252+
if self.lock_window_enabled.get():
253+
active = gw.getActiveWindow()
254+
if not active or self.target_window_title.get() not in active.title:
255+
time.sleep(0.1)
256+
continue
257+
except: break
258+
259+
interval = self.get_sleep_interval()
260+
st = time.perf_counter()
261+
262+
if self.lock_pos_enabled.get() and self.target_pos:
263+
# If "Humanize" is on, add slight jitter to the locked position
264+
if self.jitter_var.get():
265+
jx = self.target_pos[0] + random.randint(-3, 3)
266+
jy = self.target_pos[1] + random.randint(-3, 3)
267+
self.mouse.position = (jx, jy)
268+
else:
269+
self.mouse.position = self.target_pos
270+
elif self.jitter_var.get():
271+
# If humanize is on but NOT locked, subtle shake in place
272+
cur_x, cur_y = self.mouse.position
273+
self.mouse.position = (cur_x + random.randint(-1, 1), cur_y + random.randint(-1, 1))
274+
275+
# Execution
276+
self.mouse.press(btn)
277+
time.sleep(random.uniform(0.01, 0.03) if self.jitter_var.get() else 0.01)
278+
self.mouse.release(btn)
279+
self.clicks_done += 1
280+
281+
if is_double:
282+
time.sleep(random.uniform(0.01, 0.03) if self.jitter_var.get() else 0.01)
283+
self.mouse.press(btn)
284+
time.sleep(random.uniform(0.01, 0.03) if self.jitter_var.get() else 0.01)
285+
self.mouse.release(btn)
286+
self.clicks_done += 1
287+
288+
# Precise Idle
289+
rem = interval - (time.perf_counter() - st)
290+
if rem > 0:
291+
end = time.perf_counter() + rem
292+
while self.running and time.perf_counter() < end:
293+
diff = end - time.perf_counter()
294+
if diff > 0.015: time.sleep(diff - 0.010)
295+
296+
def start_clicking(self):
297+
if not self.running:
298+
self.clicks_done = 0
299+
self.start_time = time.time()
300+
self.running = True
301+
self.status_label.config(text="STATUS: RUNNING", fg="#a6e3a1")
302+
threading.Thread(target=self.clicker_loop, daemon=True).start()
303+
304+
def stop_clicking(self):
305+
if self.running:
306+
self.running = False
307+
self.status_label.config(text="STATUS: STOPPED", fg=self.kill_red)
308+
309+
def on_press(self, key):
310+
if self.binding_mode:
311+
if self.binding_mode == 'start_stop':
312+
self.hotkey_start_stop = key
313+
self.btn_bind_start.config(text=f"Toggle: {self.format_key(key)}", fg=self.accent_blue)
314+
else:
315+
self.hotkey_kill = key
316+
self.btn_bind_kill.config(text=f"Exit App: {self.format_key(key)}", fg=self.kill_red)
317+
self.binding_mode = None
318+
self.status_label.config(text="STATUS: KEY BOUND", fg=self.accent_blue)
319+
return
320+
321+
if key == self.hotkey_start_stop:
322+
self.stop_clicking() if self.running else self.start_clicking()
323+
elif key == self.hotkey_kill:
324+
self.on_closing()
325+
326+
def on_click_global(self, x, y, button, pressed):
327+
if self.picking_pos and pressed:
328+
self.target_pos = (x, y)
329+
self.picking_pos = False
330+
def update_ui():
331+
messagebox.showinfo("Selection", f"Position locked to {x}, {y}")
332+
self.status_label.config(text="STATUS: POSITION LOCKED", fg=self.accent_blue)
333+
self.root.after(0, update_ui)
334+
335+
def on_closing(self):
336+
self.running = False
337+
if hasattr(self, 'key_listener'): self.key_listener.stop()
338+
if hasattr(self, 'mouse_listener'): self.mouse_listener.stop()
339+
self.root.destroy()
340+
sys.exit()
341+
342+
if __name__ == "__main__":
343+
root = tk.Tk()
344+
app = AutoclickerApp(root)
345+
root.mainloop()

0 commit comments

Comments
 (0)