# Keybindings

"Every default keybinding, grouped by what you want to do, plus how to rebind."

Every default binding, grouped by intent. `Super` is scoot's own modifier
throughout; directions are vim's `h` `j` `k` `l`.
The rightmost column is the action string — the same grammar `scootctl action`
takes and `[binds]` uses, so each row is also its own rebind recipe.

## Cheat sheet

The whole map on one card — print it, or keep it on a second screen
until your fingers learn it:

| | `h` | `j` / `k` | `l` |
|---|---|---|---|
| **`Super`** | focus column left | focus window down / up | focus column right |
| **+ `Shift`** | move column left | move window down / up | move column right |
| **+ `Alt`** | consume / expel | — | consume / expel |
| **+ `Ctrl`** | — | focus workspace down / up | — |
| **+ `Ctrl`+`Shift`** | — | carry window to workspace down / up | — |

| | |
|---|---|
| `Super`+`1`…`9` / +`Shift` | go to workspace N / carry window there |
| `Super`+`comma` / `period` (+`Shift`) | focus output left / right, wrapping (carry with `Shift`) |
| `Super`+`r` / `f` / `m` | cycle width / fullscreen / maximize |
| `Super`+`Space` / +`Shift`+`Space` | focus floating vs strip / float or un-float |
| `Super`+`Return` / `q` / `Shift`+`e` | terminal / close window / quit |

## Move around

| Keys | Does | Action |
|---|---|---|
| `Super`+`h` / `l` | Focus column left / right | `focus-column left\|right` |
| `Super`+`j` / `k` | Focus window down / up | `focus-window down\|up` |
| `Super`+`Ctrl`+`j` / `k` | Focus workspace down / up | `focus-workspace down\|up` |
| `Super`+`1`…`9` | Focus workspace 1–9 directly | `focus-workspace-index N` |
| `Super`+`comma` / `period` | Focus output left / right (wraps) | `focus-output-left\|right` |
| `Super`+`Space` | Move focus between floating windows and the strip | `toggle-floating-focus` |

Targeting a workspace that doesn't exist yet does nothing — it neither
creates one nor falls back. (Empty workspaces are dropped, so an index only
means something against the list it was read from.)

## Move windows

| Keys | Does | Action |
|---|---|---|
| `Super`+`Shift`+`h` / `l` | Move column left / right | `move-column left\|right` |
| `Super`+`Shift`+`j` / `k` | Move window down / up | `move-window down\|up` |
| `Super`+`Ctrl`+`Shift`+`j` / `k` | Move window to workspace down / up | `move-window-to-workspace down\|up` |
| `Super`+`Shift`+`1`…`9` | Move window to workspace 1–9 | `move-window-to-workspace-index N` |
| `Super`+`Shift`+`comma` / `period` | Move window to output left / right (and follow it) | `move-window-to-output-left\|right` |
| `Super`+`Alt`+`h` / `l` | Consume into / expel from a column | `consume-or-expel left\|right` |

## Shape windows

| Keys | Does | Action |
|---|---|---|
| `Super`+`r` | Cycle the column's width | `cycle-column-width` |
| `Super`+`f` | Fullscreen on / off | `toggle-fullscreen` |
| `Super`+`m` | Maximize on / off (bar stays visible) | `toggle-maximize` |
| `Super`+`Shift`+`Space` | Float the window, or put it back | `toggle-floating` |
| `Super`+drag | Move / resize a floating window (left / right button) | `[floating] modifier` |

## Launch and leave

| Keys | Does | Action |
|---|---|---|
| `Super`+`Return` | Open a terminal (`foot`) | `spawn foot` |
| `Super`+`q` | Close the focused window | `close` |
| `Super`+`Shift`+`e` | Quit scoot | `quit` |

Quit is deliberately `Super`+`Shift`+`e`, not
`Super`+`Shift`+`q`: one slipped Shift away from
"close window", and a slip shouldn't end the whole session.

