Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

### Fixed
- Waybar `hyprland/workspaces` module adapted to use lua dispatchers
- Hyprland: `Super + Ctrl + arrows` no longer changes the group and the workspace at the same time.
Group navigation stays on `Super + Alt + arrows`
- Hyprland: the right Control key no longer hides Waybar on its own. Hiding moved to `Super + Ctrl + B`
- Hyprland: workspaces 11-20 on the numpad respond again

## v26.7.4 | 4th Week of July 2026 Release

Expand Down
57 changes: 53 additions & 4 deletions Configs/.local/share/hypr/lua/hyde/binds.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,48 @@ local function normalize(keycombo)
return trim(keycombo:gsub("%s*%+%s*", " + "))
end

-- Modifier spellings Hyprland treats as the same bit.
local modifier_aliases = {
CONTROL = "CTRL",
WIN = "SUPER",
LOGO = "SUPER",
MOD1 = "ALT",
MOD4 = "SUPER"
}

-- Reduces a combo to the form Hyprland actually matches on: modifiers are a
-- set, so spelling, order and case carry no meaning. "SUPER + CTRL + Left"
-- and "SUPER + CONTROL + LEFT" both become "CTRL + SUPER + LEFT", which is
-- what makes them collide at runtime.
local function canonicalize(keycombo)
local normalized = normalize(keycombo)
if normalized == "" then
return ""
end

