Keybinding Claude Code: Rebind, Unbind, dan Chord

Di ~/.claude/keybindings.json, yang bisa Anda buat atau buka dengan menjalankan perintah /keybindings. Isinya array bindings berisi blok, masing-masing menyebut satu konteks dan peta keystroke ke action. Perubahannya terdeteksi dan diterapkan otomatis tanpa memulai ulang Claude Code.
Setel keystroke-nya ke null di blok konteks yang sesuai. Ini juga berlaku untuk binding chord. Tetapi untuk mengambil kembali sebuah tombol prefiks sebagai binding tombol tunggal, Anda harus melepas setiap chord yang memakainya — chord di konteks aktif mana pun menahan prefiksnya tetap terpesan, dan keluarga bawaannya bisa membentang lebih dari satu konteks.
Ada empat. Ctrl+C adalah interrupt yang dipatri dan Ctrl+D adalah exit yang dipatri. Ctrl+M terpesan karena terminal mengirim byte yang identik untuknya dan untuk Enter, sehingga mengikatnya terpisah tidak mungkin. Caps Lock sama sekali tidak pernah diteruskan ke aplikasi terminal.
Tidak, keduanya beroperasi di lapisan berbeda. Vim mode menangani input di level teks — gerakan kursor, mode, motion — sedangkan keybinding menangani action di level komponen. Escape di vim mode memindahkan insert ke normal mode alih-alih memicu cancel, dan sebagian besar shortcut bertombol kontrol lewat menuju sistem keybinding.
Biasanya soal konteks atau pemesanan chord. Sebuah action chat yang diletakkan di blok Global adalah JSON yang valid dan nama action yang valid, sekaligus sepenuhnya mati. Kalau file-nya valid dan binding-nya tetap diam, periksa konteksnya dulu, lalu apakah tombolnya merupakan prefiks sebuah chord di konteks aktif mana pun. Mulai dengan --debug untuk melihat detail validasinya.

