Keychron Q9 Plus のレビュー & QMK Firmware におけるレイヤーの追加

## Keychron Q9 Plus のレビュー
### 購入したモデル
- Keychron Q9 QMK Custom Mechanical Keyboard
- Fully Assembled Knob (Plus Version)
- Silver Gray
- Keychron K Pro Red
- $149

### 良い点
- とても良い打鍵感 (ここは非常に主観的な感想)
  - HHKB や REALFORCE にあるような押し込むような打鍵感 (スコスコした感じ) というよりは、より軽い感触
  - 重い本体による安定感
    - これで殴られたら死ぬだろうと思われるほど重く、キー操作がキーボード本体に与える振動が小さい。
  - ダブルガスケットデザインの効果はあまり良くわからない。
    - 目に見えるほど押し込むためには相当の力が必要なので、どちらかといえば静音性に貢献するための特徴なのかもしれない。
- 分割スペースキーに加え、スペースキーの左側にキーが4つもあるため、レイヤーの切り替え等を割り振る際の自由度が高い。
  - 矢印キーを除いて、一番下の行に 9個のキーがあり、Keychron ではたぶんこれが最多だと思われる。

### 良くない点
- 矢印キーとHomeキーとロータリエンコーダは多分必要ない。
  - 40% キーボードの利点は、最小限の手の動きで操作を行えることであり、これらのキーはこの理念に反している。
  - これらのキーとロータリエンコーダがなければ、1列分の幅を短縮することができるはず。
  - ロータリエンコーダは面白いのであってもいいと思うが、なくて困るという人はいないのではなかろうか。
- レイヤーが足りない。
  - 数字キーが非デフォルトレイヤーに侵食する影響で、60% キーボードと比べるとキーマップは窮屈になる。
  - デフォルトレイヤー、数字 + FNレイヤー、矢印キー+ Home + End + Delete レイヤーにすると、ポインティングデバイス (マウス) を操作するためのレイヤーが足りなくなる。
  - この問題は記事の後半で解決する。
  

## QMK Firmware におけるレイヤーの追加
- 前述の通り、Keychron Q9 Plus は、数字キーが非デフォルトレイヤーに侵食する関係でやや窮屈なキーマップになる。
- デフォルトでレイヤーは5枚あり、そのうちモード1 (Winモード) とモード2 (Macモード) それぞれに固有のレイヤーが2枚ずつ割り当てられている。
  - (どちらかのモードを潰せばファームウェアの書き換えなしに実現できるが、そういうことはしたくない)
- そのため、本体側面のDIPスイッチを切り替えることなく操作できるレイヤーは 3枚となる。
- 3枚は少ないと感じたので追加する。

### 手順
- QMK ファームウェアのリポジトリをクローンし、ビルドする。
  - 以下の状態ではレイヤーが 1枚増えて 6枚となる。
```
$ git clone https://github.com/void-hoge/qmk_firmware.git
$ cd qmk_firmware
$ make keychron/q9_plus/ansi_encoder:default
```
- できたファイルを内部のメモリに書き込む。
  - ユーザーガイドに従って書き込む。
  - https://www.keychron.com/pages/keychron-q9-plus-user-guide
  - 直接書き込めるのかもしれないが、私はユーザーガイドに貼ってあるフラッシュツールを使った。(Mac と Windows にのみ対応)
  
### 変更点
- マクロ `DYNAMIC_KEYMAP_LAYER_COUNT`の値を増やす。
  - デフォルトで5なので、6で上書きする。
  - `keyboards/keychron/q9_plus/ansi_encoder/config.h` の一番下に以下の一行を追加する。
```c
#define DYNAMIC_KEYMAP_LAYER_COUNT 6
```

- `keyboards/keychron/q9_plus/ansi_encoder/keymap/default/keymap.c`のレイヤーの識別子っぽい列挙体に適当に (固有の) レイヤー名をつける。
```c
enum layer{
	MAC_BASE,
	WIN_BASE,
	MAC_FN1,
	WIN_FN1,
	FN2, // ,を追加
	FN3  // 追加 (名前が被っていなければ何でも良い)
}
```
- キーマップを適当に増やす。
  - あとで VIA を使ってで変更できるので、今は上のレイヤーからコピーする。
```c
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    [MAC_BASE] = LAYOUT_54_ansi(
        KC_TAB,  KC_Q,     KC_W,     KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,     KC_LBRC,     KC_RBRC,  KC_BSLS,          KC_MUTE,
        KC_CAPS, KC_A,     KC_S,     KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN,  KC_QUOT,               KC_ENT,           KC_HOME,
        KC_LSFT,           KC_Z,     KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,   KC_SLSH,               KC_RSFT, KC_UP,
        KC_LCTL, KC_LOPT,  KC_LCMD,  MO(MAC_FN1),      KC_SPC,                    KC_SPC,           KC_RCMD,  MO(MAC_FN1), MO(FN2),  KC_LEFT, KC_DOWN, KC_RGHT),

    [WIN_BASE] = LAYOUT_54_ansi(
        KC_TAB,  KC_Q,     KC_W,     KC_E,    KC_R,    KC_T,    KC_Y,    KC_U,    KC_I,    KC_O,    KC_P,     KC_LBRC,     KC_RBRC,  KC_BSLS,          KC_MUTE,
        KC_CAPS, KC_A,     KC_S,     KC_D,    KC_F,    KC_G,    KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN,  KC_QUOT,               KC_ENT,           KC_HOME,
        KC_LSFT,           KC_Z,     KC_X,    KC_C,    KC_V,    KC_B,    KC_N,    KC_M,    KC_COMM, KC_DOT,   KC_SLSH,               KC_RSFT, KC_UP,
        KC_LCTL, KC_LWIN,  KC_LALT,  MO(WIN_FN1),      KC_SPC,                    KC_SPC,           KC_RALT,  MO(WIN_FN1), MO(FN2),  KC_LEFT, KC_DOWN, KC_RGHT),

    [MAC_FN1] = LAYOUT_54_ansi(
        KC_GRV,  KC_BRID,  KC_BRIU,  KC_MCTL, KC_LPAD, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE,  KC_VOLD,     KC_VOLU,  _______,          RGB_TOG,
        RGB_TOG, RGB_MOD,  RGB_VAI,  RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______,  _______,               _______,          _______,
        _______,           RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, NK_TOGG, _______, _______, _______,  _______,               _______, _______,
        _______, _______,  _______,  _______,          _______,                   _______,          _______,  _______,     _______,  _______, _______, _______),

    [WIN_FN1] = LAYOUT_54_ansi(
        KC_GRV,  KC_BRID,  KC_BRIU,  KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE,  KC_VOLD,     KC_VOLU,  _______,          RGB_TOG,
        RGB_TOG, RGB_MOD,  RGB_VAI,  RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______,  _______,               _______,          _______,
        _______,           RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, NK_TOGG, _______, _______, _______,  _______,               _______, _______,
        _______, _______,  _______,  _______,          _______,                   _______,          _______,  _______,     _______,  _______, _______, _______),

    [FN2] = LAYOUT_54_ansi(
        KC_TILD, KC_F1,    KC_F2,    KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,   KC_F11,      KC_F12,   KC_BSPC,          _______,
        KC_ESC,  KC_1,     KC_2,     KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,     _______,               _______,          _______,
        _______,           _______,  _______, _______, _______, _______, _______, _______, _______, _______,  _______,               _______, _______,
        _______, _______,  _______,  _______,          _______,                   _______,          _______,  _______,     _______,  _______, _______, _______), // ,を追加

	// ここから追加
	//↓ 上でつけたレイヤー名
	[FN3] = LAYOUT_54_ansi(
        KC_TILD, KC_F1,    KC_F2,    KC_F3,   KC_F4,   KC_F5,   KC_F6,   KC_F7,   KC_F8,   KC_F9,   KC_F10,   KC_F11,      KC_F12,   KC_BSPC,          _______,
        KC_ESC,  KC_1,     KC_2,     KC_3,    KC_4,    KC_5,    KC_6,    KC_7,    KC_8,    KC_9,    KC_0,     _______,               _______,          _______,
        _______,           _______,  _______, _______, _______, _______, _______, _______, _______, _______,  _______,               _______, _______,
        _______, _______,  _______,  _______,          _______,                   _______,          _______,  _______,     _______,  _______, _______, _______)
	// ここまで
};

#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
    [MAC_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
    [WIN_BASE] = {ENCODER_CCW_CW(KC_VOLD, KC_VOLU)},
    [MAC_FN1]  = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
    [WIN_FN1]  = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI)},
    [FN2]      = {ENCODER_CCW_CW(_______, _______)}, // ,を追加
	//↓上でつけたレイヤー名
	[FN3]      = {ENCODER_CCW_CW(_______, _______)}  // 追加
};
#endif
```

- この方法で何枚までレイヤーが増やせるのかはよくわからない。
  - VIA のレイヤーキーが9まであるので、たぶん10枚までは行ける気がする。

## VIAの設定
- レイヤー 0
  - バックスラッシュ → バックスペース
  - Caps → LCtrl
  - 左下から MO(4), LCmd, LOpt, MO(5), Space, MO(2), RCmd, MO(2), MO(4)
- レイヤー 1
  - バックスラッシュ → バックスペース
  - Caps → LCtrl
  - 左下から MO(4), LWin, LAlt, MO(5), Space, MO(3), RAlt, MO(3), MO(4)
- レイヤー 2, 3
  - 左上から、チルダ、数字キー、バックスペース
  - その下に F1~F12
- レイヤー 4
  - A → Home
  - E → End
  - D → Del
  - FBNP → Right, Left, Down, Up
  - K → Macro0
    - Macro0: Emacs の kill-line をエミュレート
- レイヤー 5
  - WASD → ポインタの上下左右
  - NP → スクロール
  - JKL → 左クリック、ホイールクリック、右クリック
- ロータリエンコーダ
  - スクショ、RGB等

- https://github.com/void-hoge/viakeymaps/blob/main/keychron_q9_plus_ansi_knob.layout.json

## 総評
- 配列に慣れるため多少練習が必要なので、短期的な生産性の向上が目的ならばこれを買うべきではない。
  - 十分に慣れた状態でも 60% 以上の配列のキーボードを生産性で上回れるかというのも微妙な気がする。
  - キーボードのカスタマイズや、特殊なキー配列でのタイピングを楽しむことが目的の1つであるならば、40% はとても楽しく、練習しがいのある配列だと思う。
  - 私にとっては初めての 40% キーボードだが、所有している他のキーボードと同じような水準まで慣れるために 2週間程度を要した。
- 非常にカスタマイズ性が高く、ロータリエンコーダのような遊びもある、楽しいキーボードだと思う。