目次
先日この記事は「Cornix の Mod-Tap を一度でも踏むとファーム再書き込みでも Ctrl 残留が消えない」というファーム側のバグとして書きました。その後 Windows で再現しないことが分かって原因を調べ直したら、犯人は Mac の Karabiner-Elements の設定でした。ファーム側を疑って丸一日潰したあとに気付いたので、特定の経緯と対処を残しておきます。
Karabiner-Elements の Mod-Tap 相当の設定
結論から書くと、~/.config/karabiner.edn に書いていた次の1行が、delete_or_backspace の長押しを Left Control に変換していました。Cornix 側のファームから Mod-Tap を消しても症状が残ったのは、OS の手前で常に Ctrl を被せ直していたからです。
[:delete_or_backspace :left_control nil {:alone :delete_or_backspace}]
goku の DSL で読み解くと「Backspace を単押しすると Backspace、長押しすると Left Control」という挙動を Karabiner-Elements 側で実装した行です。やっていることは Vial の MT(MOD_LCTL, KC_BSPC) と全く同じで、OS レイヤー版の Mod-Tap になっています。
Windows に挿し替えたら直った時点で気付くべきだった
旧版の記事には「同じ本体・同じファームを Windows に挿し直すと長押しは普通に Backspace の連射になる」と書いていました。Karabiner-Elements は macOS 専用ツールなので、Windows に挿せばこの変換は走りません。
つまり「Mac でだけ起こる」という観察そのものが「Mac 側に何かがある」というシグナルでした。にもかかわらず、最後に触ったのが Cornix のキーマップだったので、ファーム側を疑い続けてしまいました。
物理キーを別位置に振っても Ctrl が効いた理由
旧版で一番不可解だったのが「別の物理キーに KC_BSPC を割り当ててもそのキーも長押しで Ctrl が効く」という挙動でした。これは Karabiner-Elements がキーコードベースで判定していることで説明がつきます。
Cornix 側で物理キーの位置を変えても、OS に届くのは同じ delete_or_backspace です。Karabiner はキーボードのどの位置から来たかではなく、届いたキーコードを見てルールを発火させます。結果として、物理キーを動かしてもこの変換は同じように被ります。
Layer Tap だけ症状が出なかった理由
旧版で「Layer Tap は同じ症状が出なかった」と書いていた点も、karabiner.edn を見ると説明できます。同じファイルに次の行があります。
[:spacebar ["layer1" 1] nil {:afterup ["layer1" 0] :alone :spacebar}]
これは Space をレイヤー切替に使う設定で、変換先が修飾キーではなくレイヤーです。Cornix 側の Layer Tap と挙動が衝突しないので、踏んでも症状が出なかったということでした。
ファーム側で試したことは全部空振りだった
旧版で書いた次のような切り分けは、すべて OS 層に変換が残っていたため空振りでした。
- vial.rocks で当該キーを
KC_BSPCに書き直す - 該当キーを
KC_NOにしてから貼り直す - USB 有線で書き直す
- 公式の
cornix-default-keymap.vilを Load して初期化 - v1.11 ⇄ v1.12 のダウングレード/アップグレード
Mac で操作している限り、最後に Karabiner-Elements が同じ変換を被せるので、ファーム側でいくらキー定義を直しても症状は変わりません。
デバイス条件で Cornix のときだけ Karabiner 側を外す
最初に考えたのは Karabiner-Elements の Mod-Tap 自体をやめる案でしたが、内蔵キーボードや別の外付けキーボードでは長押し Ctrl が便利だったので残したい。goku の :devices と :condi を使うと、特定デバイスのときだけルールを外せます。
{
:devices {
:cornix [
{:vendor_id 57624 :product_id 1} ;; Cornix BLE
{:vendor_id 18003 :product_id 1} ;; Cornix の別接続経路向けフォールバック
]
}
:main [
{
:des "mod-tap (Cornix以外でのみ発火)"
:rules [
[:condi :!cornix]
[:delete_or_backspace :left_control nil {:alone :delete_or_backspace}]
[:return_or_enter :left_shift nil {:alone :return_or_enter}]
]
}
{
:des "layer1+2 (全キーボード共通)"
:rules [
[:spacebar ["layer1" 1] nil {:afterup ["layer1" 0] :alone :spacebar}]
;; レイヤー1のキーマップなどはこちらに残す
]
}
]
}
:condi :!cornix は「Cornix 以外のキーボードのときに発火」という条件です。Cornix を挿すとこのブロックのルールが外れて、Cornix ファーム側の MT(MOD_LCTL, KC_BSPC) がそのまま素通しで OS に届きます。結果として、Cornix では Backspace の連射と長押し Ctrl が両立し、内蔵キーボードや他のキーボードでは従来どおり Karabiner 側の Mod-Tap で長押し Ctrl が効きます。挿し替えるだけで切り替わるので、毎回 Karabiner-Elements の設定をいじる必要はありません。
vendor_id と product_id は実機で異なります。確実なのは Karabiner-EventViewer.app[1] を開いて Cornix を打鍵し、光った行の vendor_id product_id を読むやり方です。BLE と USB で別 ID として認識されるケースがあるので、両方の経路で繋いだ場合は両方を :devices に列挙しておくと安全でした。
Mod-Tap 全般の制約として2連打の2回目は長押し判定にならない
これは Karabiner と Cornix のどちらの Mod-Tap でも共通ですが、Backspace を続けて2回叩いて2回目を長押しすると、Mod-Tap 側はそれを「タップの続き」と判定してしまい、長押し Ctrl が発火しません。Tap-Hold 系の実装は連続するタップを優先する側に倒れるので、修飾キーとしての長押しは「単発で押し込む」前提で割り当てるのが無難です。
Karabiner-Elements 公式 - EventViewer (2026-05-23 アクセス) ↩︎
