InkdownInkdown
Start writing

Claude-Code

62 files·4 subfolders

Shared Workspace

Claude-Code
codex

15-keybindings

Shared from "Claude-Code" on Inkdown

Keybindings System

Complete keyboard shortcut customization for the terminal UI.


Overview

A full keyboard shortcut system with 20+ contexts, user-configurable bindings, chord support, and platform-aware resolution.


Architecture

Plain text
┌─────────────────────────────────────────────┐
│              KeybindingProvider              │
│                                              │
│  ┌─────────────┐    ┌──────────────────┐    │
│  │ Default     │    │ User Bindings    │    │
│  │ Bindings    │    │ (keybindings.json)│   │
│  └──────┬──────┘    └────────┬─────────┘    │
│         │                    │              │
│         └────────┬───────────┘              │
│                  ▼                          │
│         ┌──────────────┐                    │
│         │  Resolver    │                    │
│         │  (priority)  │                    │
│         └──────┬───────┘                    │
│                │                            │
│         ┌──────▼───────┐                    │
│         │  Matcher     │                    │
│         │  (keypress)  │                    │
│         └──────────────┘                    │
└─────────────────────────────────────────────┘
0000_start_here_index_and_recommended_reading_order.md
0100_project_overview_tech_stack_runtime_modes_and_folder_map.md
0200_startup_flow_entry_points_and_cold_start_sequence.md
0300_codebase_modules_layers_state_models_and_schemas.md
0400_system_architecture_and_design_rationale.md
0500_interactive_repl_request_flow_end_to_end.md
0600_headless_sdk_and_print_mode_request_flow_end_to_end.md
0700_mcp_integration_connection_and_tool_call_flow.md
0800_external_services_sdks_storage_and_local_dependencies.md
0900_environment_variables_settings_feature_flags_and_failure_modes.md
1000_non_obvious_patterns_gotchas_and_debugging_traps.md
1100_full_codebase_file_inventory_grouped_by_directory.md
kimi
00-overview.md
01-entrypoints.md
02-state-management.md
03-query-system.md
04-tools-system.md
05-tasks-system.md
06-ui-components.md
07-bridge-remote.md
08-services.md
09-skills-plugins.md
10-commands.md
11-testing-architecture.md
12-permission-system.md
13-build-system.md
14-ink-internals.md
15-git-internals.md
16-context-compaction.md
17-vim-mode.md
18-mailbox-notifications.md
19-session-persistence.md
20-hooks-system.md
21-error-recovery.md
README.md
qwen
00-overview.md
01-entry-points.md
02-query-engine.md
03-tools-and-tasks.md
04-commands-and-skills.md
05-state-management.md
06-ink-rendering.md
07-bridge-remote.md
08-mcp-services.md
09-services-overview.md
10-multi-agent.md
11-system-prompt-constants.md
12-tool-interface.md
13-memory-system.md
14-buddy-companion.md
15-keybindings.md
16-stop-hooks.md
17-vim-mode.md
18-upstreamproxy.md
19-cost-tracking-history.md
20-contexts-styles-onboarding.md
21-hooks.md
22-screens.md
tweets-explain
claude-code-memory-analysis.md
compact
memory-system
agentic-architecture

Contexts

20+ binding contexts, each with its own keymap:

ContextScope
GlobalAlways active
ChatWhen typing in the chat input
AutocompleteWhen autocomplete is open
ConfirmationWhen confirmation dialog is shown
HelpWhen help panel is open
TranscriptWhen viewing transcript
HistorySearchWhen searching history (ctrl+r)
TaskWhen task panel is focused
ThemePickerWhen picking a theme
SettingsWhen in settings UI
TabsTab navigation
AttachmentsAttachment management
FooterFooter item selection
MessageSelectorMessage selection mode
DiffDialogDiff viewer
ModelPickerModel selection UI
SelectGeneric select component
PluginPlugin management UI
ScrollScrollable content
MessageActionsMessage action buttons
Priority Resolution

Context-specific bindings override global bindings:

Plain text
User presses Ctrl+K
    │
    ▼
Is there a binding in the current context?
    ├─ Yes → use it
    └─ No → fall back to global bindings

Default Bindings (defaultBindings.ts)

Core bindings shipped with the app:

TypeScript
// Chat context
{ key: 'enter', action: 'submit' }
{ key: 'ctrl+c', action: 'cancel' }
{ key: 'up', action: 'history-prev' }
{ key: 'down', action: 'history-next' }

