Skip to content
TwinScope0.3.10

Keyboard map

Fifteen bindings, one registry. The table below is the same list that fires the keys, fills the Settings grid and populates the command palette.

How to read this page#

Combos are written the way you read them — ⌘⇧E — and matched by parsing that same string, so the label and the behaviour cannot disagree.

Global#

Available on every screen.

KeysActionDetail
⌘KCommand paletteEverything, by name
⌘OCompare files…Pick two files from disk
⌘⇧OCompare folders…Recursive tree diff
⌘⇧V ⌘VCompare clipboardPaste A, then paste B
⌘1Go to Compare
⌘2Go to History
⌘⇧LToggle themeDark ↔ light
⌘,SettingsTheme, defaults and shortcuts
EscClose overlay

Compare screen#

KeysActionDetail
⌘⇧SSwap sidesBefore becomes after

Workspace#

Available while a comparison is open.

KeysActionDetail
⌘⇧EExport reportRepeats the last format used
⌘FSearch in comparison
⌘\Cycle view modeText and JSON each remember their own
⌥↓Next change
⌥↑Previous change
Click to enlarge
Settings → Shortcuts is generated from the registry, so it cannot describe a key the app does not have.

Why plain ⌘V is not a key binding#

⌘V is declared in the registry as an alias of ⌘⇧V, but it is implemented as a paste event listener rather than a keydown match.

That is deliberate. Letting the platform decide what counts as a paste keeps

⌘V working normally inside every text field — the search box, the history filter, the palette input — and picks up the OS variants for free, such as pasting from the Edit menu or middle-click on Linux.

The listener bails out the moment the event target is an input, a textarea or anything contentEditable, and otherwise defers to exactly the same clipboard.read path ⌘⇧V uses. The keystroke is only a trigger; the payload, the type detection and the engine choice are identical either way.

One registry, three consumers#

src/renderer/src/lib/shortcuts.tsts
{
id: 'paste-compare',
combo: '⌘⇧V',
// Plain ⌘V works too whenever you are not typing — handled by a `paste`
// listener rather than a key binding, so text fields keep their own paste.
aliases: ['⌘V'],
label: 'Compare clipboard',
detail: 'Paste A, then paste B',
scope: 'global',
inPalette: true,
icon: '⧉',
}

One table drives three things that used to drift apart:

  1. What actually fires — the keymap iterates the registry and dispatches by id.
  2. The Settings grid — rendered from the same array, showing every binding for each action rather than only the primary, because a grid that lists one key while two work is exactly the drift the table exists to prevent.
  3. The palette's Actions group — entries marked inPalette become palette rows, carrying their own combo. Seven of the fifteen are marked.

A binding that is not in the registry does not exist.

Who owns which key#

Registry entries are dispatched by whichever surface can actually perform them. The application-level keymap owns Compare files, Compare folders, Compare clipboard, Swap sides, Toggle theme, Settings and the two view switches. The rest belong to their surface: ⌘K to the palette, ⌘F to the toolbar search, ⌘⇧E to the export menu, ⌘\ to whichever engine view has view modes, and Esc to the overlay that is open.

⌥↓ and ⌥↑ are handled ahead of the rest and only when the current result actually has changes to step through, so the keys stay available to the OS otherwise.

Keys that are not registry bindings#

These belong to one control rather than to the app, so they are not in the table above and do not appear in the Settings grid.

KeysWhereWhat it does
Compare screenRuns the comparison, once both sides are filled and nothing is already running. Ignored while you are typing in a field.
Command paletteMove the cursor
Command paletteOpen the highlighted entry
⇧⏎Text diff searchWalk forward and back through the matches
EscText diff searchClear the search