Skip to content
Open
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
81 changes: 80 additions & 1 deletion docs/docs/keybindings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Chords are shown with a + between the keys. You have 2 seconds to hit the 2nd ch
| <Kbd k="Ctrl:Shift:0"/> | Focus WaveAI input |
| <Kbd k="Ctrl:Shift:1-9"/> | Switch to block number |
| <Kbd k="Ctrl:Shift:Arrows"/> / <Kbd k="Ctrl:Shift:h/j/k/l"/> | Move left, right, up, down between blocks |
| <Kbd k="Ctrl:Shift:]"/> | Cycle block focus forward (CW) |
| <Kbd k="Ctrl:Shift:["/> | Cycle block focus backward (CCW) |
| <Kbd k="Ctrl:Shift:x"/> | Replace the current block with a launcher block |
| <Kbd k="Cmd:1-9"/> | Switch to tab number |
| <Kbd k="Cmd:["/> / <Kbd k="Shift:Cmd:["/> | Switch tab left |
Expand Down Expand Up @@ -105,7 +107,84 @@ Chords are shown with a + between the keys. You have 2 seconds to hit the 2nd ch
| <Kbd k="Shift:PageUp"/> | Scroll up one page |
| <Kbd k="Shift:PageDown"/>| Scroll down one page |

## Customizeable Systemwide Global Hotkey
## Customizing Keybindings

You can override, remap, or disable any default keybinding by editing `keybindings.json` in the Wave config directory (`~/.config/waveterm/keybindings.json`). You can also edit this file from within Wave by opening the Config editor and selecting "Keybindings" in the sidebar.

The file uses a VS Code-style array format. Each entry maps a key combination to an action ID. Only overrides are needed — all defaults apply automatically.

### Key Syntax

Key combinations use colon-separated format:

- **Modifiers:** `Cmd` (macOS Command / Windows-Linux Meta), `Ctrl`, `Shift`, `Alt` (macOS Option), `Meta`
- **Special keys:** `ArrowUp`, `ArrowDown`, `ArrowLeft`, `ArrowRight`, `Home`, `End`, `Escape`, `Enter`, `Tab`, `Space`, `Backspace`, `Delete`
- **Letters and digits:** Lowercase (`a`–`z`), digits (`0`–`9`)

Comment on lines +118 to +123
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Correct the Windows/Linux modifier mapping here.

This says Cmd means “Windows-Linux Meta”, but the parser maps Cmd to the Alt key on non-macOS and uses Meta for the Windows/Super key. As written, this will send Windows/Linux users to the wrong modifier.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/docs/keybindings.mdx` around lines 118 - 123, Update the modifiers list
in the "Key combinations use colon-separated format" section: change the
description for `Cmd` so it maps to macOS Command only (not “Windows-Linux
Meta”), document `Alt` as macOS Option / Windows-Linux Alt if desired, and
explicitly state `Meta` represents the Windows/Super (Windows key) on non-macOS.
Edit the modifiers bullet that currently reads "`Cmd` (macOS Command /
Windows-Linux Meta), `Ctrl`, `Shift`, `Alt` (macOS Option), `Meta`" to reflect
these corrected mappings so the parser behavior (Cmd→macOS Command,
Alt→Option/Alt, Meta→Windows/Super) matches the implementation.

### Examples

**Rebind a key:** Change "new tab" from <Kbd k="Cmd:t"/> to <Kbd k="Cmd:Shift:t"/>:
```json
[
{ "key": "Cmd:Shift:t", "command": "tab:new" }
]
Comment on lines +124 to +130
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Document this as additive unless the default is explicitly unbound.

This example adds Cmd:Shift:t, but it does not remove Cmd:t. The current override logic only drops the default when the user also adds -tab:new or { "key": null, "command": "tab:new" }, so the example does not actually “change” the shortcut.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/docs/keybindings.mdx` around lines 124 - 130, Explain that keybinding
overrides are additive by default and that adding { "key": "Cmd:Shift:t",
"command": "tab:new" } does not remove the existing Cmd:t binding; instruct to
either explicitly unbind the default by adding the negative form "-tab:new" or
by using the null-key form { "key": null, "command": "tab:new" } when showing
how to “change” the shortcut, and reference the example command "tab:new" and
the keys "Cmd:t" and "Cmd:Shift:t" so the author updates the example and
description accordingly.

```

**Disable a keybinding:** Remove <Kbd k="Cmd:w"/> close block:
```json
[
{ "command": "-block:close" }
]
```

You can also set `key` to `null` to unbind:
```json
[
{ "key": null, "command": "block:close" }
]
```

**Swap two keys:**
```json
[
{ "key": "Cmd:d", "command": "block:splitdown" },
{ "key": "Cmd:Shift:d", "command": "block:splitright" }
]
```

### Action IDs