// Global context
{ key: 'ctrl+l', action: 'clear' }
{ key: 'ctrl+k', action: 'command-palette' }
{ key: 'ctrl+r', action: 'history-search' }
Platform-Aware Bindings

Different bindings for macOS vs Windows:

TypeScript
// macOS: Cmd+K
// Windows: Ctrl+K
const binding = isMac ? 'meta+k' : 'ctrl+k'
VT Mode Detection

Detects if running in a virtual terminal (vs SSH) and adjusts bindings accordingly.


User Configuration

Users customize bindings via keybindings.json:

JSON
{
  "bindings": [
    {
      "key": "ctrl+shift+k",
      "action": "command:help",
      "context": "global"
    }
  ]
}
Schema Validation

Bindings are validated with Zod:

TypeScript
const KeybindingSchema = z.object({
  key: z.string(),
  action: z.string(),
  context: z.enum(['global', 'chat', ...]).optional(),
})
Chord Support

Multi-key chords are supported:

JSON
{
  "key": "ctrl+x ctrl+k",
  "action": "custom-action"
}
Command Bindings

Keys can be bound to slash commands:

JSON
{
  "key": "f1",
  "action": "command:help"
}

Parser (parser.ts)

Parses keybinding strings into structured format:

TypeScript
parseKeybinding("ctrl+shift+k")
// → { modifiers: ['ctrl', 'shift'], key: 'k' }

parseKeybinding("ctrl+x ctrl+k")
// → { chord: [{ modifiers: ['ctrl'], key: 'x' }, { modifiers: ['ctrl'], key: 'k' }] }

Matcher (match.ts)

Matches a keypress against bindings:

TypeScript
matchBinding(keypress, bindings, context)
// → matching binding or null

Handles:

  • Modifier normalization
  • Case insensitivity
  • Chord matching
  • Context filtering

Resolver (resolver.ts)

Resolves the final binding for a keypress:

TypeScript
resolveBinding(keypress, context, defaultBindings, userBindings)
// → resolved binding (user > default > null)

Priority:

  1. User bindings for current context
  2. User global bindings
  3. Default bindings for current context
  4. Default global bindings

Validation (validate.ts)

Validates user keybindings:

TypeScript
validateKeybindings(raw)
// → { valid: true, bindings: [...] }
// → { valid: false, errors: [...] }

Checks:

  • Schema compliance
  • Duplicate keys
  • Invalid key names
  • Invalid actions

Reserved Shortcuts (reservedShortcuts.ts)

Shortcuts that cannot be overridden:

TypeScript
const RESERVED = [
  'ctrl+c',    // Cancel (terminal)
  'ctrl+z',    // Suspend (terminal)
  'ctrl+d',    // EOF (terminal)
]

Hooks

useKeybinding(action, callback)

Subscribe to a keybinding:

TypeScript
useKeybinding('submit', () => {
  handleSubmit()
})
useShortcutDisplay(action)

Get the display string for a shortcut:

TypeScript
const submitKey = useShortcutDisplay('submit')
// → "⏎" or "Enter"

Template (template.ts)

Generates the default keybindings.json template:

TypeScript
generateKeybindingTemplate()
// → JSON string with all default bindings as comments

Format (shortcutFormat.ts)

Formats keybindings for display:

TypeScript
formatShortcut({ modifiers: ['ctrl'], key: 'k' })
// → "Ctrl+K" (Windows)
// → "⌘K" (macOS)

Files

FilePurpose
src/keybindings/defaultBindings.tsDefault key bindings
src/keybindings/KeybindingContext.tsxReact context for keybindings
src/keybindings/KeybindingProviderSetup.tsxProvider initialization
src/keybindings/loadUserBindings.tsLoad user keybindings.json
src/keybindings/match.tsKey matching logic
src/keybindings/parser.tsKey string parser
src/keybindings/reservedShortcuts.tsReserved shortcuts
src/keybindings/resolver.tsBinding resolution
src/keybindings/schema.tsZod validation schema
src/keybindings/shortcutFormat.tsDisplay formatting
src/keybindings/template.tsTemplate generation
src/keybindings/useKeybinding.tsuseKeybinding hook
src/keybindings/useShortcutDisplay.tsDisplay hook
src/keybindings/validate.tsValidation logic