Keychron C3 Proをファームウェアをいじって使いやすくしてみる

はじめに

これまでのPCのキーボード遍歴とその問題点をさらっと復習する。PC-9801シリーズを使っていた大学時代、その後PC/AT互換機に切り替えてしばらくメーカー製PC(IBM, Gateway2000など)を使っていたが、その頃まではPCのキーボードは付属のものを使っていた。その後デスクトップPCを自分で組むようになってからは、キーボードをどうするかという問題が発生した。ということで、最初にキーボードという製品を購入したのは、2002年6月頃にPFU Happy Hacking Keyboardで、手元の記録に残っている最初のキーボードである。(ちなみに結構最近まで非常用に手元に有ったのだが、昨年甥に譲った。)

数年後(多分2005年の中盤? まだ春日部時代だと思うが・・・)、RealForce 106を購入して以来は、ずっとRealForceのユーザーで、R2のUS配列版、R3のJIS配列版を2枚購入して今に至る。

US配列からJIS配列に復帰したのは、2021年発売のRealForce R3からである。これには理由があり、2020年~2023年あたりの在宅勤務によるもの。その頃から自宅作業環境でJIS配列キーボードの会社のラップトップPCと共存しなければならなくなった。OS的には固定されているわけではないのだが、いちいち配列設定をいじるのも微妙に思うので、JIS配列に統一すれば何も考えなくていいじゃんとなった。(故にRealForce R3のJIS配列版を自宅用・会社用に2枚購入したわけである。) まあこういう妥協も必要ということになったのだが、もやもやしつつ最近6年ほど生きてきたのである。

別な方向の話として、何年か前から自作キーボードが流行っている。私は手をまだ出していないわけだが、ファームウェアをいじってって云々という話を会社の仲間内で話をしていたなあというのを思い出し、Open Source Softwareのファームウェアを積んだキーボードがあるのかなと調べてみたら、普通の製品でもありそうということで調べてみることになった。要はキー配置が自由にカスタマイズできるのであれば、あまり妥協しなくていいんじゃないかと。

ということで、QMK Firmwareに対応しているKeychron V3 Pro Redを購入してみた。作りのチープさは感じるけど、Amazon専売?で今セールで5544円となると、これはお買い得なのかもしれない。とは言うのの、結構打鍵していて気持ち良いキーボードではある。キーボードのレビュアーじゃないので深くは立ち入らない。興味の赴く先はファームウェアでどこまでいじれるか?

最近は便利になったもので、ClaudeやChatGPTを用いて調べてみると、Webブラウザベースのファームウェア設定もできるのだが、ファームウェアのコードはKeychronの場合はGithubで公開されているので、Cで書かれたソースを改変してコンパイルすれば良いとのこと。Cでプログラム書かなくなって久しいが、そのあたりもClaudeやChatGPTの助けがあればなんとかなるだろうということで、ファームウェアをいじっていくことになるのである。(実際のところはキーマップをいじるだけだから私でも書けそうな気もする。)

keymapについて

WindowsとMacは微妙に配列の違う箇所があり、この手のキーボードはWindows向けのレイヤーとMac向けのレイヤーが設定されている。何かしらの方法で切り替えることができるようになっている。(C3 Proの場合はFN+CapsLock、他の機種だと物理スイッチ。) ちょっと前までMac使うかもというサブ機の検討をしていたが、これはやめちゃってThinkPad X1 Carbon Gen13を購入したので、もう5年単位でMacを買うことはないであろうということで、このスイッチは別の用途で活用する。

  • WinモードはUSキー配列に設定されたOS(自宅Windows/Linux/FreeBSD)向けにデフォルトのまま使う
  • MacモードはJISキー配列設定のLaptopマシン(会社支給のもの)に接続する際に、OSのキーボード設定をJIS設定のままUS配列の刻印のまま入力できるようにする
  • 調査の結果
    • レイヤごとにUSとかJISという設定はできないようだ
    • Shiftキーを押下したときのの振る舞いはVIAなどでは書き換えられない。
  • defaultkeymapは直接編集せず、qmk new-keymapでhogehogeという専用keymapを作成して編集
  • MAC_BASE/MAC_FNレイヤーを「Mac用」ではなく「JIS設定のWindows専用プロファイル」として転用する方針に決定(Macは当面使わないため)
  • 必要に応じて、2番目以降のレイヤは考える。(将来40%配列とかにしたいですし。)

という感じになる。まとめると、会社支給Laptopは設定を変更せずに(JIS配列設定のままで)、PCのキーボードを使うときはJIS配列のキーボードをそのまま使い、外部キーボードに接続するときはUS刻印のまま入力できるようにする。自宅の環境はUS配列で統一する。結果としてキーボードのスイッチ切り替えで自宅環境と会社支給LaptopはどのパターンでもUS配列の刻印どおり打てるようにしようという試みである。ファームウェアを触る以上、刻印が合わないけど我慢して使うなんて言う選択肢はないのである。

