Skip to content

Instantly share code, notes, and snippets.

@james2doyle
Created August 15, 2022 17:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james2doyle/7ba8dca41b23a6a227a6568907a1ee96 to your computer and use it in GitHub Desktop.
Save james2doyle/7ba8dca41b23a6a227a6568907a1ee96 to your computer and use it in GitHub Desktop.
A Hammerspoon script that allows actions to be bound to quadrants on the trackpad
--[[
Name: Touchpad Control
Author: James Doyle <james2doyle@gmail.com>
Description: Hook into events/gestures that are triggered on the trackpad
Installation: Just require this file in your Hammerspoon init.lua file
Usage:
Bind the click actions or swipe actions to events
]]--
local trackpad_actions = {}
trackpad_actions["double_click"] = {}
trackpad_actions["triple_click"] = {
top_left = { mod = { "cmd" }, press = "w", name = "close window" },
bottom_left = { mod = { "cmd" }, press = "m", name = "minimize window" }
}
trackpad_actions["swipe"] = {
{
start = "top_left",
stop = "bottom_left",
name = "decrease volume",
action = function()
local audio_output = hs.audiodevice.defaultOutputDevice()
local volume = audio_output:outputVolume()
audio_output:setOutputVolume(volume - 5.0)
end
},
{
start = "bottom_left",
stop = "top_left",
name = "increase volume",
action = function()
local audio_output = hs.audiodevice.defaultOutputDevice()
local volume = audio_output:outputVolume()
audio_output:setOutputVolume(volume + 5.0)
end
}
}
-- trackpad layout
-- |0,1 1,1|
-- | |
-- | |
-- | 0.5,0.5 |
-- | |
-- | |
-- |0,0 1,0|
local log = hs.logger.new('trackpad-module', 'debug')
log:d("i am debugging trackpad-module")
local top_left = { start = { x = 0, y = 0.75 }, stop = { x = 0.25, y = 1 } }
local top_right = { start = { x = 0.75, y = 0.75 }, stop = { x = 1, y = 1 } }
local bottom_left = { start = { x = 0, y = 0 }, stop = { x = 0.25, y = 0.25 } }
local bottom_right = { start = { x = 0.75, y = 0 }, stop = { x = 1, y = 0.75 } }
-- causes eventtap to respond to *all* events that it can, except keyboard stuff
local eventList = {
"all",
hs.eventtap.event.types.flagsChanged,
hs.eventtap.event.types.keyDown,
hs.eventtap.event.types.keyUp,
hs.eventtap.event.types.mouseMoved
}
local lastEvent = nil
local click_counter = 0
local start_quadrant = nil
local end_quadrant = nil
-- debounce the callback that is run after touching is complete
local timer = hs.timer.doAfter(0.2, function()
if start_quadrant ~= nil and end_quadrant ~= nil then
hs.fnutils.each(trackpad_actions.swipe, function (action)
if start_quadrant == action.start and end_quadrant == action.stop then
log:d("swipe, " .. action.name)
action.action()
end
end)
if click_counter == 2 then
for quadrant,action in hs.fnutils.sortByKeys(trackpad_actions.double_click) do
if start_quadrant == quadrant and end_quadrant == quadrant then
log:d("double_click, " .. action.name)
hs.eventtap.keyStroke(action.mod, action.press)
end
end
end
if click_counter == 3 then
for quadrant,action in hs.fnutils.sortByKeys(trackpad_actions.triple_click) do
if start_quadrant == quadrant and end_quadrant == quadrant then
log:d("triple_click, " .. action.name)
hs.eventtap.keyStroke(action.mod, action.press)
end
end
end
click_counter = 0
start_quadrant = nil
end_quadrant = nil
end
end):stop()
function get_position(x, y)
if x > top_left.start.x and y > top_left.start.y and x < top_left.stop.x and y < top_left.stop.y then
return "top_left"
end
if x > top_right.start.x and y > top_right.start.y and x < top_right.stop.x and y < top_right.stop.y then
return "top_right"
end
if x > bottom_left.start.x and y > bottom_left.start.y and x < bottom_left.stop.x and y < bottom_left.stop.y then
return "bottom_left"
end
if x > bottom_right.start.x and y > bottom_right.start.y and x < bottom_right.stop.x and y < bottom_right.stop.y then
return "bottom_right"
end
return "center"
end
hs.eventtap.new({hs.eventtap.event.types.gesture, hs.eventtap.event.types.tabletPointer}, function (e)
local details = e:getTouches()
if details[1] and details[1]["phase"] == "began" then
click_counter = click_counter + 1
end
if start_quadrant == nil and details[1] and details[1]["phase"] == "began" then
local x = details[1]["normalizedPosition"]["x"]
local y = details[1]["normalizedPosition"]["y"]
start_quadrant = get_position(x, y)
end
if end_quadrant == nil and details[1] and details[1]["phase"] == "ended" then
local x = details[1]["normalizedPosition"]["x"]
local y = details[1]["normalizedPosition"]["y"]
end_quadrant = get_position(x, y)
end
timer:stop()
timer:start()
end):start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment