SkyRocket & HammerDrag
I’ve been using SkyRocket by David Balatero for years and it has been serving me very well. After starting to use hs.grid more, I wanted to add grid support to SkyRocket, but luckily Justin Wyne had already implemented the functionality and made a pull request to SkyRocket. It hasn’t been merged, but his branch’s versin can be copied to Hammerspoon config. Justin also had renamed the spoon to HammerDrag.
HammerDrag/SkyRocket can be installed by copying the init.lua to ~/.hammerspoon/spoons
└── Spoons
└── HammerDrag.spoon
└── init.lua
After which it can be taken into use in your own Hammerspoon config:
local HammerDrag = hs.loadSpoon("HammerDrag")
HammerDrag:new({
enabled = true,
preview = true,
opacity = 0.25,
grid = hs.grid,
focusOnClick = false,
moveGridMouseButton = "left",
moveGridModifiers = { "alt", "ctrl" },
resizeGridMouseButton = "right",
resizeGridModifiers = { "alt", "ctrl" },
moveMouseButton = 'left',
moveModifiers = { 'alt' },
resizeMouseButton = 'right',
resizeModifiers = { 'alt' },
disabledApps = { "Pixelmator Pro", "Affinity Designer", "System Preferences", "Teams", "Microsoft Teams" },
})
With this alt+click maintains the original SkyRocket configuration and ctrl+alt+click has the new grid support.
Using Hammerspoon’s hs.grid
Configuration:
hs.window.animationDuration = 0
hs.grid.MARGINX = 8
hs.grid.MARGINY = 8
hs.grid.setGrid("12x6", "3840x2160")
hs.grid.setGrid("6x5")
Snapping window under cursor to grid
local function get_window_under_mouse()
local _ = hs.application
local my_pos = hs.geometry.new(hs.mouse.getAbsolutePosition())
local my_screen = hs.mouse.getCurrentScreen()
return hs.fnutils.find(hs.window.orderedWindows(), function(w)
return my_screen == w:screen() and my_pos:inside(w:frame())
end)
end
hs.hotkey.bind({ "alt" }, "q", function()
local win = get_window_under_mouse()
if win then
hs.grid.snap(win)
end
end)
Resizing windows in grid with hotkeys
These hotkeys use bottom right as reference:
hs.hotkey.bind({ "cmd", "ctrl" }, "right", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.w = cell.w + 1
hs.grid.set(win, cell)
end
end)
hs.hotkey.bind({ "cmd", "ctrl" }, "left", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.w = cell.w - 1
hs.grid.set(win, cell)
end
end)
hs.hotkey.bind({ "cmd", "ctrl" }, "up", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.h = cell.h - 1
hs.grid.set(win, cell)
end
end)
hs.hotkey.bind({ "cmd", "ctrl" }, "down", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.h = cell.h + 1
hs.grid.set(win, cell)
end
end)
Top left as reference:
hs.hotkey.bind({ "cmd", "ctrl", "alt" }, "right", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.w = cell.w - 1
cell.x = cell.x + 1
hs.grid.set(win, cell)
end
end)
hs.hotkey.bind({ "cmd", "ctrl", "alt" }, "left", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.w = cell.w + 1
cell.x = cell.x - 1
hs.grid.set(win, cell)
end
end)
hs.hotkey.bind({ "cmd", "ctrl", "alt" }, "up", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.h = cell.h + 1
cell.y = cell.y - 1
hs.grid.set(win, cell)
end
end)
hs.hotkey.bind({ "cmd", "ctrl", "alt" }, "down", function()
local win = hs.window.focusedWindow()
if win then
local cell = hs.grid.get(win)
cell.h = cell.h - 1
cell.y = cell.y + 1
hs.grid.set(win, cell)
end
end)
Resizing to fullscreen and back to original size
Save original window size and positions to global variables:
windowPosX = 0
windowPosY = 0
windowWidth = 0
windowHeight = 0
Functions to save position, setting window to fullscreen and restoring original size:
function saveWindowSizeAndPosition()
local win = hs.window.focusedWindow()
local f = win:frame()
windowWidth = f.w
windowHeight = f.h
windowPosX = f.x
windowPosY = f.y
end
function restoreSavedWindowSizeAndPosition()
hs.window.animationDuration = 0
local win = hs.window.focusedWindow()
local f = win:frame()
f.w = windowWidth
f.h = windowHeight
f.x = windowPosX
f.y = windowPosY
win:setFrame(f, 0)
end
function setFullScreen()
saveWindowSizeAndPosition()
hs.window.animationDuration = 0
local win = hs.window.focusedWindow()
hs.grid.maximizeWindow(win)
end
Hotkeys:
hs.hotkey.bind({ "alt", "ctrl" }, "Up", function()
setFullScreen()
end)
hs.hotkey.bind({ "ctrl", "alt" }, "down", function()
local win = hs.window.focusedWindow()
if win then
restoreSavedWindowSizeAndPosition()
end
end)