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
80 changes: 76 additions & 4 deletions bin/omarchy-menu-keybindings
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ parse_keycodes() {
if (code != "" && symbol != "" && symbol != "NoSymbol") keycode_symbol[code] = toupper(symbol)
}
# Read off the keysym rather than the keycode, so the key left of 1 reads
# as the symbol printed on it whichever key the active layout puts it on.
for (code in keycode_symbol) {
if (keycode_symbol[code] == "GRAVE") keycode_symbol[code] = "~"
}
mouse_symbol["272"] = "LEFT MOUSE BUTTON"
mouse_symbol["273"] = "RIGHT MOUSE BUTTON"
mouse_symbol["274"] = "MIDDLE MOUSE BUTTON"
Expand Down Expand Up @@ -305,6 +311,7 @@ dynamic_bindings() {

case "$key" in
comma) key="COMMA" ;;
grave) key="~" ;;
period) key="PERIOD" ;;
minus) key="MINUS" ;;
equal) key="EQUAL" ;;
Expand All @@ -324,15 +331,41 @@ static_bindings() {
echo "SHIFT ALT,D,Download Video from Web App,sendshortcut,SHIFT ALT,D,"
}

# Actions Omarchy binds to a second chord meant as an alternative, named one at
# a time. A rule would be wrong here: Alt + Tab and Shift + Alt + Tab both say
# "Reveal active window on top" while cycling opposite ways, and a media key is
# nobody's idea of an alternative to a Super chord. Only chords a user reaches
# for interchangeably belong on one row.
alternative_chord_actions() {
cat <<'ACTIONS'
Close window
Calculator
Toggle scratchpad
Move window to scratchpad
ACTIONS
}

# Parse and format keybindings
#
# `awk` does the heavy lifting:
# - Set the field separator to a comma ','.
# - Joins the key combination (e.g., "SUPER + Q").
# - Joins the command that the key executes.
# - Puts an action's alternative chord on the row with the first one.
# - Prints display text and dispatch metadata as tab-separated fields.
parse_binding_records() {
awk -F, '
awk -F, -v alternatives="$(alternative_chord_actions)" '
BEGIN {
# The column every row pads its chords to. Nothing is allowed past it: the
# menu renders in monospace, and a row that overruns pushes its arrow out
# of a column the eye reads straight down.
column = 35;
split(alternatives, named, "\n");
for (i in named) {
if (named[i] != "") shares_a_row[named[i]] = 1;
}
}
{
# Combine the modifier and key (first two fields)
key_combo = $1 " + " $2;
Expand Down Expand Up @@ -365,16 +398,49 @@ parse_binding_records() {
gsub(/[ \t]+/, " ", key_combo); # Collapse multiple spaces to one
}
# An alternative chord joins the row the first one opened: "SUPER + W /
# SUPER + Q -> Close window". Both halves have to agree on what they run,
# since a label is only what a chord is called; an unresolved dispatcher
# says nothing at all, so it never counts as agreement.
if (action != "") {
printf "%-35s → %s\t%s\t%s\n", key_combo, action, dispatcher, arg;
action_key = action SUBSEP dispatcher SUBSEP arg;
together = "";
if (action in shares_a_row && dispatcher != "" && action_key in leads) {
together = chords[leads[action_key]] " / " key_combo;
}
if (together != "" && length(together) <= column) {
chords[leads[action_key]] = together;
} else {
# Also the path a pair too wide for the column takes: two rows in
# line beat one that juts out of it.
entries++;
chords[entries] = key_combo;
actions[entries] = action;
dispatchers[entries] = dispatcher;
args[entries] = arg;
leads[action_key] = entries;
}
}
}
END {
for (entry = 1; entry <= entries; entry++) {
printf "%-*s → %s\t%s\t%s\n", column, chords[entry], actions[entry], dispatchers[entry], args[entry];
}
}'
}

prioritize_entries() {
awk -F '\t' '
{
# Alternative chords are display only. Classifying on them would read
# "SUPER SHIFT + RETURN / SUPER SHIFT + B" as the alternate browser chord
# and drop the browser 20 rows down its own list, so match the chord that
# leads the row and ignore the rest.
line = $1
sub(/ \/ [^→]*→/, " →", line)
prio = 50
if (match(line, /Keybindings/)) prio = 0
if (match(line, /Omarchy menu/)) prio = 1
Expand Down Expand Up @@ -436,6 +502,12 @@ prioritize_entries() {
cut -f2-
}

# Drop repeated records while keeping the order Hyprland reported them in, so
# the chord a user declared first is the one that leads a merged entry.
dedupe_binding_records() {
awk '!seen[$0]++'
}

output_binding_records_uncached() {
local dynamic

Expand All @@ -446,7 +518,7 @@ output_binding_records_uncached() {
[[ -n $dynamic ]] && printf '%s\n' "$dynamic"
static_bindings
} |
sort -u |
dedupe_binding_records |
parse_keycodes |
parse_binding_records |
prioritize_entries
Expand All @@ -458,7 +530,7 @@ output_binding_records_uncached() {

keybindings_cache_key() {
{
printf 'v11\n'
printf 'v13\n'
hyprctl devices 2>/dev/null | grep -F 'active keymap:'
hyprctl binds 2>/dev/null
} | sha256sum | awk '{ print $1 }'
Expand Down
1 change: 1 addition & 0 deletions default/hypr/bindings/tiling.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
o.bind("SUPER + W", "Close window", hl.dsp.window.close())
o.bind("SUPER + Q", "Close window", hl.dsp.window.close())
o.bind("CTRL + ALT + DELETE", "Close all windows", "omarchy-hyprland-window-close-all")

o.bind("SUPER + J", "Toggle window split", hl.dsp.layout("togglesplit"))
Expand Down
2 changes: 1 addition & 1 deletion manual/03-coming-from-mac-or-windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Updates come through one command — _Update > Omarchy_ — that updates Omarchy

Software comes from a package manager, not from downloaded installers.

And when you close a window, the app actually quits. There's no macOS limbo where the program keeps running with no windows. `Super + W` means gone.
And when you close a window, the app actually quits. There's no macOS limbo where the program keeps running with no windows. `Super + W` — or `Super + Q`, if that's the finger memory you arrived with — means gone.

### On Mac hardware

Expand Down
2 changes: 1 addition & 1 deletion manual/04-navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ If you hit `Super + Shift + 2`, you'll move the current focused application onto

If you hold down `Super` and use the mouse to click on a window, you'll be able to rearrange where it sits. If you hold `Super` and use the right button on the mouse, you can freely resize the window.

You close a window on `Super + W` (and close all windows on `Ctrl + Alt + Delete`).
You close a window on `Super + W` or `Super + Q` (and close all windows on `Ctrl + Alt + Delete`).

You can also go full screen with `Super + F` or even just full-width (keeping the top bar) with `Super + Alt + F` or full-screen within a window with `Super + Ctrl + F` (good for YouTube!).

Expand Down
2 changes: 1 addition & 1 deletion manual/07-hotkeys.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You can see all the main keyboard bindings with `Super + K` (Tmux bindings with
| `Super + Alt + Space` | Apps menu |
| `Super + Escape` | System menu (suspend, restart, etc) |
| `Super + Ctrl + L` | Lock computer |
| `Super + W` | Close window |
| `Super + W` or `Super + Q` | Close window |
| `Ctrl + Alt + Del` | Close all windows |
| `Super + T` | Toggle window between tiling/floating |
| `Super + J` | Toggle window position (horizontal/vertical) |
Expand Down
Loading