local tokens = {}
for token in normalized:gmatch("[^+]+") do
tokens[#tokens + 1] = trim(token)
end

local key = table.remove(tokens) or ""

local modifiers = {}
local seen = {}
for _, token in ipairs(tokens) do
local upper = token:upper()
local modifier = modifier_aliases[upper] or upper
if not seen[modifier] then
seen[modifier] = true
modifiers[#modifiers + 1] = modifier
end
end
table.sort(modifiers)

modifiers[#modifiers + 1] = key:upper()
return table.concat(modifiers, " + ")
Comment thread
coderabbitai[bot] marked this conversation as resolved.
end

local function has_dedup_field(opts)
if type(opts) ~= "table" then
return false
Expand Down Expand Up @@ -106,7 +148,11 @@ hyde.binds.dedup_fields =
}

hyde.binds.normalize = normalize
hyde.binds.canonicalize = canonicalize

-- Maps a canonical combo to the exact string the live bind was registered
-- with. Unbinding matches that string, not the resolved key and modifiers, so
-- the original spelling has to be kept around to remove a bind again.
hyde.binds._active = hyde.binds._active or {}

local orig_add = hl.bind
Expand All @@ -115,14 +161,17 @@ hl.bind = function(keycombo, action, ...)
local normalized = hyde.binds.normalize(keycombo)
local opts = find_options(...)
local signature = serialize_flags(opts)
local dedup_id = normalized .. "|" .. signature
local dedup_id = canonicalize(keycombo) .. "|" .. signature

if normalized ~= "" and hyde.binds.dedup and hyde.binds._active[dedup_id] then
hl.unbind(normalized)
if normalized ~= "" and hyde.binds.dedup then
local registered = hyde.binds._active[dedup_id]
if registered then
hl.unbind(registered)
end
end

if normalized ~= "" then
hyde.binds._active[dedup_id] = true
hyde.binds._active[dedup_id] = normalized
keycombo = normalized
end

Expand Down
69 changes: 40 additions & 29 deletions Configs/.local/share/hypr/lua/key_binds.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
-- * Enable bind deduplication so repeated key combos don't conflict.
-- * This has to run before the first bind below, otherwise the binds in this
-- * file are registered unchecked and only user overrides get deduplicated.
-- * For multiple dispatcher actions, wrap them in one function and bind that.
-- * If you set `hyde.binds.dedup = false`, unbind duplicates manually.
hyde.binds.dedup = true
-- hyde.binds.dedup_fields = {}

-- vars for easy access
local _apps = hyde.config.app
local MOD = hyde.config.modifiers.main
Expand Down Expand Up @@ -73,15 +81,15 @@ _F = {description = "[Window Management] toggle pin"}
hl.bind(MOD .. " + F", hl.dsp.exec_cmd(hyde.sh.window.pin()), _F)
_F = {description = "[Window Management] logout menu"}
hl.bind("CTRL + ALT + DELETE", hl.dsp.exec_cmd(hyde.sh.session.logout.launcher()), _F)
-- ALT_R is a keysym, not a modifier: "ALT_R + CONTROL_R" resolves to a bare
-- right Control, so every press of that key hid the bar.
_F = {description = "[Window Management] hide waybar"}
hl.bind("ALT_R + CONTROL_R", hl.dsp.exec_cmd(hyde.sh.waybar("--hide")), _F)
hl.bind(MOD .. " + CTRL + B", hl.dsp.exec_cmd(hyde.sh.waybar("--hide")), _F)
_F = {description = "[Window Management] lock session"}
hl.bind(MOD .. " + L", hl.dsp.exec_cmd(hyde.sh.session.lock()), _F)

_F = {description = "[Window Management|Group Navigation] change active group backwards"}
hl.bind(MOD .. " + CTRL + Left", hl.dsp.group.prev(), _F)
_F = {description = "[Window Management|Group Navigation] change active group forwards"}
hl.bind(MOD .. " + CTRL + Right", hl.dsp.group.next(), _F)
-- Group navigation lives on ALT only. The CTRL variant collided with relative
-- workspace navigation further down, which binds the same combo.
_F = {description = "[Window Management|Group Navigation] change active group backwards"}
hl.bind(MOD .. " + ALT + Left", hl.dsp.group.prev(), _F)
_F = {description = "[Window Management|Group Navigation] change active group forwards"}
Expand Down Expand Up @@ -250,17 +258,20 @@ hl.bind(MOD .. "+ SHIFT + T", hl.dsp.exec_cmd(hyde.sh.menu.themes()), _F)
-- bindd = $mainMod SHIFT, R, $d wallbash mode selector , exec, pkill -x rofi || hyde-shell wallbashtoggle.sh -m # launch wallbash mode select menu
-- bindd = $mainMod SHIFT, T, $d select a theme, exec, pkill -x rofi || hyde-shell themeselect.sh # launch theme select menu

-- Numpad keys for workspaces 11-20. The Lua bind parser has no keycode form,
-- so each key is bound under both keysyms it can emit: the digit while Num
-- Lock is on, the navigation name while it is off.
local kp = {
[1] = 87,
[2] = 88,
[3] = 89,
[4] = 83,
[5] = 84,
[6] = 85,
[7] = 79,
[8] = 80,
[9] = 81,
[0] = 90
[1] = {"KP_1", "KP_End"},
[2] = {"KP_2", "KP_Down"},
[3] = {"KP_3", "KP_Next"},
[4] = {"KP_4", "KP_Left"},
[5] = {"KP_5", "KP_Begin"},
[6] = {"KP_6", "KP_Right"},
[7] = {"KP_7", "KP_Home"},
[8] = {"KP_8", "KP_Up"},
[9] = {"KP_9", "KP_Prior"},
[10] = {"KP_0", "KP_Insert"}
}

for i = 1, 10 do
Expand All @@ -269,8 +280,13 @@ for i = 1, 10 do
end

for i = 1, 10 do
local key = (i == 10) and 90 or kp[i]
hl.bind(MOD .. "+code:" .. key, hl.dsp.focus({workspace = tostring(i + 10)}), {description = "WS " .. (i + 10)})
for _, key in ipairs(kp[i]) do
hl.bind(
MOD .. " + " .. key,
hl.dsp.focus({workspace = tostring(i + 10)}),
{description = "[Workspaces|Navigation] navigate to workspace " .. (i + 10)}
)
end
end

_F = {description = "[Workspaces|Navigation|Relative workspace] change active workspace forwards"}
Expand All @@ -287,12 +303,13 @@ for i = 1, 10 do
end

for i = 1, 10 do
local key = (i == 10) and 90 or kp[i]
hl.bind(
MOD .. "+SHIFT+code:" .. key,
hl.dsp.window.move({workspace = tostring(i + 10)}),
{description = "WS " .. (i + 10)}
)
for _, key in ipairs(kp[i]) do
hl.bind(
MOD .. " + SHIFT + " .. key,
hl.dsp.window.move({workspace = tostring(i + 10)}),
{description = "[Workspaces|Move window to workspace] move focused window to workspace " .. (i + 10)}
)
end
end

_F = {description = "[Workspaces|Move window to workspace|Relative workspace] move focused window to next workspace"}
Expand Down Expand Up @@ -372,9 +389,3 @@ end
-- bindk = Super ALT, F ,test device, exec , notify-send "Hyprland" "You just pressed Super + F again!2"

-- # bindd = Alt, D , [Utilities] Enable Wayscriber ,exec, wayscriber --active

-- * Enable bind deduplication so repeated key combos don't conflict.
-- * For multiple dispatcher actions, wrap them in one function and bind that.
-- * If you set `hyde.bind.dedup = false`, unbind duplicates manually.
hyde.binds.dedup = true
-- hyde.binds.dedup_fields = {}
Loading