Skip to content

Instantly share code, notes, and snippets.

@jakebathman
Last active May 18, 2020 19:22
Show Gist options
  • Save jakebathman/1e1491283de47cb10fbec92a969be061 to your computer and use it in GitHub Desktop.
Save jakebathman/1e1491283de47cb10fbec92a969be061 to your computer and use it in GitHub Desktop.
Hammerspoon config
-- Clear the console
hs.console.clearConsole()
-- Set the default grid
hs.grid.MARGINX = 0
hs.grid.MARGINY = 0
hs.grid.GRIDWIDTH = 20
hs.grid.GRIDHEIGHT = 100
-- Also can be set using hs.grid.setGrid'20x100'
-- Don't use any animations
hs.window.animationDuration = 0.1
-- Other settings
globalPadX = 10
globalPadY = 10
globalPadXLarge = 25
globalPadYLarge = 25
globalOSMenuHeight = 20
-- Put the twitch stream in the bottom-right
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"H",
function()
-- Move the active window to the bottom-right ~1/3
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
-- Big secondary monitor
-- Window size will be 1280x681
-- Position top left at -1280,369
pos = hs.geometry(-1280, 370, 1280, 680)
hs.window.focusedWindow():move(pos)
else
-- Main laptop screen
-- Window size will be 1084x570
-- Position top left at 596,415
pos = hs.geometry(596, 415, 1084, 570)
hs.window.focusedWindow():move(pos)
end
end
)
-- Put the twitch stream in the bottom-right and chatty next to it
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"Z",
function()
-- Move the active window to the bottom-right ~1/3
-- This is the stream window (make same as cmd+alt+ctrl+H)
logWindowInfo()
-- Continue only if the active window is a Twitch stream
curWindow = hs.window.focusedWindow()
if string.find(curWindow:title(), " - Twitch") then
curScreen =hs.screen.mainScreen():name()
if curScreen == "LG Ultra HD" then
-- Big secondary monitor
-- Window size will be 1280x680
-- Position top left at -1280,370
pos = hs.geometry(-1280, 370, 1280, 680)
curWindow:move(pos)
-- Chatty window will be 1033x736
-- Position top left at -w,-367
chatty = hs.application.get('Chatty')
chatty:activate()
chattyWin = chatty:focusedWindow()
pos = hs.geometry(-1*chattyWin:frame().w, -367, 1033, 737)
chattyWin:moveToScreen(curScreen)
chattyWin:move(pos)
else
-- Main laptop screen
-- Window size will be 1084x570
-- Position top left at 596,415
pos = hs.geometry(596, 415, 1084, 570)
curWindow:move(pos)
-- Chatty window will be 991x736
-- Position top left at 0,22
chatty = hs.application.get('Chatty')
chatty:activate()
chattyWin = chatty:focusedWindow()
pos = hs.geometry(0, 22, 991, 736)
chattyWin:moveToScreen(curScreen)
chattyWin:move(pos)
-- Re-focus the stream window
curWindow:focus()
end
end
end
)
-- Put the twitch stream in the bottom-right but bigger
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"T",
function()
-- Move the active window to the bottom-right ~2/3
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
-- Big secondary monitor
-- Window size will be 1280x681
-- Position top left at -1280,369
pos = hs.geometry(-1873, 37, 1873, 1013)
hs.window.focusedWindow():move(pos)
else
-- Main laptop screen
-- Window size will be 1084x570
-- Position top left at 596,415
pos = hs.geometry(296, 246, 1384, 739)
hs.window.focusedWindow():move(pos)
end
end
)
-- Size window to smallest "restore" size and center
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"j",
function()
win = hs.window.focusedWindow()
w = 800
h = 500
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
w = 820
h = 560
end
sizeAndCenterWindow(win, w, h)
end
)
-- Size window to smaller "restore" size and center
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"k",
function()
win = hs.window.focusedWindow()
w = 1100
h = 750
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
w = 1360
h = 900
end
sizeAndCenterWindow(win, w, h)
end
)
-- Size window to medium "restore" size and center
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"l",
function()
win = hs.window.focusedWindow()
w = 1350
h = 850
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
w = 2020
h = 1280
end
sizeAndCenterWindow(win, w, h)
end
)
-- Size window to larger "restore" size and center
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
";",
function()
win = hs.window.focusedWindow()
w = 1500
h = 930
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
w = 2290
h = 1350
end
sizeAndCenterWindow(win, w, h)
end
)
-- Size window to maximum
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"'",
function()
win = hs.window.focusedWindow()
win:maximize()
end
)
-- Size window to maximum
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"return",
function()
win = hs.window.focusedWindow()
win:maximize()
end
)
-- Size window to larger "restore" size and center (same as above)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad0",
function()
win = hs.window.focusedWindow()
w = 1500
h = 930
logWindowInfo()
if hs.screen.mainScreen():name() == "LG Ultra HD" then
w = 2310
h = 1360
end
sizeAndCenterWindow(win, w, h)
end
)
-- Move window to left-center (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad1",
function()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
leftBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x1
newX = leftBoundX + globalPadX
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = rightBoundY - globalPadY - h
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
)
-- Move window to left-center (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad2",
function()
moveSouth()
end
)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"down",
function()
moveSouth()
end
)
-- Move window to bottom-right (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad3",
function()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = rightBoundX - globalPadX - w
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = rightBoundY - globalPadY - h
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
)
-- Move window to left-center (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad4",
function()
moveWest()
end
)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"left",
function()
moveWest()
end
)
-- Center window on screen
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad5",
function()
moveCenter()
end
)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"/",
function()
moveCenter()
end
)
-- Move window to right-center (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad6",
function()
moveEast()
end
)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"right",
function()
moveEast()
end
)
-- Move window to top-right (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad7",
function()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
leftBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x1
newX = leftBoundX + globalPadX
newY = globalPadY + globalOSMenuHeight
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
)
-- Move window to top-right (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad8",
function()
moveNorth()
end
)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"up",
function()
moveNorth()
end
)
-- Move window to top-right (no resizing)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"pad9",
function()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = rightBoundX - globalPadX - w
newY = globalPadY + globalOSMenuHeight
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
)
-- Move window to right half and resize (with large padding)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
".",
function()
moveAndResizeEastHalf()
end
)
-- Move window to left half and resize (with large padding)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
",",
function()
moveAndResizeWestHalf()
end
)
-- Move window to top-left quarer and resize (with large padding)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"f",
function()
logWindowInfo()
resizeQuarterWithLargePad()
moveNorthWest()
end
)
-- Move window to bottom-left quarer and resize (with large padding)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"v",
function()
logWindowInfo()
resizeQuarterWithLargePad()
moveSouthWest()
end
)
-- Move window to top-right quarer and resize (with large padding)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"g",
function()
logWindowInfo()
resizeQuarterWithLargePad()
moveNorthEast()
end
)
-- Move window to bottom-right quarer and resize (with large padding)
hs.hotkey.bind(
{"cmd", "alt", "ctrl"},
"b",
function()
logWindowInfo()
resizeQuarterWithLargePad()
moveSouthEast()
end
)
-- Rescue Windows
-- Move any windows that are off-screen onto the main screen
hs.hotkey.bind(
{"ctrl"},
"F19",
function()
logWindowInfo()
local screen = hs.screen.mainScreen()
local screenFrame = screen:fullFrame()
local wins = hs.window.visibleWindows()
local numScreens = 0
for _ in pairs(hs.screen.allScreens()) do
numScreens = numScreens + 1
end
print(numScreens)
if (hs.screen.primaryScreen() == hs.screen.mainScreen()) and (numScreens > 1) then
print("Stopping...wrong screen is focused!")
return
end
for i, win in ipairs(wins) do
local frame = win:frame()
if not frame:inside(screenFrame) then
if frame:intersect(screenFrame) then
if not frame:inside(hs.screen.primaryScreen():fullFrame()) then
print(frame)
-- it's touching the frame, but not fully inside
win:moveToScreen(screen, true, true)
end
end
end
end
end
)
function moveAndResizeEastHalf()
logWindowInfo()
-- Resize to be half of the window, with padding all around
resizeHalfWithLargePad()
-- Move east
moveEast()
end
function moveAndResizeWestHalf()
logWindowInfo()
-- Resize to be half of the window, with padding all around
resizeHalfWithLargePad()
-- Move east
moveWest()
end
function resizeHalfWithLargePad()
screenW = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
screenH = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newWidth = (screenW / 2) - globalPadXLarge
newHeight = screenH - (globalPadYLarge * 2)
-- Resize to be half of the window, with padding all around
win = hs.window.focusedWindow()
-- Only resize if it needs to be resized
if win:frame().w ~= newWidth or win:frame().h ~= newHeight then
sizeFocusedWindow(win:topLeft().x, win:topLeft().y, newWidth, newHeight)
end
end
function resizeQuarterWithLargePad()
screenW = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
screenH = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newWidth = (screenW / 2) - globalPadXLarge
newHeight = (screenH / 2) - (globalPadYLarge * 2)
-- Resize to be half of the window, with padding all around
win = hs.window.focusedWindow()
-- Only resize if it needs to be resized
if win:frame().w ~= newWidth or win:frame().h ~= newHeight then
sizeFocusedWindow(win:topLeft().x, win:topLeft().y, newWidth, newHeight)
end
end
function moveNorth()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = (rightBoundX / 2) - (w / 2)
newY = globalPadY + globalOSMenuHeight
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveSouth()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = (rightBoundX / 2) - (w / 2)
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = rightBoundY - globalPadY - h
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveEast()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = rightBoundX - globalPadX - w
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = (rightBoundY / 2) - (h / 2) + (globalOSMenuHeight / 2)
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveWest()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
leftBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x1
newX = leftBoundX + globalPadX
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = (rightBoundY / 2) - (h / 2) + (globalOSMenuHeight / 2)
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveNorthEast()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = rightBoundX - globalPadX - w
newY = globalPadY + globalOSMenuHeight
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveNorthWest()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
leftBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x1
newX = leftBoundX + globalPadX
newY = globalPadY + globalOSMenuHeight
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveSouthEast()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = rightBoundX - globalPadX - w
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = rightBoundY - globalPadY - h
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveSouthWest()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
leftBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x1
newX = leftBoundX + globalPadX
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = rightBoundY - globalPadY - h
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function moveCenter()
logWindowInfo()
win = hs.window.focusedWindow()
x = win:topLeft().x
y = win:topLeft().y
w = win:frame().w
h = win:frame().h
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = (rightBoundX / 2) - (w / 2)
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = (rightBoundY / 2) - (h / 2)
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
function sizeFocusedWindow(x, y, w, h)
rect = hs.geometry.rect(x, y, w, h)
print("sizing to rect ", rect)
hs.window.focusedWindow():setFrameWithWorkarounds(rect, 0)
end
function logWindowInfo()
print("name: ", hs.screen.mainScreen():name())
print("size: ", hs.window.focusedWindow():size())
print("topLeft: ", hs.window.focusedWindow():topLeft())
end
function sizeAndCenterWindow(win, w, h)
-- Not using centerOnScreen because it doesn't
-- position correctly with respect to the dock
-- win:centerOnScreen(nil, true)
x = win:topLeft().x
y = win:topLeft().y
rightBoundX = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).x2
newX = (rightBoundX / 2) - (w / 2)
rightBoundY = hs.screen.mainScreen():absoluteToLocal(hs.screen.mainScreen():frame()).y2
newY = (rightBoundY / 2) - (h / 2)
print("moving to ", hs.screen.mainScreen():localToAbsolute(hs.geometry.rect(newX, newY, w, h)))
-- win:setFrame(hs.screen.mainScreen():localToAbsolute(hs.geometry.rect(newX, newY, w, h)))
win:move(hs.screen.mainScreen():localToAbsolute(hs.geometry.point(newX, newY, w, h)))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment