Skip to content

Instantly share code, notes, and snippets.

@ajsharp
Created July 14, 2020 19:53
Show Gist options
  • Save ajsharp/044d9585e85eeff195d8f8683d57bbc2 to your computer and use it in GitHub Desktop.
Save ajsharp/044d9585e85eeff195d8f8683d57bbc2 to your computer and use it in GitHub Desktop.
hammerspoon config
-- hs.hotkey.bind({'cmd', 'shift'}, 'q', function()
-- hs.eventtap.keyStroke({}, "`", 0)
-- -- hs.alert.show('hi')
-- end)
-- four item tuples:
-- fromMod, fromKey, toMod, toKey
KEYMAP = {
{{'cmd', 'shift'}, 'q', {}, '`'}, -- backtick shortcut
{{'cmd'}, 'escape', {'cmd'}, '`'}, -- cycle windows via cmd+esc
{{'alt'}, 'v', {'cmd'}, 'v'}, -- remap pasting until karabiner is fixed
{{"ctrl", "shift"}, "j", {'alt'}, 'left'}, -- jump left
{{"ctrl", "shift"}, "k", {'alt'}, 'right'}, -- jump right
{{'ctrl', 'shift'}, 'i', {'cmd'}, 'up'}, -- jump to beginning of file
{{'ctrl', 'shift'}, 'n', {'cmd'}, 'down'}, -- jump to end of file
{{'ctrl', 'cmd'}, 'j', {'cmd'}, 'left'}, -- jump beginning of line
{{'ctrl', 'cmd'}, 'k', {'cmd'}, 'right'}, -- end of line
{{'ctrl', 'shift'}, 'p', {}, 'delete'},
{{'cmd', 'shift'}, 'l', {'cmd', 'shift'}, 'right'}, -- select to the end of the line
{{'cmd', 'shift'}, 'j', {'cmd', 'shift'}, 'left'}
}
for _, hotkeyVals in ipairs(KEYMAP) do
local fromMods, fromKey, toMods, toKey = table.unpack(hotkeyVals)
local toKeyStroke = function()
hs.eventtap.keyStroke(toMods, toKey, 0)
end
hs.hotkey.bind(fromMods, fromKey, toKeyStroke, nil, toKeyStroke)
end
-- make double-tap control be esc
local timer = require("hs.timer")
local eventtap = require("hs.eventtap")
local events = eventtap.event.types
local module = {}
-- ho quickly must the two single ctrl taps occur?
module.timeFrame = 0.2
-- wht to do when the double tap of ctrl occurs
module.action = function()
hs.eventtap.keyStroke({}, 'escape', 0)
end
local timeFirstControl, firstDown, secondDown = 0, false, false
-- verify that no keyboard flags are being pressed
local noFlags = function(ev)
local result = true
for k,v in pairs(ev:getFlags()) do
if v then
result = false
break
end
end
return result
end
-- verify that *only* the ctrl key flag is being pressed
local onlyCtrl = function(ev)
local result = ev:getFlags().ctrl
for k,v in pairs(ev:getFlags()) do
if k ~= "ctrl" and v then
result = false
break
end
end
return result
end
-- the actual workhorse
module.eventWatcher = eventtap.new({events.flagsChanged, events.keyDown}, function(ev)
-- if it's been too long; previous state doesn't matter
if (timer.secondsSinceEpoch() - timeFirstControl) > module.timeFrame then
timeFirstControl, firstDown, secondDown = 0, false, false
end
if ev:getType() == events.flagsChanged then
if noFlags(ev) and firstDown and secondDown then -- ctrl up and we've seen two, so do action
if module.action then module.action() end
timeFirstControl, firstDown, secondDown = 0, false, false
elseif onlyCtrl(ev) and not firstDown then -- ctrl down and it's a first
firstDown = true
timeFirstControl = timer.secondsSinceEpoch()
elseif onlyCtrl(ev) and firstDown then -- ctrl down and it's the second
secondDown = true
elseif not noFlags(ev) then -- otherwise reset and start over
timeFirstControl, firstDown, secondDown = 0, false, false
end
else -- it was a key press, so not a lone ctrl char -- we don't care about it
timeFirstControl, firstDown, secondDown = 0, false, false
end
return false
end):start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment