local M = {} -- Configuration local REQUIRED_REVERSALS = 3 -- Must switch direction 3 times (e.g., Left -> Right -> Left) local RESET_TIMEOUT = 0.3 -- Fast window: shake must be completed rapidly or it resets local LOCKOUT_DURATION = 3.0 -- Cooldown duration (seconds) before allowed to trigger again -- Asymmetrical Thresholds local SPEED_TO_ENABLE = 115.0 -- Slightly lower: easier to turn ON local SPEED_TO_DISABLE = 140.0 -- Slightly higher: harder to accidentally turn OFF -- Focusdim Global Hotkey Configuration from your settings local FOCUS_DIM_MODS = { "ctrl", "alt", "shift", "cmd" } local FOCUS_DIM_KEY = "f" -- Internal state tracking local jiggleWatcher = nil local isLocked = false local isFocusDimActive = false -- Tracks state to apply the correct threshold local lastXDirection = 0 -- -1 for left, 1 for right, 0 for still local reversalCount = 0 local lastEventTime = 0 -- Forward declaration for the timer loop M.start = function() end local function eventCallback(event) if isLocked then return false end local now = hs.timer.secondsSinceEpoch() -- Reset the counter if the movements aren't happening fast enough if (now - lastEventTime) > RESET_TIMEOUT then reversalCount = 0 lastXDirection = 0 end lastEventTime = now -- Extract horizontal movement exclusively local dx = event:getProperty(hs.eventtap.event.properties.mouseEventDeltaX) -- Dynamically choose threshold based on current state local currentThreshold = isFocusDimActive and SPEED_TO_DISABLE or SPEED_TO_ENABLE -- Only evaluate if it's a high-velocity horizontal snap matching the current state's rule if math.abs(dx) > currentThreshold then local currentDirection = (dx > 0) and 1 or -1 -- Track direction flips if lastXDirection ~= 0 and currentDirection ~= lastXDirection then reversalCount = reversalCount + 1 -- Trigger only when the full rapid shake sequence completes if reversalCount >= REQUIRED_REVERSALS then isLocked = true reversalCount = 0 lastXDirection = 0 -- Toggle our internal tracking state isFocusDimActive = not isFocusDimActive -- Instantly detach the listener M.stop() -- Simulate the hotkey press to toggle Focusdim hs.eventtap.keyStroke(FOCUS_DIM_MODS, FOCUS_DIM_KEY, 0) -- Re-enable after the lockout duration hs.timer.doAfter(LOCKOUT_DURATION, function() isLocked = false M.start() end) return false end end lastXDirection = currentDirection end return false -- Pass event through to macOS normally end function M.start() if jiggleWatcher then return end jiggleWatcher = hs.eventtap.new({ hs.eventtap.event.types.mouseMoved }, eventCallback) jiggleWatcher:start() end function M.stop() if jiggleWatcher then jiggleWatcher:stop() jiggleWatcher = nil end end return M