Skip to content

Commit 31bc17d

Browse files
committed
fix: control/escape spoon should work with Alfred
The previous technique called keySend() to send the escape key press while handling a key event. Instead, just return the escape key press & release. Faster and no worry about the handler being re-entrant.
1 parent 64e3e16 commit 31bc17d

File tree

2 files changed

+32
-33
lines changed

2 files changed

+32
-33
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"Lua.diagnostics.globals": ["hs"]
3+
}

tag-macos/hammerspoon/Spoons/ControlEscape.spoon/init.lua

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
--- as the `escape` key. If the `control` key is held down and used in
55
--- combination with another key, then provide the normal `control` key
66
--- behavior.
7-
8-
local obj={}
7+
local obj = {}
98
obj.__index = obj
109

1110
-- Metadata
@@ -27,46 +26,43 @@ function obj:init()
2726

2827
-- Create an eventtap to run each time the modifier keys change (i.e., each
2928
-- time a key like control, shift, option, or command is pressed or released)
30-
self.controlTap = hs.eventtap.new({hs.eventtap.event.types.flagsChanged},
31-
function(event)
32-
local newModifiers = event:getFlags()
29+
self.controlTap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged }, function(event)
30+
local newModifiers = event:getFlags()
3331

34-
-- If this change to the modifier keys does not invole a *change* to the
35-
-- up/down state of the `control` key (i.e., it was up before and it's
36-
-- still up, or it was down before and it's still down), then don't take
37-
-- any action.
38-
if self.lastModifiers['ctrl'] == newModifiers['ctrl'] then
39-
return false
40-
end
32+
-- If this flag change does not involve a *change* to the up/down state of
33+
-- the `control` key (i.e., it was up before and it's still up, or it was
34+
-- down before and it's still down), then don't take any action.
35+
if self.lastModifiers['ctrl'] == newModifiers['ctrl'] then return false end
4136

42-
-- If the `control` key has changed to the down state, then start the
43-
-- timer. If the `control` key changes to the up state before the timer
44-
-- expires, then send `escape`.
45-
if not self.lastModifiers['ctrl'] then
46-
self.lastModifiers = newModifiers
47-
self.sendEscape = true
48-
self.controlKeyTimer:start()
49-
else
50-
if self.sendEscape then
51-
hs.eventtap.keyStroke({}, 'escape', 1)
52-
end
53-
self.lastModifiers = newModifiers
54-
self.controlKeyTimer:stop()
37+
-- If the `control` key has changed to the down state, then start the
38+
-- timer. If the `control` key changes to the up state before the timer
39+
-- expires, then send `escape`.
40+
if not self.lastModifiers['ctrl'] then
41+
self.lastModifiers = newModifiers
42+
self.sendEscape = true
43+
self.controlKeyTimer:start()
44+
else
45+
self.lastModifiers = newModifiers
46+
self.controlKeyTimer:stop()
47+
if self.sendEscape then
48+
-- Return an escape key event for being pressed and released.
49+
return true, {
50+
hs.eventtap.event.newKeyEvent({}, 'escape', true),
51+
hs.eventtap.event.newKeyEvent({}, 'escape', false),
52+
}
5553
end
56-
return false
5754
end
58-
)
55+
return false
56+
end)
5957

6058
-- Create an eventtap to run each time a normal key (i.e., a non-modifier key)
6159
-- enters the down state. We only want to send `escape` if `control` is
6260
-- pressed and released in isolation. If `control` is pressed in combination
6361
-- with any other key, we don't want to send `escape`.
64-
self.keyDownEventTap = hs.eventtap.new({hs.eventtap.event.types.keyDown},
65-
function(event)
66-
self.sendEscape = false
67-
return false
68-
end
69-
)
62+
self.keyDownEventTap = hs.eventtap.new({ hs.eventtap.event.types.keyDown }, function(event)
63+
self.sendEscape = false
64+
return false
65+
end)
7066
end
7167

7268
--- ControlEscape:start()

0 commit comments

Comments
 (0)