diff --git a/default/hypr/bindings/tiling.lua b/default/hypr/bindings/tiling.lua index 83e0c16e0a0..5741914342b 100644 --- a/default/hypr/bindings/tiling.lua +++ b/default/hypr/bindings/tiling.lua @@ -98,8 +98,24 @@ o.bind("SUPER + CTRL + RIGHT", "Move grouped window focus right", hl.dsp.group.n o.bind("SUPER + ALT + mouse_down", "Next window in group", hl.dsp.group.next()) o.bind("SUPER + ALT + mouse_up", "Previous window in group", hl.dsp.group.prev()) +function o.switch_group_window(index) + local window = hl.get_active_window() + local group = window and window.group + + if group and index <= group.size then + hl.dispatch(hl.dsp.group.active({ index = index })) + end +end + for index = 1, 5 do - o.bind("SUPER + ALT + code:" .. tostring(index + 9), "Switch to group window " .. index, hl.dsp.group.active({ index = index })) + local group_index = index + local function switch() + o.switch_group_window(group_index) + end + + -- A function bind is opaque to the keybindings menu, so name a command it can run. + o.bind_commands[switch] = "hyprctl eval " .. o.shell_quote("o.switch_group_window(" .. group_index .. ")") + o.bind("SUPER + ALT + code:" .. tostring(group_index + 9), "Switch to group window " .. group_index, switch) end o.bind("SUPER + SLASH", "Monitor scaling up", "omarchy-hyprland-monitor-scaling up") diff --git a/test/shell.d/hyprland-group-bindings-test.sh b/test/shell.d/hyprland-group-bindings-test.sh new file mode 100644 index 00000000000..8b47107fee2 --- /dev/null +++ b/test/shell.d/hyprland-group-bindings-test.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +set -euo pipefail + +source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh" + +require_command lua + +# `lua -`, not bare `lua`: Lua 5.5 exits 0 when a script it reads from a pipe errors. +OMARCHY_PATH="$ROOT" lua - <<'LUA' +package.path = os.getenv("OMARCHY_PATH") .. "/?.lua;" .. package.path + +local function proxy() + return setmetatable({}, { + __index = function(self, key) + local value = proxy() + rawset(self, key, value) + return value + end, + __call = function() + return {} + end, + }) +end + +local bindings = {} +local active_window +local dispatched_index + +hl = { + dsp = proxy(), + bind = function(keys, dispatcher) + bindings[keys] = dispatcher + end, + dispatch = function(dispatcher) + dispatched_index = dispatcher.index + end, + get_active_window = function() + return active_window + end, +} + +hl.dsp.group.active = function(options) + return { index = options.index } +end + +require("default.hypr.helpers") +-- tiling.lua builds its workspace binds from monitor-workspaces.lua, which this test doesn't load. +o.workspaces = proxy() +require("default.hypr.bindings.tiling") + +active_window = { group = { size = 2 } } +bindings["SUPER + ALT + code:11"]() +assert(dispatched_index == 2, "an available group window is selected") + +dispatched_index = nil +bindings["SUPER + ALT + code:12"]() +assert(dispatched_index == nil, "an out-of-range group window is ignored") + +active_window = nil +bindings["SUPER + ALT + code:10"]() +assert(dispatched_index == nil, "a group window shortcut without a focused window is ignored") + +active_window = {} +bindings["SUPER + ALT + code:10"]() +assert(dispatched_index == nil, "a group window shortcut outside a group is ignored") + +assert( + o.bind_commands[bindings["SUPER + ALT + code:12"]] == "hyprctl eval 'o.switch_group_window(3)'", + "the keybindings menu can run a group window shortcut" +) +LUA + +pass "group number bindings dispatch only available group windows"