Last active
January 6, 2025 12:43
-
-
Save vwal/1222b4297f1b865c7bd570c94af8453f to your computer and use it in GitHub Desktop.
Hammerspoon QuitEnhancer Spoon script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- === QuitEnhancer === | |
--- Inspired by/based on https://apple.stackexchange.com/a/349766/55498 | |
--- | |
--- Enhances Command-Q behavior by requiring a hold to quit apps, and adds Shift-Command-Q for instant quit. | |
--- For Finder, closes the frontmost window instead of quitting the app, with the same delay behavior. | |
--- Place this script in ~/.hammerspoon/Spoons/QuitEnhancer.spoon/init.lua, | |
--- and call from ~/.hammerspoon/init.lua with: | |
--- hs.loadSpoon("QuitEnhancer") | |
--- spoon.QuitEnhancer:start(2) -- Optional parameter for Cmd-Q quit delay in seconds | |
local obj = {} | |
obj.__index = obj | |
-- Metadata | |
obj.name = "QuitEnhancer" | |
obj.version = "1.0" | |
obj.author = "Ville Walveranta" | |
obj.homepage = "https://github.com/yourusername/hammerspoon-spoons" | |
obj.license = "MIT - https://opensource.org/licenses/MIT" | |
-- Internal variables | |
obj.cmdQTimer = nil | |
obj.cmdQAlert = nil | |
obj.cmdQDelay = 2 -- default delay in seconds | |
function obj:cmdQCleanup() | |
hs.alert.closeSpecific(self.cmdQAlert) | |
self.cmdQTimer = nil | |
self.cmdQAlert = nil | |
end | |
function obj:stopCmdQ() | |
if self.cmdQTimer then | |
self.cmdQTimer:stop() | |
self:cmdQCleanup() | |
hs.alert("quit canceled", 0.5) | |
end | |
end | |
function obj:closeFinder(immediate) | |
local finder = hs.application.find("Finder") | |
if finder then | |
local win = finder:focusedWindow() | |
if win then | |
if immediate then | |
win:close() | |
else | |
self.cmdQTimer = hs.timer.doAfter(self.cmdQDelay, function() | |
win:close() | |
self:cmdQCleanup() | |
end) | |
self.cmdQAlert = hs.alert("hold to close Finder window", true) | |
end | |
end | |
end | |
end | |
function obj:startCmdQ() | |
local app = hs.application.frontmostApplication() | |
if app:name() == "Finder" then | |
self:closeFinder(false) -- false means use delay | |
return | |
end | |
self.cmdQTimer = hs.timer.doAfter(self.cmdQDelay, function() | |
app:kill() | |
self:cmdQCleanup() | |
end) | |
self.cmdQAlert = hs.alert("hold to quit " .. app:name(), true) | |
end | |
function obj:immediateQuit() | |
local app = hs.application.frontmostApplication() | |
if app:name() == "Finder" then | |
self:closeFinder(true) -- true means immediate | |
return | |
end | |
app:kill() | |
end | |
--- QuitEnhancer:init() | |
--- Method | |
--- Initialize the spoon | |
function obj:init() | |
return self | |
end | |
--- QuitEnhancer:start() | |
--- Method | |
--- Start the quit enhancer | |
--- | |
--- Parameters: | |
--- * delay - Optional number of seconds to hold Cmd-Q (default 2) | |
function obj:start(delay) | |
self.cmdQDelay = delay or 2 | |
-- Bind the hotkeys | |
self.cmdQ = hs.hotkey.bind({"cmd"}, "q", function() | |
self:startCmdQ() | |
end, function() | |
self:stopCmdQ() | |
end) | |
self.shiftCmdQ = hs.hotkey.bind({"cmd", "shift"}, "q", function() | |
self:immediateQuit() | |
end) | |
return self | |
end | |
--- QuitEnhancer:stop() | |
--- Method | |
--- Stop the quit enhancer and unbind its hotkeys | |
function obj:stop() | |
if self.cmdQ then | |
self.cmdQ:delete() | |
self.cmdQ = nil | |
end | |
if self.shiftCmdQ then | |
self.shiftCmdQ:delete() | |
self.shiftCmdQ = nil | |
end | |
return self | |
end | |
return obj |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment