Hold-to-click auto clicker for Windows. Press R to arm it, then hold the left
mouse button and it clicks for you at 1-50 CPS. Release to stop, Q to quit.
Every naive auto clicker has the same bug. You watch for a left-button-down event, and when you see one you start sending clicks. But your own clicks are left-button-down events too, so the detector sees them, and the whole thing turns into a mess of nested triggers with a click rate that has nothing to do with the slider.
Windows actually hands you the answer. A WH_MOUSE_LL hook receives an
MSLLHOOKSTRUCT with a flags field, and LLMHF_INJECTED is set on anything
that came from SendInput rather than from real hardware. So:
- Hardware click:
flags & LLMHF_INJECTED == 0. This is the user, track it. - Our own click: flag set. Ignore it entirely.
On top of that, while the macro is armed the hook returns 1 for physical
button events instead of calling CallNextHookEx. That swallows them, so the
application underneath only ever sees the synthetic stream. Clean, even CPS
with no doubled clicks.
Two things worth knowing if you poke at this code:
- The hook callback must be kept alive in a module-level variable. ctypes will garbage collect the trampoline otherwise and Windows will call into freed memory.
- A low-level hook only fires on a thread that runs a message loop, hence the
GetMessageWpump inpump_hook_messages.
Hotkeys use GetAsyncKeyState polling rather than a keyboard hook, so R and
Q work while another window has focus.
setup.batOnly dependency is pynput. tkinter ships with the standard Python installer.
run.vbs for no console window, run.bat if you want to see tracebacks.
Some games ship anti-cheat that flags injected input, and plenty of them ban for it. This exists for idle games, accessibility, and clicking through a thousand dialogs at work. Your call, your account.
Windows only. The whole thing is user32 calls.
MIT, see LICENSE.