Last active
January 8, 2024 06:17
-
-
Save amirrajan/cc5ead4015a8b9252060ce6345eebe76 to your computer and use it in GitHub Desktop.
Full Hammerspoon File
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require("hs.ipc") | |
function shell(command) | |
hs.execute(command .. ' &', true) | |
end | |
--- ========================================== | |
--- Window Management | |
--- ========================================== | |
-- ctrl+option+left resizes window to left half of screen | |
hs.hotkey.bind({'ctrl', 'option'}, "Left", function() | |
local win = hs.window.focusedWindow() | |
local f = win:frame() | |
local screen = win:screen() | |
local max = screen:frame() | |
local target_w_half = math.floor(max.w / 2) | |
local target_w_third = math.floor(max.w / 3) | |
local target_w_two_thirds = math.floor(max.w * 2 / 3) | |
f.x = max.x | |
f.y = max.y | |
if f.w == target_w_half then | |
f.w = target_w_third | |
elseif f.w == target_w_third then | |
f.w = target_w_two_thirds | |
else | |
f.w = target_w_half | |
end | |
f.h = max.h | |
win:setFrame(f, 0) | |
end) | |
-- ctrl+option+right resizes window to right half of screen | |
hs.hotkey.bind({'ctrl', 'option'}, "Right", function() | |
local win = hs.window.focusedWindow() | |
local f = win:frame() | |
local screen = win:screen() | |
local max = screen:frame() | |
local target_w_half = math.floor(max.w / 2) | |
local target_w_third = math.floor(max.w / 3) | |
local target_w_two_thirds = math.floor(max.w * 2 / 3) | |
f.y = max.y | |
if f.w == target_w_half and f.x == max.x + (max.w / 2) then | |
f.x = max.x + (max.w - target_w_third) | |
f.w = target_w_third | |
elseif f.w == target_w_third then | |
f.x = max.x + (max.w - target_w_two_thirds) | |
f.w = target_w_two_thirds | |
else | |
f.x = max.x + target_w_half | |
f.w = target_w_half | |
end | |
f.h = max.h | |
win:setFrame(f, 0) | |
end) | |
-- ctrl+option+j resizes window to fill screen | |
hs.hotkey.bind({'ctrl', 'option'}, "j", function() | |
local win = hs.window.focusedWindow() | |
local f = win:frame() | |
local screen = win:screen() | |
local max = screen:frame() | |
f.x = max.x | |
f.y = max.y | |
f.w = max.w | |
f.h = max.h | |
win:setFrame(f, 0) | |
end) | |
-- ctrl+option+, centers window and toggles between 1280x720 and full vertical height | |
hs.hotkey.bind({'ctrl', 'option'}, ",", function() | |
local win = hs.window.focusedWindow() | |
local f = win:frame() | |
local screen = win:screen() | |
local max = screen:frame() | |
local h = 748 | |
if f.w == 1280 and f.h == h then | |
f.x = max.x + (max.w / 4) | |
f.w = max.w / 2 | |
f.y = max.y | |
f.h = max.h | |
elseif f.w == max.w / 2 and f.x == max.x + (max.w / 4)then | |
f.w = 1280 | |
f.h = h | |
f.x = max.x + ((max.w - f.w) / 2) | |
f.y = max.y + ((max.h - f.h) / 2) | |
else | |
f.x = max.x + (max.w / 4) | |
f.w = max.w / 2 | |
f.y = max.y | |
f.h = max.h | |
end | |
win:setFrame(f, 0) | |
end) | |
-- ctrl+option+up sends window to next screen | |
hs.hotkey.bind({'ctrl', 'option'}, "Up", function() | |
local win = hs.window.focusedWindow() | |
win:moveToScreen(win:screen():previous(), 0) | |
end) | |
-- ctrl+option+down sends window to prev screen | |
hs.hotkey.bind({'ctrl', 'option'}, "Down", function() | |
local win = hs.window.focusedWindow() | |
win:moveToScreen(win:screen():next(), 0) | |
end) | |
--- ========================================== | |
--- Terminal <> Browser ctrl+t | |
--- ========================================== | |
-- I spend all my time in chrome and terminal, ctrl+t swaps between the two | |
hs.hotkey.bind({'ctrl'}, "t", function() | |
app_name = hs.application.frontmostApplication():name() | |
if app_name == 'Alacritty' then | |
hs.osascript.applescript('tell application "Chrome" to activate') | |
else | |
hs.osascript.applescript('tell application "Alacritty" to activate') | |
end | |
end) | |
--- ========================================== | |
--- Reload Hammerspoon | |
--- ========================================== | |
function reloadConfig(files) | |
hs.alert('Reloading Hammerspoon...') | |
shouldReload = false | |
for _,file in pairs(files) do | |
if file:sub(-4) == ".lua" then | |
shouldReload = true | |
end | |
end | |
if shouldReload then | |
hs.timer.delayed.new(0.1, doReload):start() | |
end | |
end | |
function doReload(evt) | |
if doReload then | |
result, success = hs.execute("luac -p ~/.hammerspoon/init.lua 2>&1 >/dev/null", true) | |
if not success then | |
hs.alert(result) | |
return | |
end | |
result, success = hs.execute("luac -p ~/.hammerspoon/Spoons/KeyFu.spoon/init.lua 2>&1 >/dev/null", true) | |
if not success then | |
hs.alert(result) | |
return | |
end | |
hs.reload() | |
end | |
end | |
hs_config_watcher = hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reloadConfig):start() | |
-- ========================================== | |
-- ESC | |
-- ========================================== | |
g_mod_keys = true | |
send_escape = false | |
last_mods = {} | |
control_key_handler = function() | |
send_escape = false | |
end | |
control_key_timer = hs.timer.delayed.new(0.10, control_key_handler) | |
control_handler = function(evt) | |
if not g_mod_keys then | |
return | |
end | |
local new_mods = evt:getFlags() | |
if last_mods["ctrl"] == new_mods["ctrl"] then | |
return false | |
end | |
if not last_mods["ctrl"] then | |
last_mods = new_mods | |
send_escape = true | |
control_key_timer:start() | |
else | |
if send_escape then | |
if not g_hs_mode then | |
hs.eventtap.event.newKeyEvent({}, 'escape', true):post() | |
hs.eventtap.event.newKeyEvent({}, 'escape', false):post() | |
end | |
end | |
last_mods = new_mods | |
control_key_timer:stop() | |
end | |
return false | |
end | |
control_tap = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, control_handler) | |
control_tap:start() | |
other_handler = function(evt) | |
send_escape = false | |
return false | |
end | |
other_tap = hs.eventtap.new({hs.eventtap.event.types.keyDown}, other_handler) | |
other_tap:start() | |
-- ========================================== | |
-- Hammerspoon Mode | |
-- ========================================== | |
-- OS level Hammerspoon Leader Key is ctrl+m | |
g_hs_mode = false | |
g_hs_mode_command = '' | |
hs.hotkey.bind({'ctrl'}, "m", function() | |
if not g_hs_mode then | |
hs.alert('hs mode: on') | |
g_hs_mode = true | |
end | |
end) | |
-- when in Hammerspoon mode, process keyboard input and execute a command | |
hs_mode_handler = function(evt) | |
local new_mods = evt:getFlags() | |
if not g_hs_mode then | |
return | |
end | |
if evt:getCharacters(true) then | |
g_hs_mode_command = g_hs_mode_command .. evt:getCharacters(true) | |
end | |
local was_processed = false | |
if evt:getCharacters(true) == 'i' then -- i takes you back to insert mode | |
was_processed = true | |
hs.alert('hs mode: off') | |
elseif g_hs_mode_command == 'go' then -- go takes you to google | |
shell('open http://google.com') | |
was_processed = true | |
elseif g_hs_mode_command == 'gm' then -- gm takes you to gmail | |
shell('open http://gmail.com') | |
was_processed = true | |
elseif g_hs_mode_command == 'tmw' then -- tmw "top most window" | |
-- run the applescript and get the result | |
-- alert the result | |
local ok, r = hs.osascript.applescript('tell application "System Events" to get the name of the first window of (first process where it is frontmost)') | |
hs.alert(r) | |
was_processed = true | |
elseif g_hs_mode_command == 'l' then | |
hs.alert(hs.mouse.absolutePosition().x) | |
hs.alert(hs.mouse.absolutePosition().y) | |
was_processed = true | |
elseif g_hs_mode_command == 'c' then | |
shell("sh ~/clicker.sh") | |
-- local centerPoint = hs.mouse.absolutePosition() --{x = hs.screen.mainScreen():frame().w / 2, y = hs.screen.mainScreen():frame().h / 2} | |
-- hs.mouse.absolutePosition(centerPoint) | |
-- local radius = 400 | |
-- local angle = 0 | |
-- local step = 100 | |
-- local ordinal_x = 0 | |
-- local ordinal_y = 0 | |
-- for i=radius, 0, -step do | |
-- local position = {x = centerPoint.x - 450 + ordinal_x, y = centerPoint.y + ordinal_y} | |
-- ordinal_x = ordinal_x + 64 | |
-- if ordinal_x > 900 then | |
-- ordinal_x = 0 | |
-- ordinal_y = ordinal_y + 32 | |
-- end | |
-- local offPoint = {x = hs.screen.mainScreen():frame().w / 2 - 600, y = hs.screen.mainScreen():frame().h / 2} | |
-- print(string.format("cliclick dd:%.0f,%.0f du:%.0f,%.0f c:%.0f,%.0f", | |
-- math.floor(position.x - 1), | |
-- math.floor(position.y - 1), | |
-- math.floor(position.x - 2), | |
-- math.floor(position.y - 2), | |
-- math.floor(position.x - 2), | |
-- math.floor(position.y - 2))) | |
-- shell(string.format("cliclick dd:%.0f,%.0f du:%.0f,%.0f c:%.0f,%.0f", | |
-- math.floor(position.x - 1), | |
-- math.floor(position.y - 1), | |
-- math.floor(position.x - 2), | |
-- math.floor(position.y - 2), | |
-- math.floor(position.x - 2), | |
-- math.floor(position.y - 2))) | |
-- shell(string.format("cliclick ", math.floor(position.x), math.floor(position.y))) | |
-- shell(string.format("cliclick c:%.0f,%.0f", math.floor(position.x), math.floor(position.y))) | |
-- end | |
hs.alert('complete') | |
was_processed = true | |
end | |
if was_processed then | |
g_hs_mode = false | |
g_hs_mode_command = '' | |
return true | |
end | |
if string.len(g_hs_mode_command) > 3 then | |
hs.alert("exiting (unknown command): " .. g_hs_mode_command) | |
g_hs_mode = false | |
g_hs_mode_command = '' | |
end | |
return true | |
end | |
hs_mode = hs.eventtap.new({hs.eventtap.event.types.keyDown}, hs_mode_handler) | |
hs_mode:start() | |
hs.alert.show("Hammerspoon Loaded.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment