MacでCornixの長押しCtrlが消えない原因はKarabiner側のMod-Tap設定だった

公開日:
更新日:
目次

先日この記事は「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 系の実装は連続するタップを優先する側に倒れるので、修飾キーとしての長押しは「単発で押し込む」前提で割り当てるのが無難です。

脚注
  1. Karabiner-Elements 公式 - EventViewer (2026-05-23 アクセス) ↩︎