Ghostty で Emacs の undo (C-_) が効かない問題 — kitty keyboard protocol を 0x1F 直送で回避

Ghostty で Emacs の undo (C-_) が効かない問題 — kitty keyboard protocol を 0x1F 直送で回避

ターミナルを Ghostty に乗り換えてから、Emacs で C-_(undo)を押すと

C-_ is undefined

と出るようになりました。Terminal.app では普通に効いていたので、エディタ側の問題ではなくターミナル側のキー送信が変わっているはず — その正体と直し方の話です。

何が起きていたか

Ghostty はデフォルトで kitty keyboard protocol(および modifyOtherKeys)を有効化してキー入力をエンコードします。これは「修飾キー込みでの全キー」をエスケープシーケンスで明示的に伝える仕組みで、TUI 側が対応していれば Ctrl+iTab を区別できる、Shift 単独の検知ができる、といったメリットがあります。

ところが古めの Emacs(あるいは extended protocol 非対応モードで起動した Emacs)は、そのエスケープシーケンスを解釈できません。Terminal.app が昔から送ってきた 生バイト 0x1F だけを C-_ → undo として認識する設定になっているので、新しいエンコードに切り替わった瞬間にバインドが行方不明になり、“C-_ is undefined” という結果になっていました。

直し方:Ctrl+Shift+Minus を 0x1F 直送に上書き

~/.config/ghostty/config に 1 行:

# Emacs の C-_ (undo) を生バイト 0x1F で送る。
# Ghostty デフォルトは modifyOtherKeys / kitty keyboard protocol で
# エスケープシーケンス化するので、emacs (拡張 protocol 未対応モード)
# が認識せず "C-_ is undefined" になる。Terminal.app と同じ古い
# encoding に揃える上書き。
keybind = ctrl+shift+minus=text:\x1f

text:\x1f は「リテラルのバイト 0x1F を送る」という意味の Ghostty 拡張アクション。 これで Ctrl+Shift+- (= C-_)を打つと、エンコードされた kitty/modifyOtherKeys のシーケンスではなく、Emacs が期待している裸の 0x1F がそのまま流れます。Emacs 側は何も変えていません。

なぜ 0x1F なのか

ASCII で _0x5F。一般的な US 配列では _Shift+-。これに Ctrl を合わせた “control character” がちょうど 0x1F(最上位の方を 0 にして 0x40 を引いた値)になります。Terminal.app は Ctrl+Shift+- を踏むと そのまま 0x1F 1 バイトだけ を送るので、Emacs はそれを (undefined-key 0x1f) ではなく C-_ として受け取り、undo にディスパッチできる、というだけのことでした。

いつこの修正は不要か

逆に、kitty / Ghostty / WezTerm modern モードに乗り換えて Emacs の C-/C-_ が突然効かなくなったら、まずこの「ターミナル側がエスケープ化してエディタが復号できていない」を疑うのが早いです。同じ理由で他の C- 系バインドが拾われない場合も、Ghostty の keybind = ... = text:\xNN で個別に逃がせます。

この記事をシェア

関連記事

記事一覧に戻る