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 -- Settings
---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
@ -10,28 +11,167 @@ hs.uploadCrashData(false)
hs.window.animationDuration = 0 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 -- Moonlander Detection
---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
function isDeviceMoonlander(device) local moonlanderModeConfig = {
return device.productName == "Moonlander Mark I" [false] = {
end 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) function moonlanderDetected(connected)
if connected then moonlanderMode = connected
hs.keycodes.setLayout("EurKEY v1.2") hs.keycodes.setLayout(moonlanderModeConfig[connected].keyboardLayout)
else menu:setIcon(moonlanderModeConfig[connected].icon)
hs.keycodes.setLayout("Colemak DH ISO copy")
end
end end
function searchMoonlander() local function searchMoonlander()
local usbDevices = hs.usb.attachedDevices() local usbDevices = hs.usb.attachedDevices()
local moonlanderConnected = hs.fnutils.find(usbDevices, isDeviceMoonlander) ~= nil local moonlanderConnected = hs.fnutils.find(usbDevices, isDeviceMoonlander) ~= nil
@ -41,40 +181,76 @@ end
searchMoonlander() searchMoonlander()
usbWatcher = hs.usb.watcher.new(function(event) usbWatcher = hs.usb.watcher.new(function(event)
if event.productName == "Moonlander Mark I" then if event.productName == usbDevice.moonlander then
moonlanderDetected(event.eventType == "added") moonlanderDetected(event.eventType == "added")
end end
end):start() end)
usbWatcher:start()
caffeinateWatcher = hs.caffeinate.watcher.new(function(event) caffeinateWatcher = hs.caffeinate.watcher.new(function(event)
if event == hs.caffeinate.watcher.systemDidWake then if event == hs.caffeinate.watcher.systemDidWake then
searchMoonlander() searchMoonlander()
end end
end):start() end)
caffeinateWatcher:start()
---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
-- mount ds9 via tailscale -- Window Management
---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
-- kaputti
--function mountDS9() hs.window.filter.ignoreAlways = {
-- local ssid = hs.wifi.currentNetwork() ["Mail Web Content"] = true,
-- if ssid ~= nil and ssid ~= 'vim' then -- not at home ["Mail-Webinhalt"] = true,
-- if os.execute("mount | grep //ragon@ds9._smb._tcp.local/data") == nil then -- check if mounted via mdns ["QLPreviewGenerationExtension (Finder)"] = true,
-- os.execute("diskutil umount /Volumes/data") -- umount share if it exists ["Reeder Web Content"] = true,
-- hs.osascript.applescript('mount volume "smb://ragon@ds9.ragon000.github.beta.tailscale.net/data"') -- mount share via tailscale ["Reeder-Webinhalt"] = true,
-- end ["Safari Web Content (Cached)"] = true,
-- end ["Safari Web Content (Prewarmed)"] = true,
--end ["Safari Web Content"] = true,
-- ["Safari Technology Preview Web Content (Cached)"] = true,
--mountDS9() ["Safari Technology Preview Web Content (Prewarmed)"] = true,
-- ["Safari Technology Preview Web Content"] = true,
--hs.wifi.watcher.new(function(watcher, message, interface) ["Safari-Webinhalt (im Cache)"] = true,
-- mountDS9() ["Safari-Webinhalt (vorgeladen)"] = true,
--end):start() ["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) function showHideBundleId(bundleId)
@ -87,14 +263,177 @@ function showHideBundleId(bundleId)
end end
end end
local hyperModifier = {"cmd", "shift", "ctrl", "alt"} hs.hotkey.bind(modifiers.window, hs.keycodes.map.left, moveCurrentWindowToLeftHalf)
local cmdShiftModifier = {"cmd", "shift"} hs.hotkey.bind(modifiers.window, hs.keycodes.map.right, moveCurrentWindowToRightHalf)
hs.hotkey.bind(hyperModifier, "b", function() showHideBundleId("com.bitwarden.desktop") end) hs.hotkey.bind(modifiers.window, hs.keycodes.map.down, moveCurentWindowToNextScreen)
hs.hotkey.bind(hyperModifier, "p", function() showHideBundleId("com.timeular.zei") end) hs.hotkey.bind(modifiers.window, hs.keycodes.map["return"], maximizeCurrentWindow)
hs.hotkey.bind(hyperModifier, "l", function() showHideBundleId("com.electron.logseq") end) hs.hotkey.bind(modifiers.window, "c", centerCurrentWindow)
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.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)