Last active
May 18, 2020 19:22
-
-
Save jakebathman/1e1491283de47cb10fbec92a969be061 to your computer and use it in GitHub Desktop.
Hammerspoon config
This file contains 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
-- 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