This guide provides a Python script that creates a virtual mouse for an auto-clicker functionality, specifically configured to run on Linux without requiring sudo after initial setup. It addresses common evdev permission issues by utilizing a udev rule.
import asyncio
import threading
import time
from evdev import InputDevice, UInput, ecodes as e, list_devices
from pynput.mouse import Button, Controller
# --- Configuration ---
# evdev code for the button. BTN_SIDE is the generic code for the first side button (often button 8).
TRIGGER_BUTTON_CODE = e.BTN_SIDE
CLICK_INTERVAL = 0.1 # Time in seconds between clicks
# ---------------------
clicking_enabled = False
pynput_mouse = Controller()
def find_mouse_device():
"""Finds the event device for a physical mouse."""
devices = [InputDevice(path) for path in list_devices()]
for device in devices:
# Look for a device that has mouse-like capabilities
if 'mouse' in device.name.lower() and e.EV_KEY in device.capabilities() and e.BTN_LEFT in device.capabilities()[e.EV_KEY]:
print(f"Found mouse device: {device.path} ({device.name})")
return device
return None
def clicker():
"""This thread performs the rapid left-clicks."""
while True:
if clicking_enabled:
pynput_mouse.click(Button.left, 1)
time.sleep(CLICK_INTERVAL)
async def handle_events(dev, ui):
"""Reads events from the real mouse and processes them."""
global clicking_enabled
try:
async for event in dev.async_read_loop():
# If it's our trigger button, we handle it ourselves
if event.type == e.EV_KEY and event.code == TRIGGER_BUTTON_CODE:
if event.value == 1: # 1 is pressed
print("Auto-clicker enabled.")
clicking_enabled = True
elif event.value == 0: # 0 is released
print("Auto-clicker disabled.")
clicking_enabled = False
# Do NOT write this event to the virtual device, effectively swallowing it.
else:
# For all other events, pass them through to the virtual device
ui.write_event(event)
except (OSError, asyncio.CancelledError) as err:
print(f"Event loop error: {err}")
finally:
print("Closing devices.")
dev.ungrab() # Release the physical device
ui.close()
def main():
dev = find_mouse_device()
if not dev:
print("Error: Could not find a mouse device. Make sure the script has permissions to read /dev/input/.")
return
# Create a virtual device (uinput) with the same capabilities as the real one
with UInput.from_device(dev, name='virtual-mouse') as ui:
print("Virtual mouse created. Grabbing physical mouse...")
try:
# Grab the physical device for exclusive access
dev.grab()
print("Mouse grabbed successfully. Auto-clicker is active.")
print("Hold down the side mouse button to click. Press Ctrl+C to exit.")
# Start the auto-clicker thread
click_thread = threading.Thread(target=clicker, daemon=True)
click_thread.start()
# Run the event handling loop
asyncio.run(handle_events(dev, ui))
except OSError as e:
print(f"Error: {e}. This script requires administrator privileges.")
print("Please run it with 'sudo'.")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
main()#!/bin/bash
venc/bin/python automation.pyKERNEL=="uinput", MODE="0660", GROUP="input", OPTIONS+="static_node=uinput"
- Create a project directory:
> mkdir my_autoclicker > cd my_autoclicker
- Create a Python virtual environment:
> python3 -m venv venv - Activate the virtual environment:
> source venv/bin/activate
- Install necessary Python packages:
> pip install evdev pynput
- Create
automation.py: Copy the content from theautomation.pysection above and save it asautomation.pyin yourmy_autoclickerdirectory. - Create
run.sh: Copy the content from therun.shsection above and save it asrun.shin yourmy_autoclickerdirectory. - Make
run.shexecutable:> chmod +x run.sh
This step allows your user to create virtual input devices without needing sudo every time.
- Add your user to the
inputgroup:You must log out and log back in for this change to take effect.> sudo usermod -aG input $USER
- Create or edit the udev rule file:
> sudo nano /etc/udev/rules.d/99-input.rules - Paste the content from the
99-input.rulessection above into the editor.- If the file already exists, ensure its content matches exactly.
- Save the file and exit the editor (Ctrl+O, Enter, Ctrl+X in nano).
- Reload udev rules:
> sudo udevadm control --reload-rules && sudo udevadm trigger
- Navigate to your project directory:
> cd /path/to/my_autoclicker
- Run the script:
You should now be able to run the script without being prompted for a password.
> ./run.sh
- The
automation.pyscript usesevdevto create a virtual mouse device andpynputto simulate clicks. It also grabs your physical mouse to prevent duplicate input. - The
udevrule (99-input.rules) modifies the permissions of/dev/uinput(the kernel interface for virtual input devices) to allow users in theinputgroup to write to it. - By adding your user to the
inputgroup and applying this rule, your script gains the necessary permissions without needingsudofor every execution.