new hammerspoon config
This commit is contained in:
parent
dbf3186cc2
commit
184b0b0e7f
1 changed files with 389 additions and 50 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue