Sweets
Configuration

Key Bindings

Bind keys and key sequences to Sweets actions

sweets.bind(spec, action [, argument]) maps a key combination or a multi-step sequence to an action.

sweets.bind("MOD+Return", "spawn", { "foot" })
sweets.bind("MOD+Q", "close")
sweets.bind("MOD+2", "workspace", 2)
sweets.bind("MOD+Ctrl+Right", "focus_output_right")
sweets.bind("MOD+B f", "spawn", { "firefox" })

The action tables below list which actions take an argument.

To run several actions from one binding, use a list of one through eight action entries. Each entry has a name and its optional argument:

sweets.bind("MOD+Alt+F", {
  { "toggle_floating" },
  { "center_window" },
}, { description = "Float and centre" })

The list runs in order. Each member uses the usual typed action validation. move_window and resize_window cannot be members because they start a held pointer grab; quit and mode must be last. Binding options such as repeat, release, cooldown, and description apply to the whole list. A list cannot use allow_when_locked or the spawn binding option. If one action is refused, later members still run. Two actions that change window or workspace geometry may complete in separate presentation rounds. The bindings overlay shows the list, and sweets msg binds reports action = "actions" with bounded argument text naming its members.

Mouse buttons and scroll directions use sweets.bind_mouse and sweets.bind_scroll, which accept the same general actions. noop is keyboard-only.

Consume a key

Use noop to consume a key without running a command or changing window focus:

sweets.bind("F7", "noop")

The application receives neither the press nor the release. sweets.unbind("F7") instead removes the binding and lets the key reach the application. A mode-local noop can block a shared binding while keeping its key consumed.

noop supports press-triggered keyboard bindings only, including key sequences. It cannot use on = "release" or allow_when_locked, or appear in mouse, scroll, gesture, or hot-corner actions. In a keyboard action list, later members still run. Normal shortcut inhibition applies.

Key specifications

Zero or more modifiers and one XKB keysym or physical XKB keycode, joined with +:

MOD+Shift+Return
Ctrl+Alt+Delete
XF86AudioMute
MOD+code:51
AltGr+Return
ModifierMeaning
MODWhatever mod_key is set to
CtrlControl
ShiftShift
AltAlt
SuperLogo / Windows key
AltGr, ISO_Level3_Shift, Mod5XKB level 3
ISO_Level5_ShiftXKB level 5

Names are case-insensitive, and Control, Mod1, Logo, Mod4, and Win also work. Do not combine MOD with the modifier it stands for — MOD+Super+Q is invalid while mod_key = "SUPER". mod_key accepts Super or Alt; the level modifiers must be named explicitly.

Key names are XKB keysyms such as q, Return, Escape, space, equal, KP_Add, or XF86AudioRaiseVolume. q and Q are the same key; add Shift when you mean Shift. code:N matches XKB keycode N (8 through 255) regardless of the symbol produced by the active layout. Read the XKB code in wev; it is the raw evdev code plus eight. If a keycode and keysym binding both match a press with the same modifiers, the keycode binding wins.

Modifiers must match exactly, so an extra held modifier prevents a match. Caps Lock and Num Lock are ignored, and Latin-letter bindings stay put when you switch keyboard layouts. Level-3 and level-5 modifiers are included in this exact comparison. A keysym binding with either level modifier still names the key by its level-one symbol, such as AltGr+h, even when the key types a different symbol while that modifier is held.

Set all_modes = true on a default binding to keep it active in named binding modes. The shipped volume, media, and brightness bindings use it. A mode can override or unbind the same trigger. The option is invalid inside a mode body, and a shared mode action can only return to default.

Multi-step sequences

Separate steps with a space. Each step has its own modifiers:

sweets.bind("MOD+B f", "spawn", { "firefox" })
sweets.bind("MOD+B c", "spawn", { "chromium" })
sweets.bind("Ctrl+X Ctrl+S", "reload")

For MOD+B f, press MOD+B, release, then press f alone — still holding MOD does not match.

A sequence may have up to eight steps, and each step gives you one second to press the next. A key that matches no branch cancels the sequence and is swallowed; a timeout instead lets the next key through normally.

Bindings must be prefix-free, so these cannot coexist:

sweets.bind("MOD+B", "close")
sweets.bind("MOD+B f", "spawn", { "firefox" })

Remove the shorter one first:

sweets.unbind("MOD+Q")
sweets.bind("MOD+Q Q", "close")

Actions

Programs and window state

ActionArgumentResult
noop—Consume a press-triggered keyboard binding
spawnargv tableLaunch a program
close—Ask the focused window to close
force_close—End the focused window's application
quit— or "now"Show a confirmation notice; a second quit binding within three seconds exits. "now" exits immediately
reload—Reload the configuration
dismiss_error—Hide the config-error bar
show_bindings—List the active bindings
modemode nameSwitch to a binding mode, or "default" to leave one
toggle_shortcuts_inhibit—Toggle shortcut inhibition for the focused window
toggle_inputinput selectorTurn a pointer device off and on
keyboard_layoutnext, prev, or 1–4Switch the active keyboard layout
toggle_floating—Tiled or floating
toggle_all_floating—Float every eligible window on the selected workspace, or tile them when all are floating
raise_floating, lower_floating—Move the focused floating window to the top or bottom among peers in its current stacking class
toggle_above, toggle_below—Temporarily put the focused window above or below ordinary windows; reload restores its opening rule
toggle_opacity—Make the focused window fully opaque until pressed again or the configuration reloads
toggle_gaming_mode—Toggle the runtime visual override for gaming
toggle_pin—Keep the focused floating window on its monitor across every workspace
monitor_poweron, off, or toggleTemporarily change power on the selected monitor
toggle_fullscreen—Fullscreen
toggle_windowed_fullscreen—Fullscreen without leaving the slot
toggle_maximize—Maximized
minimize—Hide the focused window
restore_minimized—Restore the most recently minimized window
center_window—Recenter the focused floating window, or the focused column on a scrolling workspace
move_floating_left/right/up/down—Move the focused floating window one step
resize_floating_grow, resize_floating_shrink—Resize a floating window horizontally
resize_floating_grow_vertical, resize_floating_shrink_vertical—Resize a floating window vertically
special_togglename (optional)Show or hide a special workspace; its options may launch the first window
special_movename (optional)Move the focused window into a special workspace

toggle_all_floating leaves minimized, pinned, maximized, and fullscreen windows alone. It is a batch toggle, not a saved snapshot of the old mixture: when any eligible window is tiled, all eligible windows float; when all are floating, the next press tiles all of them through their remembered slots.

raise_floating and lower_floating change order among peers in the current Above, Normal, or Below class. Focus, geometry, and class stay unchanged. A second press at the edge does nothing; a tiled or covering window is refused. A move that would put a transient child below its parent is refused. Later explicit focus can raise a lowered window normally.

toggle_above and toggle_below affect drawing and pointer hit testing together. Their override is temporary; every valid configuration reload clears it and restores the stacking class retained from the window's opening rules.

toggle_opacity makes the focused window fully opaque, including while it is being dragged. Press it again to use the window's configured opacity. A valid reload also clears the override. The opacity change uses animations.window_opacity; unfocused dimming remains separate. An already opaque window is unchanged.

toggle_gaming_mode temporarily suppresses Sweets window shadows, blur, compositor opacity (including XDG popups), inactive dimming, and visual animations. Switching it off restores the latest accepted Lua configuration; a valid reload while it is on updates those values without switching the mode off. It cannot change transparency drawn by a client. To keep the binding available when a game inhibits shortcuts, use:

sweets.bind("MOD+G", "toggle_gaming_mode", { allow_inhibiting = false })

The same state is available through sweets msg gaming-mode on|off|toggle and sweets msg status. For fullscreen games, check the compositor's actual plane assignment: removing effects can allow direct scanout but does not guarantee that the driver selects it.

Focus, movement, and workspaces

ActionArgumentResult
focus_next, focus_prev—Cycle focus in the workspace
focus_last—Return to the previously focused window in the workspace
focus_urgent—Focus the window that has been urgent the longest
recent_next, recent_previousscope string or { scope = "all", filter = "app_id" } (optional)Walk the held-modifier recent-windows switcher; the default scope is all
focus_left/right/up/down—Focus in a direction
focus_or_workspace_left/right/up/down—Focus in a direction, then fall through to the adjacent workspace
focus_output_left/right/up/down—Select an adjacent monitor
focus_outputconnector string or description tableSelect a named monitor
focus_output_next, focus_output_prev—Select the next or previous monitor, wrapping
workspace_swap_output_left/right/up/down—Exchange this monitor's workspace with an adjacent monitor's in shared mode
workspace_swap_output_next, workspace_swap_output_prev—Exchange with the next or previous monitor, wrapping, in shared mode
move_left/right/up/down—Move the focused window in a direction
move_output_left/right/up/down—Move it to an adjacent monitor
move_output_next, move_output_prev—Move it to the next or previous monitor, wrapping
move_output_keep_number_left/right/up/down—In per_monitor mode, move it to the same workspace number on an adjacent monitor and show that workspace
move_output_keep_number_next, move_output_keep_number_prev—Same numbered-workspace move to the next or previous monitor, wrapping
workspace1–10Switch workspace; its spawn option can launch on an empty target
workspace_move1–10Move the focused window to a workspace
workspace_empty—Switch to the first empty workspace on the selected monitor
workspace_move_empty—Move the focused window to that empty workspace
workspace_previous—Return this monitor to the workspace it showed before
workspace_relative_next, workspace_relative_prev—Switch to the next or previous numbered workspace
workspace_move_relative_next, workspace_move_relative_prev—Move the focused window to the relative workspace

Directional focus and movement look for a local target first; whether they continue onto the next monitor is set by focus_cross_monitor and move_cross_monitor. The *_output_* actions always cross.

focus_last is a toggle: it records the window you left, so pressing it again returns. It skips minimized and closed windows. focus_prev is a different action — it walks layout order, not recency.

recent_next and recent_previous are the held-modifier switcher. Their optional scope is workspace, monitor, or all; omission preserves the all-workspace, all-monitor behavior. See Recent Windows.

focus_urgent reaches any monitor. It switches workspace and restores a minimized window if it has to, then obeys pointer.follow_focus.

The *_output_next/*_output_prev actions cycle monitors in connector-name order and wrap at either end. They are the ones to bind on three or more monitors, where a direction runs out at the edge.

workspace_previous uses the same per-monitor memory as workspace_back_and_forth, but works whether or not that option is on: the option redirects a repeated number key, this is a key of its own. It does nothing on a monitor you have not switched away from yet.

Relative workspace actions use general.workspace_wrap and general.workspace_skip_empty; relative moves also use general.workspace_move_follow. They still pass the resolved number through the ordinary workspace path: a pinned target selects its monitor, while a visible, unpinned target follows workspace_shown_elsewhere. workspace_empty and workspace_move_empty select the lowest available workspace on the selected monitor. Minimized windows count as occupants; pinned windows do not. A workspace already shown or pinned to another monitor is skipped. An already selected empty target is a no-op. A numbered workspace binding with spawn launches only when its requested target remains selected and empty; use cooldown while an application starts. With general.spawn_origin_placement enabled, its first window opens there unless an opening rule specifies a different workspace.

The focus_or_workspace_* family preserves ordinary directional focus, including monitor and off-axis fallbacks, and changes workspace only when that search has no target.

Select a named monitor

focus_output selects a monitor by connector name or by its identity from sweets msg outputs.

sweets.bind("MOD+F8", "focus_output", "DP-1")
sweets.bind("MOD+F9", "focus_output", { make = "DEL", serial = "ABC123" })

A description accepts make, model, and serial; supply at least one. Every supplied field must match exactly. If several enabled monitors match, the first connector in name order wins.

Missing, disabled, powered-off, and already-selected monitors leave focus unchanged. The fallback * is not accepted. An active special workspace follows focus to the selected monitor; ordinary windows stay on their workspaces.

Layout and resizing

ActionArgumentResult
layoutlayout nameSelect tile, monocle, centered, grid, columns, deck, dwindle, or scrolling
cycle_layout, cycle_layout_reverse—Step through the layout cycle
reset_layout, reset_all_layouts—Restore layout proportions and runtime gap overrides
gaps_grow, gaps_shrinkoptional inner or outerAdjust the selected workspace by layout.gaps_step; defaults to inner
toggle_gaps—Hide or restore the selected workspace's gaps
cycle_master_position, cycle_master_position_reverse—Rotate the master position, or the scrolling strip's direction
swap_with_master—Swap the focused tiled window with the master slot
rotate_next, rotate_prev—Roll the tiled order so the next or previous window becomes master
move_next, move_prev—Swap the focused tile with its next or previous tiled-order neighbour, wrapping
focus_master—Focus the master slot, or its stack from the master
add_master, remove_master—Put one more or one fewer window in the master area
consume_or_expel_left, consume_or_expel_right—Scrolling: join the neighbouring column or tab group, or take one stacked member/tab out
move_column_left, move_column_right—Scrolling: move the focused column
focus_column_first, focus_column_last—Scrolling: focus the first or last column
cycle_column_width, cycle_column_width_reverse—Scrolling: step the focused column through the preset widths
toggle_full_width—Scrolling: fill the screen with the focused column, or undo it
expand_column—Scrolling: widen the column into the free space on screen
resize_grow, resize_shrink—Resize horizontally
resize_grow_vertical, resize_shrink_vertical—Resize vertically

swap_with_master promotes the focused tiled window to the master slot. A window that is already master swaps with the stack member you focused most recently, so the same key sends it back. With several masters, a stack window swaps with the master you focused most recently. Floating windows are unaffected.

rotate_next and rotate_prev roll the whole stack by one instead of swapping two windows, and leave focus where it is. A minimized window keeps its place in the order. On a scrolling workspace they roll whole columns along the strip.

move_next and move_prev swap only the focused tiled window with the next or previous participating tile in layout order, wrapping at either end. They keep focus on that window. On a scrolling workspace they swap whole columns and keep minimized members with their columns. Floating and covering windows, and a workspace with only one tile or column, do nothing. Unlike rotate_next, the other order positions remain in place.

sweets.bind("MOD+Alt+J", "move_next")
sweets.bind("MOD+Alt+K", "move_prev")

focus_master jumps to the master slot from anywhere in the stack. From the master it focuses the stack member you used most recently, so the same key sends you back. On a scrolling workspace use focus_column_first instead.

center_window moves a floating window and keeps its size. On a scrolling workspace it centers the focused column on screen instead. On a tiled window of any other layout it does nothing.

The move_floating_* and resize_floating_* actions travel one layout.floating_step. They act only on floating windows; resize_grow and its variants act only on tiled ones. Keyboard floating moves use the window_move animation when enabled.

See Layout for how each layout resizes.

Spawning programs

spawn takes an argument array — the executable, then one string per argument:

sweets.bind("MOD+E", "spawn", { "foot", "nvim", "/tmp/notes.txt" })
sweets.bind("MOD+D", "spawn", { "fuzzel" })

There is no shell, so pipes, redirection, variables, wildcards, quoting, and ~ are not interpreted. Use up to 32 strings, 256 bytes each and 4096 bytes total.

Programs inherit the session environment and WAYLAND_DISPLAY. Their standard error goes to the session log, so a failed launch is visible there and never affects the compositor. Add variables with sweets.env.

Running a binding while locked

The lock screen ignores your bindings. Add allow_when_locked to let one through:

sweets.bind("XF86AudioMute", "spawn", {
    "wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle",
}, { allow_when_locked = true })

The options table goes after the action's argument, or in its place when the action takes none. It defaults to off.

Only a single-key spawn may use it. Any other action, or a multi-step sequence, rejects the configuration. Keys that have not opted in still reach the lock screen, so password entry is unaffected.

A program launched this way runs with your session's full access while the screen is locked. Bind only what you would be comfortable letting someone at your keyboard run.

Binding options

The options table also takes these keys:

OptionValuesDefaultEffect
repeatingtrue, falsefalseRuns the binding again while its key is held.
allow_extra_modifierstrue, falsefalseA single key press still matches when other modifiers are held.
all_modestrue, falsefalseMakes a default-set binding active in every named mode.
on"press", "release""press"Runs a single-key binding when pressed or tapped and released.
cooldown0–5000 ms0Smallest gap between two runs.
descriptiontext, up to 128 bytesnoneThe label shown in the bindings list.
spawnargv tablenoneLaunch on an empty special_toggle or numbered workspace target.
sweets.bind("XF86AudioRaiseVolume", "spawn", {
    "wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "5%+",
}, { repeating = true })

sweets.bind("MOD+Ctrl+r", "cycle_column_width", { cooldown = 120 })
sweets.bind("MOD+d", "spawn", { "fuzzel" }, { description = "Launcher" })
sweets.bind("Super_L", "spawn", { "fuzzel" }, { on = "release" })

A held binding repeats at your keyboard repeat_delay and repeat_rate. It stops when you release the key or press another one. repeat_rate = 0 turns it off. Only a single key can repeat; a key sequence rejects the option.

Write repeating, not repeat. repeat is a reserved word in Lua, so { repeat = true } is a syntax error.

A press during the cooldown does nothing and does not reach the application. The shipped configuration repeats the volume and brightness keys.

allow_extra_modifiers = true is useful for media keys while Shift, Ctrl, Alt, Super, or a level modifier is held. Any modifiers named in the binding are still required. Exact bindings win first; among equal matches a physical code: binding wins over a keysym binding. Two permissive bindings for the same key in one mode are rejected because their modifier sets overlap. Sequences, mouse and scroll bindings, and on = "release" cannot use this option. Extra modifiers can change the keysym through XKB, so use a code: binding when the physical key must work across such translations. This option does not change lock or shortcut inhibition permission.

on = "release" fires only if you release that key without pressing another key, clicking, or scrolling in between. Both the press and release still reach the focused app. It accepts one key and cannot be combined with repeating.

Replacing and removing bindings

Binding the same key again in your configuration replaces it:

sweets.bind("MOD+Return", "spawn", { "alacritty" })

Remove one with sweets.unbind:

sweets.unbind("MOD+Space")

sweets.unbind also removes a mouse or scroll binding — it works out which kind you named:

sweets.unbind("MOD+BTN_LEFT")

An unbind removes that exact sequence only, not longer ones sharing its steps. Unbinding something that is not bound is an error, as is binding the same key twice in one layer. Replacing a binding also replaces all of its options, so rebinding a key without allow_when_locked turns it off.

Up to 256 bindings are kept. Any duplicate, ambiguous prefix, unknown action, or wrong argument rejects the whole configuration and keeps the previous bindings.

A quit binding confirms by default. The notice appears on every monitor and names the binding you pressed. Any quit binding pressed again within three seconds exits; a timeout, an accepted reload, a binding mode change, or session lock clears the confirmation. To make one binding exit immediately, use:

sweets.bind("MOD+Ctrl+Shift+Q", "quit", "now")

sweets msg quit exits immediately for scripts.

Default bindings

Sweets always starts from a small built-in map, which works even with no configuration at all:

BindingAction
MOD+ReturnSpawn foot
MOD+QClose the focused window
MOD+Shift+QShow a quit notice; press again within three seconds to exit
MOD+Shift+RReload the configuration
MOD+Shift+EDismiss the config-error bar
MOD+EscapeToggle shortcut inhibition
MOD+Shift+slashList the active bindings
MOD+SpaceToggle floating
MOD+FToggle fullscreen
MOD+J, MOD+KFocus next or previous
MOD+Shift+H/J/K/LMove left, down, up, right
MOD+equal, MOD+minusResize horizontally
MOD+Shift+equal, MOD+Shift+minusResize vertically

The installed configuration adds the full workflow:

BindingAction
MOD+Shift+FToggle maximize
MOD+M, MOD+Shift+MMinimize, restore
MOD+H/L, MOD+ArrowsFocus in a direction
MOD+Shift+ArrowsMove in a direction
MOD+Ctrl+H/J/K/L, MOD+Ctrl+ArrowsFocus an adjacent monitor
MOD+Ctrl+Shift+H/J/K/L, MOD+Ctrl+Shift+ArrowsMove to an adjacent monitor
MOD+1..9/0Switch to workspaces 1–10
MOD+Shift+1..9/0Move the window to workspaces 1–10
MOD+S, MOD+Shift+SToggle the special workspace, move into it
MOD+KP_Add, MOD+KP_SubtractResize horizontally
MOD+Shift+KP_Add, MOD+Shift+KP_SubtractResize vertically
MOD+I, MOD+Shift+ICycle the master position
MOD+W, MOD+Shift+WCycle layouts
MOD+U, MOD+Shift+UReset this layout, or all of them

Bindings your configuration does not mention stay active. Changing mod_key moves every MOD binding; ones written with an explicit Super do not move.

Listing your bindings

MOD+Shift+slash opens a list of every binding in the active set on the focused monitor. The next key press, click, or scroll closes it, so pressing the same binding again closes it too. The press still reaches its binding or window.

Bindings with a description come first and show it. The rest show their action. Inside a binding mode, the list shows that mode's bindings. MOD+Shift+slash is built in, so it works in every mode. If you open the list with another key, bind that key inside each mode as well.

sweets.bind("MOD+Shift+slash", "show_bindings")

sweets.bindings_overlay({
    columns = 2,
    background = "#1C1F26F2",
    text = "#E6E9F0",
    accent = "#7AA2F7",
    font = "Monospace 10",
})
FieldDefaultEffect
columns21–4 columns
background"#1C1F26F2"Panel color, #RRGGBB or #RRGGBBAA
text"#E6E9F0"Label color
accent"#7AA2F7"Title and key color
font"Monospace 10"Pango font description

The list shows as many bindings as fit on one screen. When some are left out, its last line says how many. sweets msg binds prints every binding in a terminal.

Media keys

The installed configuration binds the XF86 keys. They carry no modifier, so they work straight from a laptop keyboard, but each needs its tool installed. They remain exact by default. Redeclare a key with allow_extra_modifiers = true to use it while other modifiers are held.

BindingActionTool
XF86AudioRaiseVolumeVolume +5%, capped at 100%wpctl
XF86AudioLowerVolumeVolume −5%wpctl
XF86AudioMuteToggle output mutewpctl
XF86AudioMicMuteToggle microphone mutewpctl
XF86MonBrightnessUp / DownBacklight ±5%brightnessctl
XF86AudioPlay / XF86AudioPausePlay / pauseplayerctl
XF86AudioNext / XF86AudioPrevNext / previous trackplayerctl
XF86AudioStopStop playbackplayerctl

XF86TouchpadToggle is bound too, to turn the touchpad off and on.

All the spawning keys set allow_when_locked, so they keep working on the lock screen. Rebind any key without that option to turn that off.

The installed file also carries commented recipes for the keyboard backlight, the lock key, the radio key and the power key, which not every laptop has.

The power key is the one that needs more than a binding: logind powers the machine off on its own. Set general.power_key = "compositor" to take the key away from it.

Some laptops report brightness keys from two devices at once, so one press runs the binding twice and the backlight jumps by double the step. Run libinput debug-events and press the key to see whether yours does.

Volume uses wpctl from PipeWire and WirePlumber. On PulseAudio, rebind to the pactl equivalents shown in the installed sweets.lua. Sweets does not install these tools.

Windowed fullscreen

toggle_windowed_fullscreen tells the focused window it is fullscreen without moving it. The window hides its own chrome and keeps its slot, its border and its gaps.

sweets.bind("MOD+Ctrl+Shift+F", "toggle_windowed_fullscreen")

Use it to share a browser presentation, or a video, while keeping your notes on screen beside it.

A window that is already fullscreen returns to its slot and stays chromeless. Pressing toggle_fullscreen, or the window asking for fullscreen itself, takes over and clears the windowed state.

Not every application reacts to the fullscreen state, so on some windows this appears to do nothing. XWayland windows are refused outright. Either way the compositor logs what it decided at debug level.

Force close

force_close ends an application that will not close. It sends SIGTERM, then SIGKILL three seconds later if the application is still connected.

sweets.bind("MOD+Ctrl+Q", "force_close")

It ends the whole application, so its other windows close too. XWayland windows are refused, because they all share one Xwayland process.

A window that ignores close for five seconds is marked unresponsive. Its border takes border.unresponsive, and sweets msg windows reports unresponsive: true. The mark clears as soon as the application responds again.

Shortcut inhibition

Games, virtual machines, and remote-desktop clients can ask to receive shortcuts themselves. While such a window has focus, your bindings go to it instead. Set allow_inhibiting = false on selected keyboard bindings to keep them with Sweets:

sweets.bind("MOD+1", "workspace", 1, { allow_inhibiting = false })

That key's press and release are consumed, so the client never receives it. The default is true. The option is rejected on mouse or scroll bindings, which shortcut inhibition does not affect, and with on = "release", which forwards both edges. It is separate from allow_when_locked.

toggle_shortcuts_inhibit stays with the compositor, and the built-in MOD+Escape is the escape hatch. If you remove it, bind that action to something else.

A sequence can start while inhibition is active only if a branch reaches an exempt action. A shared prefix is consumed; choosing a non-exempt branch cancels the sequence and consumes that key too. Virtual-terminal switching always stays with the compositor, and no binding runs while the session is locked.

Reload

sweets --check-config
sweets msg reload

A valid reload replaces every binding at once and cancels a half-typed sequence. An invalid one changes nothing.

On this page