Skip to content

Commit c33db71

Browse files
authored
Implement Hammerspoon mouse autoclick script q
Added Hammerspoon script for mouse autoclick functionality.
1 parent e329d54 commit c33db71

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

pages/mac/index.template.html

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,157 @@ <h2>Truecrypt - Veracrypt</h2>
10611061
href="https://news.ycombinator.com/item?id=13048479#:~:text=great%20for%20hackers-,You%20should%20try%20the%20option%20%22Enable%20Dragging%20with%20Drag%20Lock,until%20you%20short%2Dtap%20again."
10621062
>https://news.ycombinator.com/item?id=13048479#:~:text=great%20for%20hackers-,You%20should%20try%20the%20option%20%22Enable%20Dragging%20with%20Drag%20Lock,until%20you%20short%2Dtap%20again.</a
10631063
>
1064+
<h2>Hammerspoon mouse autoclick</h2>
1065+
<script type="editor" data-lang="lua">
1066+
local cps = 30
1067+
local delay = 1 / cps
1068+
1069+
-- How long (in seconds) a button can be held before autoclicking stops.
1070+
-- Release and press again to restart.
1071+
local maxHoldSeconds = 3
1072+
1073+
local leftTimer = nil
1074+
local rightTimer = nil
1075+
local leftWatchdog = nil
1076+
local rightWatchdog = nil
1077+
1078+
-------------------------------------------------
1079+
-- Fast left click
1080+
-------------------------------------------------
1081+
1082+
local function leftClick()
1083+
local pos = hs.mouse.absolutePosition()
1084+
1085+
hs.eventtap.event.newMouseEvent(
1086+
hs.eventtap.event.types.leftMouseDown,
1087+
pos
1088+
):post()
1089+
1090+
hs.eventtap.event.newMouseEvent(
1091+
hs.eventtap.event.types.leftMouseUp,
1092+
pos
1093+
):post()
1094+
end
1095+
1096+
-------------------------------------------------
1097+
-- Fast right click
1098+
-------------------------------------------------
1099+
1100+
local function rightClick()
1101+
local pos = hs.mouse.absolutePosition()
1102+
1103+
hs.eventtap.event.newMouseEvent(
1104+
hs.eventtap.event.types.rightMouseDown,
1105+
pos
1106+
):post()
1107+
1108+
hs.eventtap.event.newMouseEvent(
1109+
hs.eventtap.event.types.rightMouseUp,
1110+
pos
1111+
):post()
1112+
end
1113+
1114+
-------------------------------------------------
1115+
-- Helpers: stop individual timers
1116+
-------------------------------------------------
1117+
1118+
local function stopLeft()
1119+
if leftTimer then
1120+
leftTimer:stop()
1121+
leftTimer = nil
1122+
end
1123+
-- Also cancel the watchdog if the key was released before it fired
1124+
if leftWatchdog then
1125+
leftWatchdog:stop()
1126+
leftWatchdog = nil
1127+
end
1128+
end
1129+
1130+
local function stopRight()
1131+
if rightTimer then
1132+
rightTimer:stop()
1133+
rightTimer = nil
1134+
end
1135+
-- Also cancel the watchdog if the key was released before it fired
1136+
if rightWatchdog then
1137+
rightWatchdog:stop()
1138+
rightWatchdog = nil
1139+
end
1140+
end
1141+
1142+
-------------------------------------------------
1143+
-- F18 = left autoclick
1144+
-- Raw eventtap instead of hs.hotkey.bind to avoid
1145+
-- the internal queue that hotkey uses for repeats,
1146+
-- which causes clicks to keep firing after release.
1147+
-- isRepeat filters out OS key-repeat events so only
1148+
-- the first physical keyDown starts the timer.
1149+
-- "Last pressed wins": starting left stops right first.
1150+
-- Watchdog: stops clicking after maxHoldSeconds if still held.
1151+
-------------------------------------------------
1152+
1153+
local keyTap = hs.eventtap.new(
1154+
{ hs.eventtap.event.types.keyDown, hs.eventtap.event.types.keyUp },
1155+
function(event)
1156+
local keyCode = event:getKeyCode()
1157+
local isRepeat = event:getProperty(hs.eventtap.event.properties.keyboardEventAutorepeat) ~= 0
1158+
1159+
-- F18 keycode = 79
1160+
if keyCode == 79 then
1161+
1162+
-- First physical keyDown only, repeats ignored
1163+
if event:getType() == hs.eventtap.event.types.keyDown and not leftTimer and not isRepeat then
1164+
-- Last pressed wins: cancel right if it was running
1165+
stopRight()
1166+
leftTimer = hs.timer.doEvery(delay, leftClick)
1167+
-- Watchdog fires once after maxHoldSeconds and kills the click timer
1168+
leftWatchdog = hs.timer.doAfter(maxHoldSeconds, stopLeft)
1169+
1170+
-- Stop immediately on key release
1171+
elseif event:getType() == hs.eventtap.event.types.keyUp then
1172+
stopLeft()
1173+
end
1174+
end
1175+
1176+
return false
1177+
end
1178+
)
1179+
1180+
-------------------------------------------------
1181+
-- Left Control = right autoclick
1182+
-- Ctrl is a modifier key so it fires flagsChanged
1183+
-- instead of keyDown/keyUp.
1184+
-- "Last pressed wins": starting right stops left first.
1185+
-- Watchdog: stops clicking after maxHoldSeconds if still held.
1186+
-------------------------------------------------
1187+
1188+
local ctrlTap = hs.eventtap.new(
1189+
{ hs.eventtap.event.types.flagsChanged },
1190+
1191+
function(event)
1192+
local flags = event:getFlags()
1193+
1194+
-- Ctrl pressed
1195+
if flags.ctrl and not rightTimer then
1196+
-- Last pressed wins: cancel left if it was running
1197+
stopLeft()
1198+
rightTimer = hs.timer.doEvery(delay, rightClick)
1199+
-- Watchdog fires once after maxHoldSeconds and kills the click timer
1200+
rightWatchdog = hs.timer.doAfter(maxHoldSeconds, stopRight)
1201+
end
1202+
1203+
-- Ctrl released
1204+
if not flags.ctrl and rightTimer then
1205+
stopRight()
1206+
end
1207+
1208+
return false
1209+
end
1210+
)
1211+
1212+
keyTap:start()
1213+
ctrlTap:start()
1214+
</script>
10641215
<h2>Install MacPorts</h2>
10651216
<script type="editor" data-lang="sh">
10661217

0 commit comments

Comments
 (0)