また5000円ちょいのキーボードなら遊んでOKだろうと・・・ では、やってみよう。

環境構築

  • Arch Linux上にuvで隔離したPython環境を作成し、QMK CLI(qmkパッケージ)をインストール
  • クロスコンパイラ(avr-gcc, arm-none-eabi-gcc等)はpacmanでシステムに導入(uvの管轄外)
  • Keychron公式フォークのqmk_firmwareをサブモジュール込みでclone
  • ハマった点: Arch Linux/CachyOS(作業始めた頃はこっちを使っていた)のavr-gccパッケージが/usr/avr/lib/...を探すのに対し、avr-libcパッケージの実体は/usr/lib/avr/lib/...にあり、パス不整合でリンクエラー。sudo ln -s /usr/lib/avr /usr/avrのシンボリックリンクで解決
# 依存パッケージ(クロスコンパイラ等)
sudo pacman -S base-devel avr-gcc avr-libc avrdude arm-none-eabi-gcc arm-none-eabi-newlib dfu-util git

# avr-gcc/avr-libcのパス不整合の解消(CachyOS固有)
sudo ln -s /usr/lib/avr /usr/avr

# プロジェクト用ディレクトリとuv仮想環境
mkdir -p ~/Documents/src/qmk-keychron
cd ~/Documents/src/qmk-keychron
uv init
uv add qmk

# Keychronフォークのclone
git clone --recurse-submodules https://github.com/Keychron/qmk_firmware.git

# QMK CLIの設定と動作確認
uv run qmk config user.qmk_home="$(pwd)/qmk_firmware"
uv run qmk doctor

カスタム用キーマップの作成

uv run qmk new-keymap -kb keychron/c3_pro/ansi/red -km hogehoge

qmk_firmware/keyboards/keychron/c3_pro/ansi/red/keymaps/hogehoge/rules.mkに以下を追記:

KEY_OVERRIDE_ENABLE = yes
VIA_ENABLE = yes

