Skip to content

Instantly share code, notes, and snippets.

@pallove
Last active May 24, 2022 14:42
Show Gist options
  • Save pallove/125fd35a524064fbf95752455a739110 to your computer and use it in GitHub Desktop.
Save pallove/125fd35a524064fbf95752455a739110 to your computer and use it in GitHub Desktop.
improve the spoon(HoldToQuit) of hammerspoon, the behaviour like Google Chrome`s
--- === HoldToQuit ===
---
--- Instead of pressing ⌘Q, hold ⌘Q to close applications.
local obj = {}
obj.__index = obj
-- Metadata
obj.name = "HoldToQuit"
obj.version = "1.1"
obj.author = "Matthias Strauss <matthias.strauss@mayflower.de>"
obj.github = "@MattFromGer"
obj.homepage = "https://github.com/Hammerspoon/Spoons"
obj.license = "MIT - https://opensource.org/licenses/MIT"
obj.revisor = "DustinLL"
--- HoldToQuit.duration
--- Variable
--- Integer containing the duration (in seconds) how long to hold
--- the hotkey. Default 1.
obj.duration = 0.8
--- HoldToQuit.defaultHotkey
--- Variable
--- Default hotkey mapping
obj.defaultHotkey = {
quit = { {"cmd"}, "Q" }
}
--- HoldToQuit.hotkeyQbj
--- Variable
--- Hotkey object
obj.hotkeyQbj = nil
--- HoldToQuit.timer
--- Variable
--- Timer for counting the holding time
obj.timer = nil
-- HoldToQuit.ignoreApp
obj.ignoreApp = {
{name = 'Finder', keep = true}, --- keep, avoid bell
{name = 'Google Chrome'}, --- use owner setting
{name = 'Hammerspoon', keep = true}, --- make it safe
}
local delayTimer
local timeStamp
local function gettime()
return math.floor(hs.timer.absoluteTime() / 1000000)
end
local function hasIgnore(app)
for _, obj in ipairs(obj.ignoreApp) do
if obj.name then
if string.find(app:path(), '/' .. obj.name) then
return true, obj
end
elseif obj.id then
if string.find(app:bundleID(), obj.id) then
return true, obj
end
end
end
return false, obj
end
--- HoldToQuit.killCurrentApp
--- Method
--- Kill the frontmost application
function obj:killCurrentApp()
hs.alert.closeAll(0)
delayTimer:stop()
local app = hs.application.frontmostApplication()
app:kill()
end
--- HoldToQuit:init()
--- Method
--- Initialize spoon
function obj:init()
delayTimer = hs.timer.delayed.new(0.5, function()
self.timer:stop()
end)
self.timer = hs.timer.delayed.new(self.duration, self.killCurrentApp)
end
--- HoldToQuit:onKeyDown()
--- Method
--- Start timer on keyDown
function obj:onKeyDown()
if self.timer:running() then
if delayTimer:running() then
self.timer:stop()
self:killCurrentApp()
end
else
hs.alert.closeAll(0)
local app = hs.application.frontmostApplication()
local flag, obj = hasIgnore(app)
if flag then
if obj.keep then return end
local hotkey = self.defaultHotkey.quit
hs.eventtap.event.newKeyEvent(hotkey[1], hotkey[2], true):post(app)
return
end
hs.alert.show(string.format("Hold %s to Quit [%s]", self.hotkeyQbj.idx, app:name()))
timeStamp = gettime()
self.timer:start()
end
end
--- HoldToQuit:onKeyUp()
--- Method
--- Stop Timer & show alert message
function obj:onKeyUp()
if self.timer:running() then
local endTime = gettime()
if (endTime - timeStamp < 200) then
delayTimer:start()
else
self.timer:stop()
end
else
local app = hs.application.frontmostApplication()
local flag, obj = hasIgnore(app)
if flag then
if obj.keep then return end
local hotkey = self.defaultHotkey.quit
hs.eventtap.event.newKeyEvent(hotkey[1], hotkey[2], false):post(app)
end
end
end
--- HoldToQuit:start()
--- Method
--- Start HoldToQuit with default hotkey
function obj:start()
if (self.hotkeyQbj) then
self.hotkeyQbj:enable()
else
local mod = self.defaultHotkey["quit"][1]
local key = self.defaultHotkey["quit"][2]
self.hotkeyQbj = hs.hotkey.bind(mod, key, function() obj:onKeyDown() end, function() obj:onKeyUp() end)
end
end
--- HoldToQuit:stop()
--- Method
--- Disable HoldToQuit hotkey
function obj:stop()
if (self.hotkeyQbj) then
self.hotkeyQbj:disable()
end
end
--- HoldToQuit:bindHotkeys(mapping)
--- Method
--- Binds hotkeys for HoldToQuit
---
--- Parameters:
--- * mapping - A table containing hotkey modifier/key details for the following items:
--- * show - This will define the quit hotkey
function obj:bindHotkeys(mapping)
if (self.hotkeyQbj) then
self.hotkeyQbj:delete()
end
local mod = mapping["quit"][1]
local key = mapping["quit"][2]
self.hotkeyQbj = hs.hotkey.bind(mod, key, function() obj:onKeyDown() end, function() obj:onKeyUp() end)
return self
end
return obj
@trolologuy
Copy link

Hi,

Thanks a lot for the help and for the great spoon ! Now it works as expected ! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment