this repo has no description
1local appBindings = {
2 ["1"] = "Slack",
3 ["2"] = "Discord",
4 ["3"] = "Messages",
5 ["4"] = "Mail",
6 ["7"] = "Spotify",
7 ["8"] = "Firefox",
8 ["9"] = "Ghostty",
9 ["0"] = "Obsidian",
10}
11
12for key, app in pairs(appBindings) do
13 hs.hotkey.bind({ "cmd", "ctrl" }, key, function()
14 hs.application.launchOrFocus(app)
15 end)
16end
17
18hs.hotkey.bind({ "cmd", "ctrl" }, "r", function()
19 hs.reload()
20end)
21
22-- Window management
23hs.window.animationDuration = 0
24
25local function moveWindow(fn)
26 local win = hs.window.focusedWindow()
27 if not win then return end
28 local screen = win:screen():frame()
29 fn(win, screen)
30end
31
32local windowBindings = {
33 h = function(w, s) w:setFrame({ x = s.x, y = s.y, w = s.w / 2, h = s.h }) end,
34 l = function(w, s) w:setFrame({ x = s.x + s.w / 2, y = s.y, w = s.w / 2, h = s.h }) end,
35 Return = function(w, s) w:setFrame(s) end,
36 u = function(w, s) w:setFrame({ x = s.x, y = s.y, w = s.w / 2, h = s.h / 2 }) end,
37 i = function(w, s) w:setFrame({ x = s.x + s.w / 2, y = s.y, w = s.w / 2, h = s.h / 2 }) end,
38 j = function(w, s) w:setFrame({ x = s.x, y = s.y + s.h / 2, w = s.w / 2, h = s.h / 2 }) end,
39 k = function(w, s) w:setFrame({ x = s.x + s.w / 2, y = s.y + s.h / 2, w = s.w / 2, h = s.h / 2 }) end,
40}
41
42for key, fn in pairs(windowBindings) do
43 hs.hotkey.bind({ "ctrl", "alt" }, key, function() moveWindow(fn) end)
44end
45
46-- Cycling window positions (thirds and 2/3rds)
47local cycleState = { g = 0, e = 0 }
48
49-- g: 1/3 width, cycles right → middle → left
50hs.hotkey.bind({ "ctrl", "alt" }, "g", function()
51 local win = hs.window.focusedWindow()
52 if not win then return end
53 local s = win:screen():frame()
54 local positions = {
55 { x = s.x + s.w * 2 / 3, y = s.y, w = s.w / 3, h = s.h },
56 { x = s.x + s.w / 3, y = s.y, w = s.w / 3, h = s.h },
57 { x = s.x, y = s.y, w = s.w / 3, h = s.h },
58 }
59 cycleState.g = (cycleState.g % #positions) + 1
60 win:setFrame(positions[cycleState.g])
61end)
62
63-- e: 2/3 width, cycles left → right
64hs.hotkey.bind({ "ctrl", "alt" }, "e", function()
65 local win = hs.window.focusedWindow()
66 if not win then return end
67 local s = win:screen():frame()
68 local positions = {
69 { x = s.x, y = s.y, w = s.w * 2 / 3, h = s.h },
70 { x = s.x + s.w / 3, y = s.y, w = s.w * 2 / 3, h = s.h },
71 }
72 cycleState.e = (cycleState.e % #positions) + 1
73 win:setFrame(positions[cycleState.e])
74end)
75
76-- Volume control
77local volumeStep = 5
78local volumeMods = { "ctrl", "shift", "cmd" }
79local volumeAlertId = nil
80
81local function showVolumeAlert(vol)
82 if volumeAlertId then hs.alert.closeSpecific(volumeAlertId) end
83 volumeAlertId = hs.alert.show("Volume: " .. math.floor(vol) .. "%")
84end
85
86hs.hotkey.bind(volumeMods, "=", function()
87 local device = hs.audiodevice.defaultOutputDevice()
88 device:setVolume(math.min(100, device:volume() + volumeStep))
89 showVolumeAlert(device:volume())
90end)
91
92hs.hotkey.bind(volumeMods, "-", function()
93 local device = hs.audiodevice.defaultOutputDevice()
94 device:setVolume(math.max(0, device:volume() - volumeStep))
95 showVolumeAlert(device:volume())
96end)
97
98hs.alert.show("Config loaded")