Skip to content

Commit

Permalink
feat: improve autoclick functionality and UI feedback
Browse files Browse the repository at this point in the history
- Refactored `autoclick.py` to use the `textual` library for a better UI experience.
- Added real-time status updates with dynamic background color changes based on autoclicker state.
- Updated `click_mouse.py` to support status callbacks for UI integration.
  • Loading branch information
arkeasz committed Feb 22, 2025
1 parent 62965f7 commit ba65934
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 56 deletions.
96 changes: 49 additions & 47 deletions autoclick.py
Original file line number Diff line number Diff line change
@@ -1,55 +1,57 @@
# !/usr/bin/python
from click_mouse import *
from textual.app import App, ComposeResult
from textual.widgets import Static
from textual.reactive import reactive
from pynput.keyboard import Listener, KeyCode
from pynput.mouse import Button, Controller
from rich.console import Console
from rich.style import Style
import argparse
import os
from click_mouse import ClickMouse
from textual.color import Color

console = Console()

parser = argparse.ArgumentParser(description="Autoclicker")
parser.add_argument("--left", action="store_true", help="Use left mouse button")
parser.add_argument("--right", action="store_true", help="Use right mouse button")
args = parser.parse_args()
class AutoClickApp(App):
CSS = "Screen {align: center middle;}"
status = reactive("[white]Autoclick: STOPPED[/white]")

delay: float = 0.1
button = Button.left
def __init__(self, delay, button):
super().__init__()
self.delay = delay
self.button = button
self.click_thread = ClickMouse(delay, button, self.update_status)
self.listener = None

if args.left:
button = Button.left
delay: float = 0.05
elif args.right:
button = Button.right
delay: float = 0.5
def compose(self) -> ComposeResult:
self.status_display = Static(self.status)
instructions = Static("[cyan]Press [bold]R[/bold] to start/stop | Press [bold]X[/bold] to exit[/cyan]")
yield self.status_display
yield instructions


os.system('cls' if os.name == 'nt' else 'clear')
console.print("PRESS 'r'", style="#aaaaaa", justify="center", )
start_stop_key = KeyCode(char='r')
exit_key = KeyCode(char='x')


click_thread = ClickMouse(delay, button)
click_thread.start()


def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
console.print("stop autoclick", style="#ffffff")
def update_status(self, message):
self.status = message
if "RUNNING" in message:
self.screen.styles.background = Color(78, 191, 96)
else:
style = Style(bgcolor="#eeeeee", color="#3322dd")
click_thread.start_clicking()
console.print("start autoclick", style=style)
elif key == exit_key:
console.print("exit autoclick", style="#aaaaaa")
click_thread.exit()
listener.stop()



with Listener(on_press=on_press) as listener:
listener.join()
self.screen.styles.background = Color(191, 78, 96)


def on_mount(self) -> None:
self.screen.styles.background = Color(191, 78, 96)
self.screen.styles.border = ('heavy', 'white')
self.click_thread.start()
start_stop_key = KeyCode(char='r')
exit_key = KeyCode(char='x')

def on_press(key):
if key == start_stop_key:
if self.click_thread.running:
self.click_thread.stop_clicking()
else:
self.click_thread.start_clicking()
elif key == exit_key:
self.exit()

self.listener = Listener(on_press=on_press)
self.listener.start()

def on_unmount(self) -> None:
if self.listener:
self.listener.stop()
self.click_thread.exit()
22 changes: 13 additions & 9 deletions click_mouse.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
import time
import threading
import time
from pynput.mouse import Controller, Button
from enum import Enum

mouse = Controller()

class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super(ClickMouse, self).__init__()
def __init__(self, delay, button, update_status_callback):
super().__init__()
self.delay = delay
self.button = button
self.button = Button.left if button == 'left' else Button.right
self.update_status_callback = update_status_callback
self.running = False
self.program_running = True
self.mouse = Controller()
self.daemon = True

def start_clicking(self):
self.running = True
self.update_status_callback("[green]Autoclick: RUNNING[/green]")

def stop_clicking(self):
self.running = False
self.update_status_callback("[yellow]Autoclick: STOPPED[/yellow]")

def exit(self):
self.stop_clicking()
self.program_running = False

def run(self):
while self.program_running:
while self.running:
mouse.click(self.button)
if self.running:
self.mouse.click(self.button)
time.sleep(self.delay)
time.sleep(0.1)
else:
time.sleep(0.1)
24 changes: 24 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from pynput.mouse import Button
import argparse
import os
from autoclick import AutoClickApp

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Autoclicker with Textual")
parser.add_argument("--left", action="store_true", help="Use left mouse button")
parser.add_argument("--right", action="store_true", help="Use right mouse button")
args = parser.parse_args()

delay = 0.1
button = Button.left

if args.left:
button = Button.left
delay = 0.05
elif args.right:
button = Button.right
delay = 0.5

os.system('cls' if os.name == 'nt' else 'clear')
app = AutoClickApp(delay, button)
app.run()

0 comments on commit ba65934

Please sign in to comment.