I'm using the following in an attempt to emulate what I had w/ Karabiner to add a symbol layer to my keyboard. I use karabiner-elements to map Caps Lock to F18 and then use this to map tapping capslock to escape and holding and pressing another key (like Caps Lock+F -> ()
This works pretty well except for a couple exceptions. I don't want to list them all in one issue, so I'll list the first here:
If I press Ctrl+Caps Lock I end up with Ctrl+F18 when I really want Ctrl+ESC. I could remap that explicitly, but then I need to do the same for Cmd+Caps Lock and all combinations of modifiers.
Is there a way to sort of "pass through" the modifier keys for a binding? I'd also like this to apply to the symbols, so if I hit Ctrl+Caps Lock+F I'd get Ctrl+(
@aaronjensen
untested, and maybe reckless rubbish but maybe something along these lines:
hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, function(e)
local mods = e:getFlags()
local keyCode = e:getKeyCode()
if ((hs.eventtap.checkKeyboardModifiers().capslock) and mods.ctrl and keyCode.f) then
hs.eventtap.keyStroke({'ctrl'}, "(")
end
end)
_apologies if this errors, not been coding for long_
@rootscript thank you for the suggestion. This wasn't exactly what I needed, but it did point me in the right direction. I ended up using eventtap.new to create my bindings so I could listen to all modifiers and forward them on.
Here is is what I ended up with: https://github.com/aaronjensen/dotfiles/blob/9bcf07ebaf3ef7f597c37daefaae78d5492e13a0/hammerspoon/symbol_layer.lua
Symbol layer
-- The default delay is too slow, making key repeating very slow
fast_delay = 1000
function tableContainsValue(tbl, value)
for _, v in ipairs(tbl) do
if v == value then
return true
end
end
return false
end
function itableUnion(a, b)
local ab = {}
for _, v in ipairs(a) do
table.insert(ab, v)
end
for _, v in ipairs(b) do
if not tableContainsValue(ab, v) then
table.insert(ab, v)
end
end
return ab
end
function tableKeys(tbl)
local ret = {}
for key, _ in pairs(tbl) do
table.insert(ret, key)
end
return ret
end
function enableSymbolLayer()
local symbols = {
o = {{}, '-'}, -- o -> -
p = {{'shift'}, '='}, -- p -> +
s = {{}, '['}, -- s -> [
d = {{'shift'}, '['}, -- d -> {
f = {{'shift'}, '9'}, -- f -> (
g = {{}, '='}, -- g -> =
h = {{'shift'}, '-'}, -- h -> _
j = {{'shift'}, '0'}, -- j -> )
k = {{'shift'}, ']'}, -- k -> }
l = {{}, ']'}, -- l -> ]
c = {{'shift'}, '`'}, -- c -> ~
v = {{}, '`'}, -- v -> `
m = {{'shift'}, '\\'}, -- m -> |
[','] = {{'shift'}, ','}, -- , -> <
['.'] = {{'shift'}, '.'}, -- . -> >
}
-- If you hold capslock for this long and then let go, ESC will not be sent.
local cancel_delay_seconds = 0.3
local triggered = true
local resetTimer = hs.timer.delayed.new(cancel_delay_seconds, function()
triggered = true
end)
-- This tap handles remapping. It is only enabled while capslock is held
local tap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, function(event)
-- Check if this event is from the keyboard or from us. We need to ignore
-- events from us.
local processId = event:getProperty(hs.eventtap.event.properties.eventSourceUnixProcessID)
if processId > 0 then
return false
end
triggered = true
local key = hs.keycodes.map[event:getKeyCode()]
local remap = symbols[key]
if remap then
local mods = tableKeys(event:getFlags())
local newMods = itableUnion(mods, remap[1])
local newKey = remap[2]
hs.eventtap.keyStroke(newMods, newKey, fast_delay)
end
-- Do not send event on
return true
end)
-- This tap handles F18 (capslock) with any modifier and is enabled right away.
hs.eventtap.new({hs.eventtap.event.types.keyDown, hs.eventtap.event.types.keyUp}, function(event)
local key = hs.keycodes.map[event:getKeyCode()]
-- Ignore all events but f18
if key ~= 'f18' then
return false
end
if event:getType() == hs.eventtap.event.types.keyDown then
resetTimer:start()
triggered = false
tap:start()
else
resetTimer:stop()
tap:stop()
if not triggered then
-- Strip the fn flag, which is set because the key is f18
local flags = event:getFlags()
flags['fn'] = nil
local mods = tableKeys(flags)
hs.eventtap.keyStroke(mods, 'ESCAPE', fast_delay)
end
end
-- Do not send event on
return true
end):start()
end
enableSymbolLayer()
I consider this closed because I was able to do it.
Hi, I don't think that the code is working anymore
Most helpful comment
@rootscript thank you for the suggestion. This wasn't exactly what I needed, but it did point me in the right direction. I ended up using
eventtap.newto create my bindings so I could listen to all modifiers and forward them on.Here is is what I ended up with: https://github.com/aaronjensen/dotfiles/blob/9bcf07ebaf3ef7f597c37daefaae78d5492e13a0/hammerspoon/symbol_layer.lua
Symbol layer
I consider this closed because I was able to do it.