@@ -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