| Action ID | Default Key | Description |
| --- | --- | --- |
| `tab:new` | <Kbd k="Cmd:t"/> | Open a new tab |
| `tab:close` | <Kbd k="Cmd:Shift:w"/> | Close the current tab |
| `tab:prev` | <Kbd k="Cmd:["/> | Switch to previous tab |
| `tab:next` | <Kbd k="Cmd:]"/> | Switch to next tab |
| `tab:switchto1`–`tab:switchto9` | <Kbd k="Cmd:1"/>–<Kbd k="Cmd:9"/> | Switch to tab N |
| `block:new` | <Kbd k="Cmd:n"/> | Open a new block |
| `block:close` | <Kbd k="Cmd:w"/> | Close the current block |
| `block:splitright` | <Kbd k="Cmd:d"/> | Split right |
| `block:splitdown` | <Kbd k="Cmd:Shift:d"/> | Split down |
| `block:magnify` | <Kbd k="Cmd:m"/> | Magnify/unmagnify block |
| `block:refocus` | <Kbd k="Cmd:i"/> | Refocus the current block |
| `block:navup/navdown/navleft/navright` | <Kbd k="Ctrl:Shift:Arrows"/> | Navigate between blocks |
| `block:navcw` | <Kbd k="Ctrl:Shift:]"/> | Cycle block focus forward (CW) |
| `block:navccw` | <Kbd k="Ctrl:Shift:["/> | Cycle block focus backward (CCW) |
| `block:switchto1`–`block:switchto9` | <Kbd k="Ctrl:Shift:1"/>–<Kbd k="Ctrl:Shift:9"/> | Switch to block N |
| `block:switchtoai` | <Kbd k="Ctrl:Shift:0"/> | Focus WaveAI input |
| `block:replacewithlauncher` | <Kbd k="Ctrl:Shift:x"/> | Replace block with launcher |
| `app:search` | <Kbd k="Cmd:f"/> | Find/search |
| `app:openconnection` | <Kbd k="Cmd:g"/> | Open connection switcher |
| `app:toggleaipanel` | <Kbd k="Cmd:Shift:a"/> | Toggle WaveAI panel |
| `app:togglewidgetssidebar` | <Kbd k="Cmd:b"/> | Toggle widgets sidebar |
| `app:settings` | <Kbd k="Cmd:,"/> | Open settings |
| `term:togglemultiinput` | <Kbd k="Ctrl:Shift:i"/> | Toggle terminal multi-input |
| `generic:cancel` | <Kbd k="Escape"/> | Close modals/search |
| `block:splitchord` | <Kbd k="Ctrl:Shift:s"/> | Initiate split chord |

Changes take effect immediately — no restart required.

## Customizable Systemwide Global Hotkey

Wave allows setting a custom global hotkey to focus your most recent window from anywhere in your computer. For more information on this, see [the config docs](./config#customizable-systemwide-global-hotkey).

Expand Down
6 changes: 6 additions & 0 deletions frontend/app/monaco/schemaendpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import aipresetsSchema from "../../../schema/aipresets.json";
import backgroundsSchema from "../../../schema/backgrounds.json";
import connectionsSchema from "../../../schema/connections.json";
import keybindingsSchema from "../../../schema/keybindings.json";
import settingsSchema from "../../../schema/settings.json";
import waveaiSchema from "../../../schema/waveai.json";
import widgetsSchema from "../../../schema/widgets.json";
Expand Down Expand Up @@ -45,6 +46,11 @@ const MonacoSchemas: SchemaInfo[] = [
fileMatch: ["*/WAVECONFIGPATH/widgets.json"],
schema: widgetsSchema,
},
{
uri: "wave://schema/keybindings.json",
fileMatch: ["*/WAVECONFIGPATH/keybindings.json"],
schema: keybindingsSchema,
},
];

export { MonacoSchemas };
13 changes: 13 additions & 0 deletions frontend/app/store/global-atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
const settingsAtom = atom((get) => {
return get(fullConfigAtom)?.settings ?? {};
}) as Atom<SettingsType>;
const keybindingsAtom = atom((get) => {
const fullConfig = get(fullConfigAtom);
if (!fullConfig?.keybindings) return [];
try {
const raw = fullConfig.keybindings;
const parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
return Array.isArray(parsed) ? parsed : [];
} catch {
console.warn("Failed to parse keybindings.json");
return [];
}
});
const hasCustomAIPresetsAtom = atom((get) => {
const fullConfig = get(fullConfigAtom);
if (!fullConfig?.presets) {
Expand Down Expand Up @@ -136,6 +148,7 @@ function initGlobalAtoms(initOpts: GlobalInitOptions) {
fullConfigAtom,
waveaiModeConfigAtom,
settingsAtom,
keybindingsAtom,
hasCustomAIPresetsAtom,
hasConfigErrors,
staticTabId: staticTabIdAtom,
Expand Down
Loading