Created
October 13, 2017 18:43
-
-
Save philc/ed70ae4e60062c2d494fae97d5da43ce to your computer and use it in GitHub Desktop.
My hammerspoon config
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
----------------------------------------------------------------------- | |
-- References: | |
-- https://github.com/apesic/dotfiles/blob/master/.hammerspoon/init.lua | |
-- https://learnxinyminutes.com/docs/lua/ | |
----------------------------------------------------------------------- | |
---------------- | |
-- Configuration | |
---------------- | |
-- Make the alerts look nicer. | |
hs.alert.defaultStyle.strokeColor = {white = 1, alpha = 0} | |
hs.alert.defaultStyle.fillColor = {white = 0.05, alpha = 0.75} | |
hs.alert.defaultStyle.radius = 10 | |
-- Disable the slow default window animations. | |
hs.window.animationDuration = 0 | |
-- Modifier sets that I use | |
local mash_app = {"cmd", "ctrl"} | |
--------------------- | |
-- Window positioning | |
--------------------- | |
function moveLeftHalf() | |
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 / 2 | |
f.h = max.h | |
win:setFrame(f) | |
end | |
function moveRightHalf() | |
local win = hs.window.focusedWindow() | |
local f = win:frame() | |
local screen = win:screen() | |
local max = screen:frame() | |
f.x = max.x + (max.w / 2) | |
f.y = max.y | |
f.w = max.w / 2 | |
f.h = max.h | |
win:setFrame(f) | |
end | |
function maximize() | |
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) | |
end | |
function moveToScreen(screenPos) | |
window = hs.window.focusedWindow() | |
screen = hs.screen.find({x=screenPos, y=0}) | |
window:moveToScreen(screen) | |
end | |
hs.hotkey.bind(mash_app, "1", function() | |
moveToScreen(0) | |
moveLeftHalf() | |
end) | |
hs.hotkey.bind(mash_app, "2", function() | |
moveToScreen(0) | |
moveRightHalf() | |
end) | |
hs.hotkey.bind(mash_app, "3", function() | |
moveToScreen(1) | |
moveLeftHalf() | |
end) | |
hs.hotkey.bind(mash_app, "4", function() | |
moveToScreen(1) | |
moveRightHalf() | |
end) | |
hs.hotkey.bind(mash_app, "M", maximize) | |
------------------------------------- | |
-- Application focusing shortcuts | |
------------------------------------- | |
-- Like hs.application.launchOrFocus, except that it works for apps created using Epichrome. | |
-- I'm not sure why this implementation has different behavior than hs.application.launchOrFocus. | |
-- Reference: https://github.com/Hammerspoon/hammerspoon/issues/304 | |
function myLaunchOrFocus(appName) | |
local app = hs.appfinder.appFromName(appName) | |
if app == nil then | |
hs.application.launchOrFocus(appName) | |
else | |
windows = app:allWindows() | |
if windows[1] then | |
windows[1]:focus() | |
end | |
end | |
end | |
hs.hotkey.bind(mash_app, 'L', function() myLaunchOrFocus('Google Chrome') end) | |
hs.hotkey.bind(mash_app, 'J', function() myLaunchOrFocus('Emacs') end) | |
hs.hotkey.bind(mash_app, 'K', function() myLaunchOrFocus('/Applications/iTerm.app') end) | |
hs.hotkey.bind(mash_app, 'U', function() myLaunchOrFocus('Gmail') end) | |
hs.hotkey.bind(mash_app, 'Y', function() myLaunchOrFocus('GmailPersonal') end) | |
hs.hotkey.bind(mash_app, ',', function() myLaunchOrFocus('Slack') end) | |
hs.hotkey.bind(mash_app, 'N', function() myLaunchOrFocus('Terminal') end) | |
hs.hotkey.bind({"cmd", "ctrl", "shift"}, 'N', function () myLaunchOrFocus('Spotify') end) | |
hs.hotkey.bind(mash_app, 'O', function() myLaunchOrFocus('Org') end) | |
hs.hotkey.bind(mash_app, 'C', function() myLaunchOrFocus('GCalendar') end) | |
------------------------------------- | |
-- Window layouts | |
------------------------------------- | |
local leftScreen = hs.screen{x=0,y=0} | |
local centerScreen = hs.screen{x=1,y=0} | |
local rightScreen = hs.screen{x=2,y=0} | |
local threeScreenLayout = { | |
{"Emacs", nil, centerScreen, hs.layout.maximized, nil, nil}, | |
{"Google Chrome", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"iTerm2", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"Gmail", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"GmailPersonal", nil, leftScreen, hs.layout.right50, nil, nil}, | |
{"GCalendar", nil, centerScreen, hs.layout.left50, nil, nil}, | |
{"Slack", nil, leftScreen, hs.layout.right50, nil, nil}, | |
{"MacVim", nil, leftScreen, hs.layout.right50, nil, nil}, | |
{"Org", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Xcode", nil, centerScreen, hs.layout.right50, nil, nil}, | |
{"Finder", nil, centerScreen, hs.layout.left50, nil, nil}, | |
{"Preview", nil, centerScreen, hs.layout.left50, nil, nil}, | |
{"OmniGraffle 6", nil, centerScreen, hs.layout.maximized, nil, nil}, | |
{"Terminal", nil, centerScreen, hs.layout.left50, nil, nil}, | |
{"Spotify", nil, centerScreen, hs.layout.left50, nil, nil}, | |
{"PowerPoint", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Calendar", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"System Preferences", nil, leftScreen, hs.layout.left50, nil, nil} | |
} | |
local twoScreenLayout = { | |
{"Emacs", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"Google Chrome", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"iTerm2", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"Gmail", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"GmailPersonal", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"GCalendar", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Slack", nil, leftScreen, hs.layout.right50, nil, nil}, | |
{"MacVim", nil, leftScreen, hs.layout.right50, nil, nil}, | |
{"Org", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Xcode", nil, leftScreen, hs.layout.right50, nil, nil}, | |
{"Finder", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Preview", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"OmniGraffle 6", nil, leftScreen, hs.layout.maximized, nil, nil}, | |
{"Terminal", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Spotify", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"PowerPoint", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"Calendar", nil, leftScreen, hs.layout.left50, nil, nil}, | |
{"System Preferences", nil, leftScreen, hs.layout.left50, nil, nil} | |
} | |
function switchLayout() | |
local numScreens = #hs.screen.allScreens() | |
local layout = {} | |
if numScreens == 1 then | |
layout = twoScreenLayout | |
elseif numScreens == 2 then | |
layout = twoScreenLayout | |
elseif numScreens == 3 then | |
layout = threeScreenLayout | |
end | |
hs.layout.apply(layout) | |
end | |
hs.hotkey.bind(mash_app, "'", function() | |
switchLayout() | |
end) | |
------------------- | |
-- Other shortcuts | |
------------------- | |
-- Lock the screen. This may also be possible with hs.caffeinate.lockScreen. | |
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "l", function() | |
os.execute("/Users/phil/scripts/macos/lock_screen.sh") | |
end) | |
-- Lock the screen. This may also be possible with hs.caffeinate.lockScreen. | |
hs.hotkey.bind(mash_app, "9", function() | |
os.execute("/Users/phil/scripts/macos/lock_screen.sh") | |
end) | |
function getVolumeIncrement() | |
local volume = hs.audiodevice.current().volume | |
-- When the volume gets near zero, change it in smaller increments. Otherwise even the first increment | |
-- above zero may be too loud. | |
-- NOTE(phil): I noticed that using a decimal smaller than 0.4 will sometimes result in the volume remaining | |
-- unchanged after calling setVolume, as if OSX only lets you change the volume by large increments. | |
if volume < 2 then return 0.4 else return 2 end | |
end | |
hs.hotkey.bind(mash_app, "9", function() | |
hs.audiodevice.defaultOutputDevice():setVolume(hs.audiodevice.current().volume - getVolumeIncrement()) | |
end) | |
hs.hotkey.bind(mash_app, "0", function() | |
hs.audiodevice.defaultOutputDevice():setVolume(hs.audiodevice.current().volume + getVolumeIncrement()) | |
end) | |
-- Show date time and battery | |
hs.hotkey.bind(mash_app, 'T', function() | |
local seconds = 3 | |
local message = os.date("%I:%M%p") .. "\n" .. os.date("%a %b %d") .. "\nBattery: " .. | |
hs.battery.percentage() .. "%" | |
hs.alert.show(message, seconds) | |
end) | |
-- Shortcut to reload this hammerspoon config | |
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "R", function() hs.reload() end) | |
hs.alert.show("Config loaded") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
My hammerspoon config is now checked in here