JIS/US記号ズレの解消(本題)

  • 物理配列はUS(ANSI)キートップのまま、Windows側を日本語キーボード(106/109キー)設定にすると、Shiftを押した際の記号(数字段の@^&*()_+等、[]`'まわり)がJISの解釈にズレる問題に対処する
  • QMK公式のkeymap_jp.hを一次資料として、USB HIDコードとJIS文字の対応表を作成
  • 対処方法としてKey Overrides機能(KEY_OVERRIDE_ENABLE = yes)を使い、keymap.cに19個のオーバーライドルールを実装
    • ハマった点1: ko_make_with_layers()等のマクロはデフォルトでトリガーのShiftを自動的に抑制する仕様だったため、Shiftを維持すべき7箇所で意図せずShiftが消えていた。構造体リテラルで.suppressed_mods = 0を明示して解決
    • ハマった点2: Enter脇の\|キー(KC_BSLS)だけ、JIS設定下で]/}として誤認識される問題が発覚。これはANSI配列にのみ存在する物理位置がJIS配列の]キー位置とscancode上で重なるためと判明。KC_INT1(無シフト)/Shift+KC_INT3(シフト)という、JIS配列に実在する専用コードに送り先を変更して解決

記号キーの補正一覧

キー 補正内容
Shift+2 @(Shiftのみ補正)
Shift+6 ^(Shiftのみ補正)
Shift+7 &(Shiftのみ補正)
Shift+8 *(Shiftのみ補正)
Shift+9 ((Shiftのみ補正)
Shift+0 )(Shiftのみ補正)
Shift+- _(Shiftのみ補正)
=(無シフト・Shift双方) = / +
[(無シフト・Shift双方) [ / {
](無シフト・Shift双方) ] / }
'(無シフト・Shift双方) ' / "
Shift+; :(Shiftのみ補正)
`(無シフト・Shift双方) ` / ~
\(無シフト・Shift双方) \ / `

追加改善

  • MAC_BASE/MAC_FNの修飾キー配列をMac配列からWindows配列(KC_LWIN/KC_LALT等)に変更
  • MAC_BASE/MAC_FNのファンクションキー段を、当初Mac用(メディアキーがデフォルト)だったものをWIN_BASE/WIN_FNと同じ配置(F1〜F12がデフォルト)に統一
  • 左右AltキーをMod-Tap化: 長押しでAlt、タップで無変換(KC_INT5)/変換(KC_INT4)。当初KC_MHEN/KC_HENKという名前を使おうとしたが、このQMKバージョンには存在せずKC_INT5/KC_INT4が正しい実体だった
  • VIA対応(VIA_ENABLE = yes)を追加し、VIA/Remap経由でのライブ編集も可能な状態にした。

VIA/Remap運用上の知識

  • VIAのDesignタブ用JSONは「見た目のKeymap」であり、実際のキー割り当てはキーボード本体から読み出される
  • 一度VIA有効な状態で起動するとkeymaps[]の内容がEEPROMにコピーされ、以降はEEPROM優先になる。そのためkeymaps[](キー配置)を変更して再flashする際はBootmagic(Escキー押しながらUSB挿し直し)でEEPROMクリアが必要になる場合がある
  • 一方、key_overridesのようなロジック変更はEEPROMと無関係にflashで即反映される
  • Remapも同じVIAプロトコルで動作するため今回のファームウェアと互換性あり
  • Mod-TapのようなVIA標準UIにないキーコードは、VIAの「Any」キーにQMKのマクロ構文(例: MT(MOD_LALT,KC_INT5))をテキストでそのまま入力すれば設定可能(16進数の手計算は不要)

無変換/変換キーの割り当て方式の検討

左右Altキーは物理的にちょっと押しにくい位置にあるため、無変換/変換の割り当て方式を複数検討・試験的に実装した。

方式1: 左右Alt Mod-Tap(実装済み)

長押しでAlt、タップで無変換/変換。

LALT_T(KC_INT5)  // 左Alt: 長押しでAlt、タップで無変換
RALT_T(KC_INT4)  // 右Alt: 長押しでAlt、タップで変換
  • ハマった点: 当初KC_MHEN/KC_HENKという名前を使おうとしたが、このQMKバージョンには存在せずコンパイルエラー。正しい実体はKC_INT5(無変換)/KC_INT4(変換)だった

方式2: CapsLock長押し+F/J(実装済み、方式1と併用)

CapsLock本来の機能(大文字/小文字切り替え)は使わない前提で、CapsLock位置を恒久的なFnキー(MO(MAC_FN)/MO(WIN_FN))に変更し、そのFN層のCaps/A/S/D/F/G/H/J/K/L段のF/J位置に無変換/変換を割り当て。(これは後に使わない方向になった。)

MO(MAC_FN)  // MAC_BASE側: CapsLock位置を押している間MAC_FN層へ
MO(WIN_FN)  // WIN_BASE側: CapsLock位置を押している間WIN_FN層へ
// 各FN層のCaps/A/S/D/F/G/H/J/K/L段、F位置=KC_INT5(無変換)、J位置=KC_INT4(変換)

ビルド・書き込み

uv run qmk compile -kb keychron/c3_pro/ansi/red -km hogehoge
uv run qmk flash -kb keychron/c3_pro/ansi/red -km hogehoge

書き込み時は、キーボードのリセットボタン(SETボタン)を押しながらUSBを挿し直し、DFU(ブートローダー)モードに入れる。

検討したが見送った/保留の方式

  • VIAの「Any」キーでのライブ設定: QMKのマクロ構文(MT(MOD_LALT,KC_INT5)のようなテキスト)をそのまま入力すれば16進数の手計算なしで設定可能。ただしkeymaps[]の再flash時にEEPROMが上書きされ設定が消えるため、最終的にはkeymap.cに固定する運用とした
  • スペースキー長押し+F/G: 押しやすさの面では魅力的だが、スペースは高頻度キーのためタップ/ホールド判定の誤爆リスクが高く、TAPPING_TERM等の追加チューニングが必要になりそうなため保留
  • Combo機能(2キー同時押し): CapsLockの有無に依存しない移植性の高い方式として案に上がったが、実装は保留

EEPROMがらみの注意点

keymaps[](キー配置そのもの)を変更して再flashする際は、Bootmagic(通常起動時にEscキーを押しながらUSB挿し直し)でEEPROMをクリアしないと、古いキー配置が優先されて反映されないことがある。EEPROMを確実にクリアする手段として、EE_CLRキーコードを一時的に未使用キー(PrintScreenなど)に割り当てて押す方法も有効。

今後の予定

  • 方式1(Alt Mod-Tap)と方式2(CapsLock+F/J)をC3 Proで実際にしばらく使い比べ、どちらが快適か、あるいは併用が良いかを検証
    • これは方式1(Alt Mod-Tap)でほぼ決着している。結局CapsLockキーをCtrlキーと思ってどのソフトでもEmacsキーバインドで移動できるように割り振るレイヤを作ってみる方向に(C-Fがこの場合重なる。)
  • 65%以下のキーボードでの実装方法の検討。

現在の状態

Keychron C3 Pro(ANSI/Red)向けhogehogekeymapは、JIS/US記号の完全対応、無変換/変換キーの2方式(左右Alt Mod-Tap、CapsLock+F/J)を両方実装した状態で完成し、実機での動作確認も完了。この構成(環境構築手順・key_overridesのコード・レイヤー構成)は、他のキーボードでも、個別の調整は必要かもしれないが、同程度の難易度で適用できそうなので、一気にキーボードを切り替えてよいだろう。

実際にその後、会社用にKeychron C1 Max、自宅用にはKeychron Q8 Maxを買ってみて、同様の設定を行っている。(キーが少ないのでより複雑だけど・・・PrintScreenをFN+BackSpaceとかENDをFN+Homeとか、PGupをFN+⇡、PGdnをFN+⇣みたいな割付を追加。さほどの問題ではない・・・(Claudeがコードを書いてくれる))

ということで、ほぼ目算通り。移行可能となった。