The desktop profile adds two binds on top of these defaults:
`Super`+`d` opens the app launcher and
`Ctrl`+`Alt`+`Space` its run mode (PATH
executables beside the apps) — see
[the desktop profile](../desktop/index.md#launcher).

Under `--tty`, `Ctrl`+`Alt`+`F1`…`F12`
additionally switch VTs — always winning over config binds, so the recovery
path survives a bad config.

## Change one binding

Bindings live in `[binds]` in `~/.config/scoot/config.toml`: `"combo" =
"action string"`. Combos are `modifier+modifier+...+key`
(`super+shift+h`); names are case-insensitive; a capital letter names the
*unshifted* key, so Shift chords spell Shift out. To open a different
terminal:

```toml
[binds]
"super+Return" = "spawn alacritty"
```

Then apply it without restarting:

```sh
scootctl reload
```

Keybindings reload live — like the layout, outputs, appearance, floating
rules and autostart. Only `[tty] gpu`, `[renderer] backend`,
`[xwayland] enabled` and an output's `mode` need a restart, and a reload
says so by name instead of silently ignoring them. A mistake never stops
scoot from starting: it logs the problem and uses the default.

Want the whole file, commented? `scoot --print-default-config --write`
writes it once (and refuses rather than overwriting).

## The bind grammar

A `[binds]` entry is `"combo" = "action string"`. A combo is
`modifier+modifier+...+key` (`super+shift+h`), or a bare key with no
modifier (`"Return" = "close"` — legal, intercepting every press of that
key with no modifier held). Whitespace around `+` is ignored. Modifier
names are case-insensitive: `ctrl`/`control`, `shift`, `alt`,
`super`/`logo`/`meta`/`cmd`. The key is an xkb keysym name, tried
exactly then case-insensitively — and binds match a key's *unshifted*
symbol, so `"A"` means plain `a`, exactly like `"a"`: write
`"shift+a"` for the Shift chord.

Two failure behaviors worth knowing, since both fail silently rather
than as a startup error: a bind that doesn't parse is skipped with a
warning naming just that bind (everything else still loads); and two
combo strings resolving to the same combination (`"Super+H"` vs
`"super+h"`) are *both* skipped — "last one wins" would be
run-to-run-unstable, so the colliding group is dropped instead. There
is no "unbind" action: a user bind on a combo with a default simply
replaces it, and removing a bind from the file falls back to its
default (or to unbound).

A bind can also be a table with the action under `action` plus two
opt-ins — one entry carrying everything about one combo, rather than
a second list of combos elsewhere that could disagree with the action:

```toml
[binds]
"XF86AudioRaiseVolume" = { action = "spawn wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+", repeat = true, allow_when_locked = true }
```

To hold volume-up and have it keep stepping, that is the whole recipe:
`repeat = true`. To have the key work on the lock screen too,
`allow_when_locked = true` beside it.

- **`repeat` re-fires the bind while its key is held** — after a 200 ms
  delay, then 25 times a second (the seat keyboard's own rate, so
  binds step exactly the way a held key repeats in a terminal). The
  timer exists only while such a key is held. `quit` and `close`
  never repeat, even when flagged — holding quit must never end the
  session. Flagging either warns and runs the bind once.
- **`allow_when_locked` lets a `spawn` bind fire while the session is
  locked** — volume, brightness and media keys from the lock screen.
  Anything else keeps today's refusal even when flagged, and `scoot
  msg action ...` stays refused while locked too: an IPC request
  carries an arbitrary command from whoever sent it, while a bind can
  only run its config-pinned command.

Both default off, so a plain `"combo" = "action"` string behaves exactly
as before: fire once, never locked. A table entry missing its `action`,
or a non-boolean flag, warns and falls back; an unknown field warns
and is ignored, while the rest of the entry applies.

Fullscreen and maximize, spelled out: `Super+f` covers the whole output
while its column is focused — gaps, ring and a bar's reserved strip
included — keeping its place in the strip (focus away and the view
scrolls on; focus back and it covers again). Surfaces on the `top`
layer hide under it; `overlay` and the lock screen stay above.
`Super+m` fills the usable area instead (bar visible, gaps and ring
kept). Both restore the layout exactly on leave; moving the window, or
focusing a window stacked in the same column, ends them.
