Files
dots/gui/.config/hypr/dots_binds.lua
T

264 lines
15 KiB
Lua

-- gui package — the dots keybinds, split out of ./hyprland.lua. Required there
-- after the app/start overrides (the launchers read hc.app.*) and before
-- ./host.lua.
local hc = hyde.config
local MOD = hc.modifiers.main
local home = os.getenv("HOME") or ""
-- ── Keybinds ─────────────────────────────────────────────────────────────────
-- Policy: preserve what the dots keybindings.conf did live until the port —
-- where a dots bind and a HyDE bind share a combo, the dots action wins and
-- the displaced HyDE action is noted. Binds identical in both are not
-- repeated here (volume/media/brightness, screenshots, Super+Q/W,
-- rofi menus, Super+L lock, Super+Shift+F pin, Super+S scratchpad family,
-- Super+Z/X + mouse drag/resize, Super+J togglesplit, Super+T/E/B via the
-- app.* overrides in hyprland.lua, Super+Alt+G gamemode, Ctrl+Shift+Esc
-- sysmon).
-- Removes every live bind on a combo regardless of flags. hl.bind's dedup only
-- replaces a bind whose flags match exactly; HyDE binds with locked/transparent/
-- repeating flags would otherwise stay live next to ours and double-fire.
local function unbind_all(combo)
-- _active/canonicalize are HyDE-private; if an update renames them, degrade
-- to "the displaced HyDE binds double-fire" instead of erroring here and
-- silently dropping every bind registered below this line.
if not (hyde.binds and hyde.binds._active and hyde.binds.canonicalize) then
return
end
local canon = hyde.binds.canonicalize(combo)
for id, registered in pairs(hyde.binds._active) do
if id:sub(1, #canon + 1) == canon .. "|" then
hl.unbind(registered)
hyde.binds._active[id] = nil
end
end
end
local _F
-- Launchers (dots-only combos, no conflict)
_F = { description = "[Launcher|Apps] work session (kitty c2)" }
hl.bind(MOD .. " + CTRL + I", hl.dsp.exec_cmd("kitty --session " .. home .. "/.config/kitty/c2.conf"), _F)
_F = { description = "[Launcher|Apps] work session (kitty runners)" }
hl.bind(MOD .. " + CTRL + O", hl.dsp.exec_cmd("kitty --session " .. home .. "/.config/kitty/runners.conf"), _F)
_F = { description = "[Launcher|Apps] pyradio (kitty music)" }
hl.bind(MOD .. " + R", hl.dsp.exec_cmd("kitty --session " .. home .. "/.config/kitty/music.conf"), _F)
_F = { description = "[Launcher|Apps] ferdium" }
hl.bind(MOD .. " + Y", hl.dsp.exec_cmd("ferdium"), _F)
_F = { description = "[Launcher|Apps] betterbird" }
hl.bind(MOD .. " + M", hl.dsp.exec_cmd("betterbird"), _F)
_F = { description = "[Launcher|Apps] freetube" }
hl.bind(MOD .. " + F", hl.dsp.exec_cmd("freetube"), _F)
_F = { description = "[Launcher|Apps] web browser (librewolf)" }
hl.bind(MOD .. " + SHIFT + B", hl.dsp.exec_cmd("librewolf"), _F)
_F = { description = "[Launcher|Apps] terminal emulator (st)" }
hl.bind(MOD .. " + CTRL + T", hl.dsp.exec_cmd("st"), _F)
_F = { description = "[Launcher|Apps] terminal emulator" }
hl.bind("CTRL + ALT + T", hl.dsp.exec_cmd(hc.app.terminal), _F)
-- Rebound fresh so the hc.app.* overrides actually apply: HyDE's binds
-- evaluated _apps.browser/_apps.explorer when key_binds.lua ran, baking in the
-- hyde-shell open wrappers.
_F = { description = "[Launcher|Apps] web browser" }
hl.bind(MOD .. " + B", hl.dsp.exec_cmd("zen-browser"), _F)
_F = { description = "[Launcher|Apps] file explorer" }
hl.bind(MOD .. " + E", hl.dsp.exec_cmd("dolphin"), _F)
-- Conflict resolutions (dots action wins; displaced HyDE action noted)
_F = { description = "[Launcher|Apps] web browser (firefox)" } -- displaces HyDE: hide waybar
hl.bind(MOD .. " + CTRL + B", hl.dsp.exec_cmd("firefox"), _F)
_F = { description = "[Launcher|Apps] xmpp (gajim)" } -- displaces HyDE: toggle group (dots keeps it on Super+Shift+G)
hl.bind(MOD .. " + G", hl.dsp.exec_cmd("gajim"), _F)
_F = { description = "[Window Management] toggle group" } -- displaces HyDE: game launcher
hl.bind(MOD .. " + SHIFT + G", hl.dsp.group.toggle(), _F)
_F = { description = "[Launcher|Apps] terminal emulator (alacritty)" } -- displaces HyDE: theme select menu
hl.bind(MOD .. " + SHIFT + T", hl.dsp.exec_cmd("alacritty"), _F)
-- Through `wbar`, never killall: under supervision a killed waybar is back in
-- seconds, and a raw relaunch next to it means two bars.
_F = { description = "[Theming and Wallpaper] reload hyprland + waybar" } -- displaces HyDE: wallbash mode menu
hl.bind(MOD .. " + SHIFT + R", hl.dsp.exec_cmd("hyprctl reload; " .. home .. "/.local/bin/wbar restart"), _F)
_F = { description = "[Launcher|Apps] neovim" } -- displaces HyDE: code editor
hl.bind(MOD .. " + C", hl.dsp.exec_cmd("kitty nvim"), _F)
-- Super+K keepassxc — HyDE's keyboard-layout switch carries locked=true, so a
-- plain rebind would leave both live (flags are part of a bind's identity).
unbind_all(MOD .. " + K") -- displaces HyDE: keyboard layout switch (locked)
_F = { description = "[Launcher|Apps] password manager" }
hl.bind(MOD .. " + K", hl.dsp.exec_cmd("keepassxc"), _F)
-- Alt+Tab focus-down — HyDE ships a 4-bind alt-tab switcher (transparent/
-- release flags); remove the whole cluster, half a switcher is worse than none.
unbind_all("ALT + TAB") -- displaces HyDE: alt-tab switcher (cycle next)
unbind_all("ALT + SHIFT + TAB")
unbind_all("ALT + ALT_L")
unbind_all("ALT + ALT_R")
_F = { description = "[Window Management|Change focus] focus down" }
hl.bind("ALT + TAB", hl.dsp.focus({ direction = "down" }), _F)
-- Waybar toggle (custom layout; the legacy Ctrl+Alt+W). systemctl stop is a
-- deliberate stop, so Restart=always does not undo it.
_F = { description = "[Window Management] toggle waybar" }
hl.bind("CTRL + ALT + W", hl.dsp.exec_cmd(home .. "/.local/bin/wbar toggle"), _F)
-- Fullscreen on Alt+Return (Shift+F11 stays HyDE's cycle-fullscreen).
-- Native dispatcher, not exec "hyprctl dispatch fullscreen": in Lua mode that
-- CLI arg is evaluated as hl.dispatch(fullscreen) — a nil global, dead bind.
_F = { description = "[Window Management] toggle fullscreen" }
hl.bind("ALT + RETURN", hl.dsp.window.fullscreen(), _F)
-- No Super+Delete: HyDE's exit() ends the session on the spot, no confirm, and
-- the combo is one slipped finger from Super+Alt+Delete. Ctrl+Alt+Delete (the
-- logout menu) stays the way out.
unbind_all(MOD .. " + Delete") -- displaces HyDE: exit hyprland session
-- ── Focus (arrows + hjkl) ────────────────────────────────────────────────────
-- Super+Ctrl+Up/Down: movefocus — displaces HyDE: nearest-empty (Down), which
-- moves to Super+Ctrl+E below. Super+Ctrl+Left/Right move the window to r±1
-- (Workspaces below); r±1 nav is on Super+Left/Right and Super+Ctrl+Shift.
for dir, key in pairs({ left = "LEFT", right = "RIGHT", up = "UP", down = "DOWN" }) do
_F = { description = "[Window Management|Change focus] focus " .. dir }
if key == "UP" or key == "DOWN" then
hl.bind(MOD .. " + CTRL + " .. key, hl.dsp.focus({ direction = dir }), _F)
end
hl.bind("ALT + CTRL + " .. key, hl.dsp.focus({ direction = dir }), _F)
end
for dir, key in pairs({ left = "H", right = "L", up = "K", down = "J" }) do
_F = { description = "[Window Management|Change focus] focus " .. dir }
hl.bind("ALT + CTRL + " .. key, hl.dsp.focus({ direction = dir }), _F)
end
-- Super+Ctrl+H/L carried a deliberate double action in the hyprlang chain:
-- changegroupactive (a no-op outside a group) AND movefocus fired together.
-- Lua dedup would collapse the pair, so one function does both.
-- (Replaces HyDE's plain group-nav binds on the same combos.) Unlike the
-- arrows, they do not move the window to r±1 — that is Super+Ctrl+Alt+H/L.
_F = { description = "[Window Management|Change focus] group prev + focus left" }
hl.bind(MOD .. " + CTRL + H", function()
hl.dispatch(hl.dsp.group.prev())
hl.dispatch(hl.dsp.focus({ direction = "left" }))
end, _F)
_F = { description = "[Window Management|Change focus] group next + focus right" }
hl.bind(MOD .. " + CTRL + L", function()
hl.dispatch(hl.dsp.group.next())
hl.dispatch(hl.dsp.focus({ direction = "right" }))
end, _F)
_F = { description = "[Window Management|Change focus] focus up" }
hl.bind(MOD .. " + CTRL + K", hl.dsp.focus({ direction = "up" }), _F)
_F = { description = "[Window Management|Change focus] focus down" }
hl.bind(MOD .. " + CTRL + J", hl.dsp.focus({ direction = "down" }), _F)
-- ── Resize (add hjkl to HyDE's arrow set) ────────────────────────────────────
-- HyDE puts a flagless calculator menu on Super+Shift+K; our repeating resize
-- would double-fire next to it (flag mismatch), so drop the calculator.
unbind_all(MOD .. " + SHIFT + K") -- displaces HyDE: calculator menu
for _, m in ipairs({ { "L", 30, 0 }, { "H", -30, 0 }, { "K", 0, -30 }, { "J", 0, 30 } }) do
_F = { description = "[Window Management|Resize Active Window] resize window", repeating = true }
hl.bind(MOD .. " + SHIFT + " .. m[1], hl.dsp.window.resize({ x = m[2], y = m[3], relative = true }), _F)
end
-- ── Move active window (Super+Alt, float-aware: moveactive / swapwindow) ─────
-- Displaces HyDE: wallpaper next/prev (Alt+Right/Left) and waybar layout
-- next/prev (Alt+Up/Down); wallpaper moves to Super+Alt+Ctrl+Shift below,
-- as in the dots chain. HyDE's binds carry no flags but ours are repeating,
-- so an explicit unbind is needed to keep them from double-firing.
unbind_all(MOD .. " + ALT + RIGHT")
unbind_all(MOD .. " + ALT + LEFT")
unbind_all(MOD .. " + ALT + UP")
unbind_all(MOD .. " + ALT + DOWN")
local function dots_move_window(dir, pix)
local lut = { l = { -1, 0 }, r = { 1, 0 }, u = { 0, -1 }, d = { 0, 1 } }
local m = lut[dir]
return function()
local w = hl.get_active_window()
if w and w.floating then
hl.dispatch(hl.dsp.window.move({ x = m[1] * pix, y = m[2] * pix, relative = true }))
else
local names = { l = "left", r = "right", u = "up", d = "down" }
hl.dispatch(hl.dsp.window.swap({ direction = names[dir] }))
end
end
end
for _, m in ipairs({
{ "LEFT", "l" },
{ "RIGHT", "r" },
{ "UP", "u" },
{ "DOWN", "d" },
{ "H", "l" },
{ "L", "r" },
{ "K", "u" },
{ "J", "d" },
}) do
_F = { description = "[Window Management|Move active window] move " .. m[2], repeating = true }
hl.bind(MOD .. " + ALT + " .. m[1], dots_move_window(m[2], 30), _F)
end
-- ── Wallpaper (moved off Super+Alt by the dots chain) ────────────────────────
_F = { description = "[Theming and Wallpaper] next global wallpaper" }
hl.bind(MOD .. " + ALT + CTRL + SHIFT + RIGHT", hl.dsp.exec_cmd(hyde.sh.wallpaper("--next")), _F)
_F = { description = "[Theming and Wallpaper] previous global wallpaper" }
hl.bind(MOD .. " + ALT + CTRL + SHIFT + LEFT", hl.dsp.exec_cmd(hyde.sh.wallpaper("--prev")), _F)
-- ── Workspaces ───────────────────────────────────────────────────────────────
-- r~N = Nth workspace of the FOCUSED monitor — load-bearing on the 3-monitor
-- workspace sets (1-10 / 11-20 / 21-30 pinned per monitor in host.lua).
-- HyDE's own binds pass "r+1"/"empty" strings the same way; r~N is the one
-- thing to verify first in the live session.
for i = 1, 10 do
local key = (i == 10) and 0 or i
_F = { description = "[Workspaces|Navigation] navigate to workspace " .. i .. " (monitor-relative)" }
hl.bind(MOD .. " + " .. key, hl.dsp.focus({ workspace = "r~" .. i }), _F) -- displaces HyDE: absolute workspace N
_F = { description = "[Workspaces|Move window to workspace] move to workspace " .. i .. " (monitor-relative)" }
hl.bind(MOD .. " + CTRL + " .. key, hl.dsp.window.move({ workspace = "r~" .. i }), _F)
_F = { description = "[Workspaces|Move window silently] move to workspace " .. i .. " (monitor-relative)" }
hl.bind(MOD .. " + ALT + " .. key, hl.dsp.window.move({ workspace = "r~" .. i, follow = false }), _F) -- displaces HyDE: absolute silent move
end
-- Relative workspace nav on Super+Ctrl+Shift (dots), displacing HyDE's
-- move-window-in-workspace family there (repeating flags -> explicit unbind;
-- dots does window movement on Super+Alt instead).
unbind_all(MOD .. " + SHIFT + CTRL + LEFT")
unbind_all(MOD .. " + SHIFT + CTRL + RIGHT")
unbind_all(MOD .. " + SHIFT + CTRL + UP")
unbind_all(MOD .. " + SHIFT + CTRL + DOWN")
_F = { description = "[Workspaces|Navigation|Relative workspace] change active workspace forwards" }
hl.bind(MOD .. " + CTRL + SHIFT + RIGHT", hl.dsp.focus({ workspace = "r+1" }), _F)
hl.bind(MOD .. " + CTRL + SHIFT + L", hl.dsp.focus({ workspace = "r+1" }), _F)
_F = { description = "[Workspaces|Navigation|Relative workspace] change active workspace backwards" }
hl.bind(MOD .. " + CTRL + SHIFT + LEFT", hl.dsp.focus({ workspace = "r-1" }), _F)
hl.bind(MOD .. " + CTRL + SHIFT + H", hl.dsp.focus({ workspace = "r-1" }), _F)
_F = { description = "[Workspaces|Navigation|Relative workspace] change active workspace forwards" }
hl.bind(MOD .. " + RIGHT", hl.dsp.focus({ workspace = "r+1" }), _F)
_F = { description = "[Workspaces|Navigation|Relative workspace] change active workspace backwards" }
hl.bind(MOD .. " + LEFT", hl.dsp.focus({ workspace = "r-1" }), _F)
_F = { description = "[Workspaces|Move window to workspace|Relative workspace] move focused window to next workspace" }
hl.bind(MOD .. " + CTRL + RIGHT", hl.dsp.window.move({ workspace = "r+1" }), _F) -- displaces HyDE: workspace r+1
_F = {
description = "[Workspaces|Move window to workspace|Relative workspace] move focused window to previous workspace",
}
hl.bind(MOD .. " + CTRL + LEFT", hl.dsp.window.move({ workspace = "r-1" }), _F) -- displaces HyDE: workspace r-1
-- E for "empty" — Super+Ctrl+Down is taken by movefocus above
_F = { description = "[Workspaces|Navigation] navigate to the nearest empty workspace" }
hl.bind(MOD .. " + CTRL + E", hl.dsp.focus({ workspace = "empty" }), _F)
-- Move window to relative workspace: HyDE ships the arrow pair; add hjkl.
_F = { description = "[Workspaces|Move window to workspace|Relative workspace] move focused window to next workspace" }
hl.bind(MOD .. " + CTRL + ALT + L", hl.dsp.window.move({ workspace = "r+1" }), _F)
_F = {
description = "[Workspaces|Move window to workspace|Relative workspace] move focused window to previous workspace",
}
hl.bind(MOD .. " + CTRL + ALT + H", hl.dsp.window.move({ workspace = "r-1" }), _F)
-- ── Hardware controls ────────────────────────────────────────────────────────
-- HyDE binds bare F10/F11/F12 to mute / volume down / volume up (key_binds.lua,
-- locked + repeating -- a plain rebind would leave both live). That is a laptop
-- F-row assumption: the Cantor has no F-row, so F1-F12 only ever arrive from its
-- Vial layer 5 and have to reach applications instead of the mixer. The
-- XF86Audio* binds below them keep the media keys working, so nothing is lost,
-- and Shift+F11 (cycle fullscreen) canonicalizes separately and survives.
unbind_all("F10") -- displaces HyDE: un/mute output
unbind_all("F11") -- displaces HyDE: decrease volume
unbind_all("F12") -- displaces HyDE: increase volume