Ringkasan Utama
Keybinding Claude Code tinggal di satu file yang dibuat oleh perintah keybindings, dan perubahannya berlaku tanpa memulai ulang. Binding tercakup pada sebuah konteks seperti Chat atau Confirmation, action memakai bentuk namespace-titik dua-action, dan menyetel sebuah action ke null melepas binding bawaannya. Empat shortcut sama sekali tidak bisa diganti.
Saya ingin satu tombol untuk menyisipkan baris baru lalu memilih tombol yang tampak kosong. Ia menolak terikat, dalam senyap, dan saya mengira file-nya yang salah. Bukan: tombol yang saya pilih adalah prefiks dari tiga chord bawaan, dan sebuah chord di konteks aktif mana pun menahan prefiksnya tetap terpesan. Binding saya sedang bersaing dengan mekanisme yang keberadaannya tidak saya sadari.
Sistem keybinding-nya lebih terstruktur daripada yang biasanya dibuat perkakas terminal — sembilan belas konteks, daftar action bernamespace, dukungan chord sungguhan — dan strukturnya itulah yang membuat sebagian rebind menolak bekerja dengan alasan yang tidak kentara. Tulisan ini membahas file-nya, konteksnya, aturan prefiks chord, tombol yang terpesan beserta alasannya, dan bagaimana vim mode serta keybinding hidup berdampingan tanpa berkelahi.
Jalankan perintah keybindings dan Claude Code membuat atau membuka file-nya untuk Anda. Isinya sebuah objek berisi array blok, masing-masing menyebut satu konteks dan peta dari keystroke ke action. URL schema di bagian atas bersifat opsional dan layak dipertahankan — ia memberi Anda autocompletion untuk nama action di editor mana pun yang membacanya, dan itu penting karena jumlahnya jauh lebih dari seratus.
// ~/.claude/keybindings.json — run /keybindings to create it.
// Changes are detected and applied WITHOUT restarting.
{
"$schema": "https://www.schemastore.org/claude-code-keybindings.json",
"bindings": [
{
"context": "Chat",
"bindings": {
"ctrl+e": "chat:externalEditor",
"ctrl+u": null
}
}
]
}
# Actions are namespace:action — chat:submit, app:toggleTodos.
# Setting one to null unbinds the default.
#
# Modifiers join with +: ctrl shift alt|opt|option|meta
# cmd|command|super|win
# The cmd group is only detected in terminals that report the
# Super modifier (Kitty protocol, xterm modifyOtherKeys). Most
# do not — use ctrl or meta for bindings that must work anywhere.Setiap binding milik sebuah konteks, dan binding di konteks yang keliru sekadar tidak pernah berjalan. Ada sembilan belas konteks, dan pembagiannya lebih halus daripada dugaan kebanyakan orang — dialog permission, penampil diff, model picker, dan penjelajah plugin semuanya punya konteks sendiri. Empat yang benar-benar akan Anda sentuh adalah berikut ini.
Konteks yang layak diketahui:
| Konteks | Kapan ia berlaku | Action khasnya |
|---|---|---|
| Global | Di mana pun di dalam aplikasi | Interrupt, keluar, membuka transkrip |
| Chat | Area input utama | Submit, baris baru, editor eksternal, ganti permission mode |
| Confirmation | Dialog permission dan konfirmasi | Ya, tidak, menampilkan penjelasan perintah |
| Scroll | Menggulir percakapan pada fullscreen rendering | Naik dan turun satu halaman, lompat ke bawah, memperluas seleksi |
Sebagian besar default sudah baik. Empat ini yang saya lihat diubah orang lalu dipertahankan:
Ada setting flavour readline yang mengubah satu keluarga default pengeditan teks sekaligus alih-alih mengikatnya satu per satu: tombol hapus kata menghapus sampai whitespace sebelumnya, tombol maju kata berhenti di ujung sebuah kata alih-alih awal kata berikutnya, dan muncul binding hapus sampai ujung kata. Kalau Anda punya memori otot dari shell berbasis readline, satu setting itu lebih berharga daripada rebind individual mana pun.
Inilah mekanisme yang memblokir rebind saya, dan ia layak dipahami alih-alih disiasati. Chord adalah keystroke yang dipisahkan spasi, dan chord mana pun di konteks aktif menahan keystroke pertamanya. Mengambil kembali keystroke itu sebagai binding tombol tunggal berarti melepas setiap chord yang memakainya — dan keluarga bawaannya membentang di dua konteks, jadi melepas hanya yang terlihat menyisakan prefiksnya tetap terpesan.
# Chords are keystrokes separated by a space:
# "ctrl+k ctrl+s" press Ctrl+K, release, then Ctrl+S
#
# The rule that catches people: a chord in ANY active context
# keeps its prefix RESERVED. To reclaim ctrl+x as a single key
# you must unbind every chord that uses it — and the default
# ctrl+x family spans TWO contexts.
{
"bindings": [
{
"context": "Task",
"bindings": { "ctrl+x ctrl+b": null }
},
{
"context": "Chat",
"bindings": {
"ctrl+x ctrl+k": null,
"ctrl+x ctrl+e": null,
"ctrl+x": "chat:newline"
}
}
]
}
# Unbind SOME but not all chords on a prefix and pressing that
# prefix still enters chord-wait mode for the survivors.Tiap pemesanan punya alasan konkret, dan salah satunya fakta tentang terminal alih-alih keputusan siapa pun. Tombol interrupt dan exit dipatri di kode. Yang ketiga terpesan karena terminal mengirim byte yang identik untuknya dan untuk Enter, sehingga mengikatnya terpisah secara fisik tidak mungkin. Dan yang keempat sama sekali tidak pernah diteruskan ke aplikasi terminal.
# Cannot be rebound, and the reasons are worth knowing:
Ctrl+C hardcoded interrupt / cancel
Ctrl+D hardcoded exit
Ctrl+M terminals send an identical byte to Enter (both CR)
Caps Lock never delivered to terminal applications at all
# Conflicts with things that are not Claude Code:
Ctrl+B tmux prefix — press twice to send it through
Ctrl+A GNU screen prefix
Ctrl+Z Unix process suspend
# This is why the background-task action gained the
# ctrl+x ctrl+b chord alongside its ctrl+b default: the chord
# sidesteps the tmux prefix entirely.Tiga lagi bentrok dengan hal di luar Claude Code dan tidak bisa diperbaiki dari file ini. Prefiks tmux dan GNU screen dikonsumsi multiplexer sebelum Claude Code melihatnya — di tmux Anda bisa menekan tombolnya dua kali untuk meneruskannya — dan tombol suspend ditangani shell. Kalau sebuah binding bekerja di luar tmux dan tidak di dalamnya, file-nya bukan masalahnya.
Keduanya beroperasi di lapisan berbeda, dan mengetahui lapisan mana memiliki apa menghemat banyak kebingungan:
Di vim normal mode, dua tombol berperilaku seperti harapan pengguna vim alih-alih seperti perilaku Claude Code biasanya: tanda tanya menampilkan menu bantuan, dan garis miring membuka history search — sama seperti tombol history search di mode standar. Itu konsesi yang disengaja pada memori otot vim, bukan kecelakaan, dan tidak terdokumentasi di tempat yang akan Anda lihat saat mengedit file keybinding.
Claude Code memvalidasi file-nya saat dimuat dan memperingatkan soal error parsing, nama konteks yang tidak valid, nilai action yang tidak valid, bentrokan dengan shortcut terpesan, dan binding ganda dalam satu konteks. Peringatan itu muncul saat file dimuat dan juga ditulis ke debug log, jadi memulai dengan flag debug adalah cara melihat detailnya alih-alih ringkasannya.
Kalau file-nya valid dan binding-nya tetap tidak melakukan apa-apa, penyebab lazimnya adalah konteks lalu pemesanan chord, dengan urutan itu. Periksa bahwa action yang Anda ikat memang ada di konteks tempat Anda meletakkannya — sebuah action chat di blok Global adalah JSON yang valid, nama action yang valid, dan sepenuhnya mati.
Dua hal membuat sistem ini mudah begitu Anda tahu: binding itu tercakup, jadi separuh dari semua kegagalan adalah satu blok di konteks yang keliru, dan chord menahan prefiksnya, jadi separuh sisanya adalah tombol yang tidak sekosong kelihatannya. Selebihnya sekadar pencarian. Pertahankan baris schema di bagian atas file untuk autocompletion, mulai dengan flag debug pertama kali sebuah binding berulah, dan raih setting flavour readline sebelum Anda mengikat ulang pengeditan teks tombol demi tombol.
Sumber & bacaan lanjutan