new hammerspoon config

This commit is contained in:
Philipp Hochkamp 2022-10-16 08:33:05 +02:00
parent dbf3186cc2
commit 184b0b0e7f

View file

@ -1,3 +1,4 @@
----------------------------------------------------------------------------------------------------
-- Settings
----------------------------------------------------------------------------------------------------
@ -10,71 +11,246 @@ hs.uploadCrashData(false)
hs.window.animationDuration = 0
local log = hs.logger.new('init', 'debug')
configWatcher = hs.pathwatcher.new(hs.configdir, hs.reload)
configWatcher:start()
configWatcher = hs.pathwatcher.new(hs.configdir, hs.reload):start()
local moonlanderMode = false
local maximizeMode = true
----------------------------------------------------------------------------------------------------
-- Utilities
----------------------------------------------------------------------------------------------------
local modifier = {
cmd = "cmd",
shift = "shift",
ctrl = "ctrl",
option = "alt",
}
local modifiers = {
hyper = { modifier.cmd, modifier.shift, modifier.ctrl, modifier.option },
window = { modifier.ctrl, modifier.option },
clipboard = { modifier.ctrl, modifier.cmd }
}
local bundleID = {
activityMonitor = "com.apple.ActivityMonitor",
finder = "com.apple.finder",
firefox = "org.mozilla.firefox",
emacs = "org.gnu.emacs",
iterm = "com.googlecode.iterm2",
safari = "com.apple.Safari",
safariTechnologyPreview = "com.apple.SafariTechnologyPreview",
spotify = "com.spotify.client",
bitwarden = "com.bitwarden.desktop",
teams = "com.microsoft.teams",
timeular = "com.timeular.zei",
logseq = "com.electron.logseq"
}
local usbDevice = {
moonlander = "Moonlander Mark I"
}
local function languageIsGerman() return hs.host.locale.preferredLanguages()[1]:sub(0, 2) == "de" end
local function maximizeCurrentWindow() hs.window.focusedWindow():maximize() end
local function centerCurrentWindow() hs.window.focusedWindow():centerOnScreen() end
local function moveCurrentWindowToLeftHalf()
local win = hs.window.focusedWindow()
local screenFrame = win:screen():frame()
local newFrame = hs.geometry.rect(screenFrame.x, screenFrame.y, screenFrame.w / 2, screenFrame.h)
win:setFrame(newFrame)
end
local function moveCurrentWindowToRightHalf()
local win = hs.window.focusedWindow()
local screenFrame = win:screen():frame()
local newFrame = hs.geometry.rect(screenFrame.x + screenFrame.w / 2, screenFrame.y, screenFrame.w / 2, screenFrame.h)
win:setFrame(newFrame)
end
local function moveCurentWindowToNextScreen()
local win = hs.window.focusedWindow()
win:moveToScreen(win:screen():next())
end
local function moveMouseToWindowCenter()
local windowCenter = hs.window.frontmostWindow():frame().center
hs.mouse.absolutePosition(windowCenter)
end
local function moveMouseToUpperLeft()
local screenFrame = (hs.window.focusedWindow():screen() or hs.screen.primaryScreen()):frame()
local newPoint = hs.geometry.point(screenFrame.x + screenFrame.w / 4, screenFrame.y + screenFrame.h / 4)
hs.mouse.absolutePosition(newPoint)
end
local function moveMouseToUpperRight()
local screenFrame = (hs.window.focusedWindow():screen() or hs.screen.primaryScreen()):frame()
local newPoint = hs.geometry.point(screenFrame.x + screenFrame.w * 3 / 4, screenFrame.y + screenFrame.h / 4)
hs.mouse.absolutePosition(newPoint)
end
local function moveMouseToLowerLeft()
local screenFrame = (hs.window.focusedWindow():screen() or hs.screen.primaryScreen()):frame()
local newPoint = hs.geometry.point(screenFrame.x + screenFrame.w / 4, screenFrame.y + screenFrame.h * 3 / 4)
hs.mouse.absolutePosition(newPoint)
end
local function moveMouseToLowerRight()
local screenFrame = (hs.window.focusedWindow():screen() or hs.screen.primaryScreen()):frame()
local newPoint = hs.geometry.point(screenFrame.x + screenFrame.w * 3 / 4, screenFrame.y + screenFrame.h * 3 / 4)
hs.mouse.absolutePosition(newPoint)
end
----------------------------------------------------------------------------------------------------
-- Menu
----------------------------------------------------------------------------------------------------
local function menuItems()
return {
{
title = "Hammerspoon " .. hs.processInfo.version,
disabled = true
},
{ title = "-" },
{
title = "Moonlander Mode",
checked = moonlanderMode,
fn = function() moonlanderDetected(not moonlanderMode) end
},
{
title = "Maximize Mode",
checked = maximizeMode,
fn = function() maximizeMode = not maximizeMode end
},
{ title = "-" },
{
title = "Reload",
fn = hs.reload
},
{
title = "Console...",
fn = hs.openConsole
},
{ title = "-" },
{
title = "Quit",
fn = function() hs.application.get(hs.processInfo.processID):kill() end
}
}
end
menu = hs.menubar.new()
menu:setMenu(menuItems)
----------------------------------------------------------------------------------------------------
-- Moonlander Detection
----------------------------------------------------------------------------------------------------
function isDeviceMoonlander(device)
return device.productName == "Moonlander Mark I"
end
local moonlanderModeConfig = {
[false] = {
keyboardLayout = "Colemak DH ISO copy",
icon = hs.configdir .. "/assets/statusicon_off.tiff"
},
[true] = {
keyboardLayout = "EurKEY v1.2",
icon = hs.configdir .. "/assets/statusicon_on.tiff"
}
}
local function isDeviceMoonlander(device) return device.productName == usbDevice.moonlander end
function moonlanderDetected(connected)
if connected then
hs.keycodes.setLayout("EurKEY v1.2")
else
hs.keycodes.setLayout("Colemak DH ISO copy")
end
moonlanderMode = connected
hs.keycodes.setLayout(moonlanderModeConfig[connected].keyboardLayout)
menu:setIcon(moonlanderModeConfig[connected].icon)
end
function searchMoonlander()
local usbDevices = hs.usb.attachedDevices()
local moonlanderConnected = hs.fnutils.find(usbDevices, isDeviceMoonlander) ~= nil
moonlanderDetected(moonlanderConnected)
local function searchMoonlander()
local usbDevices = hs.usb.attachedDevices()
local moonlanderConnected = hs.fnutils.find(usbDevices, isDeviceMoonlander) ~= nil
moonlanderDetected(moonlanderConnected)
end
searchMoonlander()
usbWatcher = hs.usb.watcher.new(function(event)
if event.productName == "Moonlander Mark I" then
moonlanderDetected(event.eventType == "added")
end
end):start()
if event.productName == usbDevice.moonlander then
moonlanderDetected(event.eventType == "added")
end
end)
usbWatcher:start()
caffeinateWatcher = hs.caffeinate.watcher.new(function(event)
if event == hs.caffeinate.watcher.systemDidWake then
searchMoonlander()
end
end):start()
if event == hs.caffeinate.watcher.systemDidWake then
searchMoonlander()
end
end)
caffeinateWatcher:start()
----------------------------------------------------------------------------------------------------
-- mount ds9 via tailscale
-- Window Management
----------------------------------------------------------------------------------------------------
-- kaputti
--function mountDS9()
-- local ssid = hs.wifi.currentNetwork()
-- if ssid ~= nil and ssid ~= 'vim' then -- not at home
-- if os.execute("mount | grep //ragon@ds9._smb._tcp.local/data") == nil then -- check if mounted via mdns
-- os.execute("diskutil umount /Volumes/data") -- umount share if it exists
-- hs.osascript.applescript('mount volume "smb://ragon@ds9.ragon000.github.beta.tailscale.net/data"') -- mount share via tailscale
-- end
-- end
--end
--
--mountDS9()
--
--hs.wifi.watcher.new(function(watcher, message, interface)
-- mountDS9()
--end):start()
hs.window.filter.ignoreAlways = {
["Mail Web Content"] = true,
["Mail-Webinhalt"] = true,
["QLPreviewGenerationExtension (Finder)"] = true,
["Reeder Web Content"] = true,
["Reeder-Webinhalt"] = true,
["Safari Web Content (Cached)"] = true,
["Safari Web Content (Prewarmed)"] = true,
["Safari Web Content"] = true,
["Safari Technology Preview Web Content (Cached)"] = true,
["Safari Technology Preview Web Content (Prewarmed)"] = true,
["Safari Technology Preview Web Content"] = true,
["Safari-Webinhalt (im Cache)"] = true,
["Safari-Webinhalt (vorgeladen)"] = true,
["Safari-Webinhalt"] = true,
["Strongbox (Safari)"] = true,
}
windowFilter = hs.window.filter.new({
"App Store",
"Code",
"DataGrip",
"Firefox",
"Fork",
"Fotos",
"Google Chrome",
"Vivaldi",
"IntelliJ IDEA",
"Mail",
"Emacs",
"Microsoft Outlook",
"Microsoft Teams",
"Music",
"Musik",
"Photos",
"Postman",
"Reeder",
"Safari",
"Safari Technology Preview",
"Spotify",
"Strongbox",
"BitWarden",
"Logseq",
"Timeular",
"Tower",
})
windowFilter:subscribe({ hs.window.filter.windowCreated, hs.window.filter.windowFocused }, function(window)
if maximizeMode and window ~= nil and window:isStandard() and window:frame().h > 500 then
window:maximize()
end
end)
----------------------------------------------------------------------------------------------------
-- Scratchpad
-- Keyboard Shortcuts
----------------------------------------------------------------------------------------------------
function showHideBundleId(bundleId)
@ -87,14 +263,177 @@ function showHideBundleId(bundleId)
end
end
local hyperModifier = {"cmd", "shift", "ctrl", "alt"}
local cmdShiftModifier = {"cmd", "shift"}
hs.hotkey.bind(hyperModifier, "b", function() showHideBundleId("com.bitwarden.desktop") end)
hs.hotkey.bind(hyperModifier, "p", function() showHideBundleId("com.timeular.zei") end)
hs.hotkey.bind(hyperModifier, "l", function() showHideBundleId("com.electron.logseq") end)
hs.hotkey.bind(hyperModifier, "e", function() hs.task.new("@myEmacs@/bin/emacsclient", nil, function() return false end, {"-c"}):start() end)
hs.hotkey.bind(hyperModifier, "i", function() hs.task.new("@myEmacs@/bin/emacsclient", nil, function() return false end, {"--eval", "(emacs-everywhere)"}):start() end)
hs.hotkey.bind(modifiers.window, hs.keycodes.map.left, moveCurrentWindowToLeftHalf)
hs.hotkey.bind(modifiers.window, hs.keycodes.map.right, moveCurrentWindowToRightHalf)
hs.hotkey.bind(modifiers.window, hs.keycodes.map.down, moveCurentWindowToNextScreen)
hs.hotkey.bind(modifiers.window, hs.keycodes.map["return"], maximizeCurrentWindow)
hs.hotkey.bind(modifiers.window, "c", centerCurrentWindow)
hs.hotkey.bind(modifiers.hyper, "[", moveMouseToWindowCenter)
hs.hotkey.bind(modifiers.hyper, "m", moveMouseToUpperLeft)
hs.hotkey.bind(modifiers.hyper, "o", moveMouseToUpperRight)
hs.hotkey.bind(modifiers.hyper, hs.keycodes.map.up, moveMouseToLowerLeft)
hs.hotkey.bind(modifiers.hyper, hs.keycodes.map.down, moveMouseToLowerRight)
hs.hotkey.bind(modifiers.hyper, hs.keycodes.map.delete, function() hs.caffeinate.lockScreen() end)
hs.hotkey.bind(modifiers.hyper, "a", function() showHideBundleId(bundleID.activityMonitor) end)
hs.hotkey.bind(modifiers.hyper, "c", function() showHideBundleId(bundleID.safari) end)
hs.hotkey.bind(modifiers.hyper, "f", function() showHideBundleId(bundleID.finder) end)
hs.hotkey.bind(modifiers.hyper, "e", function() hs.task.new("@myEmacs@/bin/emacsclient", nil, function() return false end, {"-c"}):start() end)
hs.hotkey.bind(modifiers.hyper, "i", function() hs.task.new("@myEmacs@/bin/emacsclient", nil, function() return false end, {"--eval", "(emacs-everywhere)"}):start() end)
hs.hotkey.bind(modifiers.hyper, "p", function() showHideBundleId(bundleID.timeular) end)
hs.hotkey.bind(modifiers.hyper, "b", function() showHideBundleId(bundleID.bitwarden) end)
hs.hotkey.bind(modifiers.hyper, "t", function() showHideBundleId(bundleID.iterm) end)
hs.hotkey.bind({ modifier.cmd }, "\\", function()
local application = hs.application.frontmostApplication()
if application:bundleID() == bundleID.bitwarden then
application:hide()
else
hs.application.launchOrFocusByBundleID(bundleID.bitwarden)
end
end)
----------------------------------------------------------------------------------------------------
-- Tiling
-- Mouse Shortcuts
----------------------------------------------------------------------------------------------------
local function handleMouse2()
local application = hs.application.frontmostApplication()
-- Safari: Close tab
if application:bundleID() == bundleID.safari then
hs.eventtap.keyStroke({ modifier.cmd }, "w")
-- Safari Technology Preview: Close tab
elseif application:bundleID() == bundleID.safariTechnologyPreview then
hs.eventtap.keyStroke({ modifier.cmd }, "w")
-- Google Chrome: Close tab
elseif application:bundleID() == bundleID.googleChrome then
hs.eventtap.keyStroke({ modifier.cmd }, "w")
-- Firefox: Close tab
elseif application:bundleID() == bundleID.firefox then
hs.eventtap.keyStroke({ modifier.cmd }, "w")
-- Teams: End call
elseif application:bundleID() == bundleID.teams then
hs.eventtap.keyStroke({ modifier.cmd, modifier.shift }, "h")
-- Spotify: Toggle play
elseif application:bundleID() == bundleID.spotify then
hs.eventtap.keyStroke({}, "space")
end
end
local function handleMouse3()
local application = hs.application.frontmostApplication()
-- Safari: Back
if application:bundleID() == bundleID.safari then
if languageIsGerman() then
application:selectMenuItem({ "Verlauf", "Zurück" })
else
application:selectMenuItem({ "History", "Back" })
end
-- Safari Technology Preview: Back
elseif application:bundleID() == bundleID.safariTechnologyPreview then
application:selectMenuItem({ "History", "Back" })
-- Google Chrome: Back
elseif application:bundleID() == bundleID.googleChrome then
if languageIsGerman() then
application:selectMenuItem({ "Verlauf", "Zurück" })
else
application:selectMenuItem({ "History", "Back" })
end
-- Firefox: Back
elseif application:bundleID() == bundleID.firefox then
hs.eventtap.keyStroke({ modifier.cmd }, "left")
-- Teams: Toggle mute
elseif application:bundleID() == bundleID.teams then
hs.eventtap.keyStroke({ modifier.cmd, modifier.shift }, "m")
-- Spotify: Next
elseif application:bundleID() == bundleID.spotify then
hs.eventtap.keyStroke({ modifier.cmd }, "right")
-- Reeder: Open in Safari
elseif application:bundleID() == bundleID.reeder then
hs.eventtap.keyStroke({}, "b")
-- Other: Copy to clipboard
else
hs.eventtap.keyStroke({ "cmd" }, "c")
end
end
local function handleMouse4()
local application = hs.application.frontmostApplication()
-- Safari: Forward
if application:bundleID() == bundleID.safari then
if languageIsGerman() then
application:selectMenuItem({ "Verlauf", "Vorwärts" })
else
application:selectMenuItem({ "History", "Forward" })
end
-- Safari Technology Preview: Forward
elseif application:bundleID() == bundleID.safariTechnologyPreview then
application:selectMenuItem({ "History", "Forward" })
-- Google Chrome: Forward
elseif application:bundleID() == bundleID.googleChrome then
if languageIsGerman() then
application:selectMenuItem({ "Verlauf", "Vorwärts" })
else
application:selectMenuItem({ "History", "Forward" })
end
-- Firefox: Forward
elseif application:bundleID() == bundleID.firefox then
hs.eventtap.keyStroke({ modifier.cmd }, "right")
-- Teams: Toggle video
elseif application:bundleID() == bundleID.teams then
hs.eventtap.keyStroke({ modifier.cmd, modifier.shift }, "o")
-- Spotify: Previous
elseif application:bundleID() == bundleID.spotify then
hs.eventtap.keyStroke({ modifier.cmd }, "left")
-- Reeder: Mark all as read
elseif application:bundleID() == bundleID.reeder then
hs.eventtap.keyStroke({}, "a")
-- Other: Paste from clipboard
else
hs.eventtap.keyStroke({ modifier.cmd }, "v")
end
end
mouseTap = hs.eventtap.new({ hs.eventtap.event.types.otherMouseDown }, function(event)
if event:getButtonState(2) then
handleMouse2()
elseif event:getButtonState(3) then
handleMouse3()
elseif event:getButtonState(4) then
handleMouse4()
end
return true
end)
mouseTap:start()
----------------------------------------------------------------------------------------------------
-- Clipboard Manager
----------------------------------------------------------------------------------------------------
-- clipboard = require("clipboard")
-- clipboard:start()
--
-- hs.hotkey.bind(modifiers.clipboard, "v", function() clipboard:toggleClipboard() end)
-- hs.hotkey.bind(modifiers.clipboard, hs.keycodes.map.delete, function() clipboard:clearAll() end)