MODULO 4.6

⌨️ Keybindings

Pipeline de 5 estagios de processamento de teclas: decodificacao terminal, configuracao de bindings, matching de teclas, resolucao de chords e despacho React.

8
Topicos
~70
Minutos
Deep
Nivel
Source
Tipo
1

📡 Stage 1: Terminal Byte Decode

parse-keypress.ts converte sequencias de escape do terminal em objetos ParsedKey. Tres protocolos suportados:

Legacy VT sequences

Setas e function keys com info de modifier em parametros numericos (\x1b[1;5D = Ctrl+Left)

CSI u (Kitty protocol)

Formato "ESC [ codepoint ; modifier u" -- habilita combinacoes antes impossiveis como Shift+Enter

xterm modifyOtherKeys

Formato "ESC [ 27 ; modifier ; keycode ~" -- requer parsing explicito para evitar matches parciais

Modifier Bitmask (XTerm standard)

modifier = 1 + (shift?1:0) + (alt?2:0) + (ctrl?4:0) + (super?8:0)

2

📋 Stage 2: Default Bindings & Parsing

18 contextos suportados: Global, Chat, Autocomplete, Confirmation, Help, Transcript, HistorySearch, Task, ThemePicker, Settings, Tabs, Attachments, Footer, MessageSelector, DiffDialog, ModelPicker, Select, Plugin.

Bindings Notaveis (Chat context)

enter -- chat:submit
escape -- chat:cancel
ctrl+x ctrl+k -- chat:killAgents (chord)
ctrl+s -- chat:stash
ctrl+v / alt+v -- chat:imagePaste

💡 Platform-aware dynamic keys

Windows usa alt+v para image paste porque Ctrl+V e system paste. Shift+Tab depende do modo VT do terminal (Node.js 24.2.0+ / 22.17.0+).

3

🔍 Stage 3: Key Matching

Alt/Meta Unification

Terminais legacy nao distinguem Alt de Meta -- ambos setam key.meta = true. O matcher aceita se alt OU meta for requerido.

Escape Special Case

Pressionar Escape envia \x1b, que Ink interpreta como key.meta = true. O codigo strip meta explicitamente ao fazer match de escape keys.

4

🎵 Stage 4: Chord Resolution

O resolver retorna um de cinco resultados:

match
none
unbound
chord_started
chord_cancelled
flowchart TD
    A["Key event arrives"] --> B["Build testChord\n(pending + currentKeystroke)"]
    B --> C{"Escape key\n+ pending?"}
    C -->|"Yes"| CANCEL["chord_cancelled"]
    C -->|"No"| D{"Any live longer\nchord prefix?"}
    D -->|"Yes"| WAIT["chord_started\n(store pending)"]
    D -->|"No"| E{"Exact chord\nmatch?"}
    E -->|"action = null"| UNBOUND["unbound\n(swallow event)"]
    E -->|"action = string"| MATCH["match\n(fire action)"]
    E -->|"No match"| F{"Was in chord?"}
    F -->|"Yes"| CANCEL2["chord_cancelled"]
    F -->|"No"| NONE["none\n(propagate)"]
                    
5

⚛️ Stage 5: React Hooks & Context

Componentes registram interesse via useKeybinding() (acao unica) ou useKeybindings() (mapa de acoes).

False return convention

Um handler pode retornar false para sinalizar "nao consumido -- propagar adiante". ScrollKeybindingHandler usa isso para permitir que componentes filhos tratem wheel events quando o conteudo cabe na tela.

6

🔄 User Config & Hot-Reload

// ~/.claude/keybindings.json
{
  "bindings": [{
    "context": "Chat",
    "bindings": {
      "ctrl+y": "chat:submit",
      "enter": null,    // unbind Enter
      "ctrl+shift+p": "command:compact"
    }
  }]
}

Merge strategy: User bindings append apos defaults. Scan linear com last-match-wins significa que entradas do usuario supersede defaults naturalmente.

Hot-reload: chokidar monitora o arquivo com delay de 500ms. Delecao do arquivo reseta para defaults.

7

🛡️ Validacao & Shortcuts Reservados

Categoria Keys Severidade
Non-rebindablectrl+c, ctrl+d, ctrl+merror
Terminal reservedctrl+z, ctrl+\warn/error
macOS onlycmd+c/v/x/q/w/tab/spaceerror

💡 ctrl+s NAO e reservado

Flow control esta desabilitado em terminais modernos, e Claude Code usa ctrl+s para stashing.

8

🗺️ Pipeline Completo

flowchart LR
    subgraph Terminal
        B1["Raw bytes\n\\x1b[13;2u"]
    end
    subgraph Parse["parse-keypress.ts"]
        B2["CSI-u / VT / SGR\ndecodeModifier()"]
        B3["ParsedKey\n{name:'enter', shift:true}"]
        B2 --> B3
    end
    subgraph Config["Binding Config"]
        C1["defaultBindings.ts"]
        C2["~/.claude/keybindings.json"]
        C3["parseBindings()"]
        C1 --> C3
        C2 --> C3
    end
    subgraph Resolve["resolver.ts"]
        R1["resolveKeyWithChordState()"]
        R2["chord prefix check"]
        R3["exact match\nlast-wins scan"]
        R1 --> R2 --> R3
    end
    subgraph React["useKeybinding.ts"]
        H1["ChordResolveResult"]
        H2["handler()"]
        H1 --> H2
    end
    Terminal --> Parse
    Parse --> Resolve
    Config --> Resolve
    Resolve --> React
                    

📋 Resumo do Modulo

Pipeline de 5 estagios: byte decode, binding config, key matching, chord resolution, React dispatch
Tres protocolos de teclado suportados: Legacy VT, CSI u (Kitty), xterm modifyOtherKeys
18 contextos de UI, cada um com bindings independentes
Chord resolution com 5 resultados possiveis e modelo last-wins de override
Hot-reload via chokidar com delay de estabilizacao de 500ms
Validacao com 5 tipos de warning e shortcuts reservados protegidos
Modulo Anterior Proximo Modulo