2年ほど前に key-chord が0.8.2 にアップデートされてから動かなくなってハマったので原因と解決策をメモしておきます。
症状
自分の設定はこんな感じでした。
(leaf key-chord
:ensure t
:hook (after-init-hook . key-chord-mode)
:chord (("l;" . init-loader-show-log))
:config
;; key-chordが固まった時の復帰処理
(defun my-key-chord-ensure ()
(when (and key-chord-mode
(not (eq input-method-function 'key-chord-input-method)))
(key-chord-mode -1)
(key-chord-mode 1)))
(add-hook 'input-method-activate-hook #'my-key-chord-ensure)
(add-hook 'input-method-deactivate-hook #'my-key-chord-ensure))
l; と入力しても、ただの2文字 l ; がそのまま挿入されるだけ。コードは発火せず、エラーも *Messages* への出力も一切なし。何が起きているのか手がかりがまったくない状態でした。
原因
調べてわかったのは、leaf の :chord キーワード(use-package-chords/bind-chord.el も同様)が、内部的に key-chord-define や key-chord-define-global を呼ぶのではなく、[key-chord K1 K2] という内部表現のベクタに対して素の define-key でバインドしている、ということでした。
一方で key-chord-use-key-tracking というオプションがデフォルトで t(有効)になっていて、これが有効だと key-chord-keys-in-use という追跡用のベクタに登録されているキーしかコード判定の対象にしません。この key-chord-keys-in-use は key-chord-define 系の関数を経由したときにしか更新されないため、leaf の :chord のように define-key で直接バインドしたコードは、そもそも追跡対象として認識されません。結果として key-chord-input-method は2文字目を読みにいく前の時点で「このキーは対象外」と判断して処理を打ち切ってしまい、コードが一切発火しなくなります。
実際に以下で確認できました。
(message "tracked? l=%S ;=%S" (aref key-chord-keys-in-use ?l) (aref key-chord-keys-in-use ?\;))
;; => nil nil
見ての通り nil です。l も ; も追跡対象に入っていません。
解決策
1行追加するだけで直りました。
(leaf key-chord
:ensure t
:hook (after-init-hook . key-chord-mode)
:chord (("l;" . init-loader-show-log))
:config
(setq key-chord-use-key-tracking nil) ;; <- これ
;; key-chordが固まった時の復帰処理
(defun my-key-chord-ensure ()
(when (and key-chord-mode
(not (eq input-method-function 'key-chord-input-method)))
(key-chord-mode -1)
(key-chord-mode 1)))
(add-hook 'input-method-activate-hook #'my-key-chord-ensure)
(add-hook 'input-method-deactivate-hook #'my-key-chord-ensure))
key-chord-use-key-tracking を nil にすると、追跡ベクタを使った高速判定をやめて、毎回フルチェック(key-chord-lookup-key)に戻るだけなので、レスポンスへの影響はほぼ気にならないレベルです。
まとめ
-
leafの:chordやuse-package-chordsで定義したコードが、アップデート後に急に動かなくなったらkey-chord-use-key-trackingを疑ってみてください -
(setq key-chord-use-key-tracking nil)を1行足すだけで直ります - このコードベースに詳しいわけではないので「正しい」修正がどうあるべきかはわかりませんが(デフォルトを
nilにする?key-chord-mode有効化時に既存のキーマップから追跡ベクタを構築する?など)、同じ症状で時間を溶かす人が減ればと思い記録しておきます