-- ============================================================================ -- Personal overrides, ported from the niri config. -- Append to ~/.config/hypr/hyprland.lua, after require("default.hypr.omarchy"). -- Every rebind of an Omarchy default is unbound first. The comment after each -- unbind says what the key did before. -- ============================================================================ -- ─── Window management ────────────────────────────────────────────────────── -- Mod+Q -> close. Omarchy already binds this, so it is only made explicit. hl.unbind("SUPER + Q") o.bind("SUPER + Q", "Close window", hl.dsp.window.close()) -- Mod+W was tabbed display. Here it flips the workspace layout, and sets every -- column to 75% of the screen when the workspace turns to scrolling. Dwindle -- needs no widths, because it re-tiles on its own. -- Needs ~/.local/bin/omarchy-toggle-layout. Pass another fraction to change -- the width, e.g. "omarchy-toggle-layout 0.6". hl.unbind("SUPER + W") -- was: close window o.bind("SUPER + W", "Toggle workspace layout", "omarchy-toggle-layout") -- Mod+BackSpace -> last window. hl.unbind("SUPER + BACKSPACE") -- was: toggle window transparency o.bind("SUPER + BACKSPACE", "Focus last window", hl.dsp.focus({ last = true })) -- Tabs. Hyprland groups are the nearest thing to a niri tabbed column. -- SUPER + G (group) and SUPER + ALT + TAB (next in group) are Omarchy defaults. -- ─── Focus and swap: hjkl ─────────────────────────────────────────────────── -- Focus steps through the windows of a group first, and leaves the group only -- at the ends. This is the focus half of the smart-move behavior below, and -- Hyprland does it on its own, so no script is needed. hl.config({ binds = { movefocus_cycles_groupfirst = true } }) hl.unbind("SUPER + J") -- was: toggle window split hl.unbind("SUPER + K") -- was: keybindings menu hl.unbind("SUPER + L") -- was: toggle workspace layout o.bind("SUPER + H", "Focus on left window", hl.dsp.focus({ direction = "l" })) o.bind("SUPER + J", "Focus on below window", hl.dsp.focus({ direction = "d" })) o.bind("SUPER + K", "Focus on above window", hl.dsp.focus({ direction = "u" })) o.bind("SUPER + L", "Focus on right window", hl.dsp.focus({ direction = "r" })) -- The old SUPER + J job, moved to a free key. Dwindle only; toggling needs -- dwindle.preserve_split, which Omarchy already sets. o.bind("SUPER + D", "Toggle window split", hl.dsp.layout("togglesplit")) -- Smart move: merge into the neighboring group if there is one, else swap. -- Needs ~/.local/bin/omarchy-smart-move. o.bind("SUPER + SHIFT + H", "Move or merge left", "omarchy-smart-move l") o.bind("SUPER + SHIFT + J", "Move or merge down", "omarchy-smart-move d") o.bind("SUPER + SHIFT + K", "Move or merge up", "omarchy-smart-move u") o.bind("SUPER + SHIFT + L", "Move or merge right", "omarchy-smart-move r") -- ─── Workspaces and monitors ──────────────────────────────────────────────── hl.unbind("SUPER + CTRL + K") -- was: Herdr keybindings o.bind("SUPER + CTRL + J", "Next workspace", hl.dsp.focus({ workspace = "e+1" })) o.bind("SUPER + CTRL + K", "Previous workspace", hl.dsp.focus({ workspace = "e-1" })) -- Workspaces 1 to 5 on the home row of the left half: ALT to focus, -- ALT + SHIFT to send the window there. No Omarchy default uses ALT with a -- letter, so nothing is unbound. for index, key in ipairs({ "Q", "W", "E", "R", "T" }) do local workspace = tostring(index) o.bind("ALT + " .. key, "Switch to workspace " .. workspace, hl.dsp.focus({ workspace = workspace })) o.bind("ALT + SHIFT + " .. key, "Move window to workspace " .. workspace, hl.dsp.window.move({ workspace = workspace })) end hl.unbind("SUPER + O") -- was: pop window out hl.unbind("SUPER + SHIFT + O") -- was: Obsidian (moved to SUPER + CTRL + ALT + O) o.bind("SUPER + O", "Focus next monitor", hl.dsp.focus({ monitor = "+1" })) o.bind("SUPER + SHIFT + O", "Move window to next monitor", hl.dsp.window.move({ monitor = "+1" })) o.bind("SUPER + CTRL + SHIFT + J", "Move window to next monitor", hl.dsp.window.move({ monitor = "+1" })) o.bind("SUPER + CTRL + SHIFT + K", "Move window to previous monitor", hl.dsp.window.move({ monitor = "-1" })) -- Named workspaces, in place of niri-dynamic-workspaces. o.bind("SUPER + SHIFT + CTRL + ALT + W", "Workspace w", hl.dsp.focus({ workspace = "name:w" })) o.bind("SUPER + SHIFT + CTRL + ALT + H", "Workspace h", hl.dsp.focus({ workspace = "name:h" })) o.bind("SUPER + CTRL + ALT + X", "Workspace x", hl.dsp.focus({ workspace = "name:x" })) -- ─── Sizing ───────────────────────────────────────────────────────────────── -- Mod+R / Mod+Shift+R. Needs ~/.local/bin/omarchy-cycle-window-size. o.bind("SUPER + R", "Cycle window size", "omarchy-cycle-window-size") o.bind("SUPER + SHIFT + R", "Cycle window size back", "omarchy-cycle-window-size prev") -- Alt+Shift+hjkl. Hyprland resizes by pixels, not by percent, so 100 px -- replaces the niri 10%. o.bind("ALT + H", "Shrink window width", hl.dsp.window.resize({ x = -100, y = 0, relative = true })) o.bind("ALT + L", "Grow window width", hl.dsp.window.resize({ x = 100, y = 0, relative = true })) o.bind("ALT + K", "Shrink window height", hl.dsp.window.resize({ x = 0, y = -100, relative = true })) o.bind("ALT + J", "Grow window height", hl.dsp.window.resize({ x = 0, y = 100, relative = true })) -- Column fitting. These are scrolling layout messages, so they do nothing on -- a dwindle workspace. Mod+F (expand to available width) has no exact match; -- the Omarchy default SUPER + ALT + F (full width) is the closest. o.bind("SUPER + ALT + C", "Fit active column", hl.dsp.layout("fit active")) o.bind("SUPER + SHIFT + ALT + C", "Fit visible columns", hl.dsp.layout("fit visible")) -- ─── Applications ─────────────────────────────────────────────────────────── -- Same modifier block as the niri config. Each one focuses an open window -- before it launches a new one. The launch command uses the same desktop -- entry the vicinae URLs named, so no binary names are guessed. hl.unbind("SUPER + CTRL + A") -- was: audio panel o.bind("SUPER + CTRL + A", "Claude", "omarchy-launch-or-focus claude \"gtk-launch com.anthropic.Claude\"") o.bind("SUPER + CTRL + G", "Gemini", "omarchy-launch-or-focus gemini \"gtk-launch gemini-desktop\"") o.bind("SUPER + CTRL + ALT + H", "AI apps", "omarchy-cycle ai") o.bind("SUPER + CTRL + ALT + J", "Terminals", "omarchy-cycle-terminal") o.bind("SUPER + CTRL + ALT + K", "Browsers", "omarchy-cycle-browser") o.bind("SUPER + CTRL + ALT + G", "Ghostty", "omarchy-cycle ghostty") o.bind("SUPER + CTRL + ALT + Y", "Web apps", "omarchy-cycle webapp") o.bind("SUPER + CTRL + ALT + O", "Obsidian", "omarchy-cycle obsidian") o.bind("SUPER + CTRL + ALT + F", "File manager", "omarchy-launch-or-focus nautilus \"gtk-launch org.gnome.Nautilus\"") o.bind("SUPER + CTRL + ALT + E", "Fastmail", "omarchy-launch-or-focus fastmail \"gtk-launch fastmail\"") o.bind("SUPER + CTRL + ALT + M", "Beeper", "omarchy-launch-or-focus beeper \"gtk-launch beeper\"") hl.unbind("SUPER + CTRL + ALT + T") -- was: show time o.bind("SUPER + CTRL + ALT + T", "Todoist", "omarchy-launch-or-focus todoist \"gtk-launch todoist\"") hl.unbind("SUPER + CTRL + ALT + W") -- was: toggle weather o.bind("SUPER + CTRL + ALT + W", "tldraw", "omarchy-launch-or-focus tldraw \"gtk-launch tldraw_offline\"") o.bind("SUPER + CTRL + ALT + SPACE", "Sticky notes", "omarchy-launch-or-focus sticky \"gtk-launch io.github.faridjaff.StickyNotesCanvas\"") hl.unbind("SUPER + SHIFT + G") -- was: Signal o.bind("SUPER + SHIFT + G", "Goliath", { launch = "kitty --title=goliath ssh -t goliath tmux new-session -A -s main" }) -- ─── Screenshots ──────────────────────────────────────────────────────────── hl.unbind("SUPER + S") -- was: toggle scratchpad hl.unbind("SUPER + SHIFT + S") -- was: Google Maps hl.unbind("SUPER + CTRL + S") -- was: share menu o.bind("SUPER + S", "Screenshot region", "omarchy-capture-screenshot region") o.bind("SUPER + SHIFT + S", "Screenshot window", "omarchy-capture-screenshot windows") o.bind("SUPER + CTRL + S", "Screenshot monitor", "omarchy-capture-screenshot fullscreen") -- ─── Session ──────────────────────────────────────────────────────────────── hl.unbind("SUPER + SHIFT + E") -- was: Email (Fastmail is on SUPER + CTRL + ALT + E) o.bind("SUPER + SHIFT + E", "System menu", "omarchy-menu toggle system") o.bind("SUPER + SHIFT + Q", "System menu", "omarchy-menu toggle system") -- ─── Dictation ────────────────────────────────────────────────────────────── o.bind("SUPER + F24", "Dictate to Hermes", "voxtype record toggle --profile hermes") -- ─── Menus, in place of vicinae ───────────────────────────────────────────── -- Same keys as the niri config, pointed at the Omarchy menus. -- Mod+Space (vicinae toggle) needs no line: SUPER + SPACE is already the -- Omarchy menu. SUPER + ALT + SPACE is the apps menu. hl.unbind("SUPER + SHIFT + SPACE") -- was: toggle top bar o.bind("SUPER + SHIFT + SPACE", "Emojis", "omarchy-shell shell toggle omarchy.emojis") hl.unbind("SUPER + P") -- was: pseudo window o.bind("SUPER + P", "Clipboard manager", "omarchy-shell shell toggle omarchy.clipboard") -- Mod+Shift+Return was the vicinae window switcher. ScrollOverview on -- ALT + TAB below takes that job, so SUPER + SHIFT + RETURN keeps its default -- job of opening the browser. -- ─── ScrollOverview plugin ────────────────────────────────────────────────── if hl.plugin.scrolloverview then hl.config({ plugin = { scrolloverview = { gesture_distance = 300, -- how far is the "max" for the gesture scale = 0.5, -- preferred overview scale workspace_gap = 100, layout = "vertical", -- vertical or horizontal wallpaper = 2, -- 0: global only, 1: per-workspace only, 2: both blur = true, -- blur only the main overview wallpaper shadow = { enabled = true, range = 50, }, }, }, }) -- Omarchy puts two binds on ALT + TAB: focus next window, and reveal the -- active window on top. Both go, and the overview takes the key. Written with -- o.bind and a description, so it shows up in the keybindings menu. hl.unbind("ALT + TAB") o.bind("ALT + TAB", "Toggle overview", function() hl.plugin.scrolloverview.overview("toggle all") end) end