QMKの環境構築～レイヤ毎にLEDの光り方を変える

# 目次
* [QMKの環境構築](#anchor1)
* [自分用keymapの作成](#anchor2)
* [ファーウェアのコンパイルと書き込み](#anchor3)
* [自分用keymapの編集](#anchor4)
* [レイヤー毎のRGBLEDの設定](#anchor5)
* [おまけ](#anchor6)


<a id="anchor1"></a>
# QMKの環境構築
※この記事では[QMK Toolbox](https://github.com/qmk/qmk_toolbox/releases)を使いません。コマンドライン操作でコンパイルやProMicroへの書き込みができるようになることを目標とします。また、Windowsでの環境構築の解説なので、macOSの場合適宜読み替えてください。

### 1. ともあれ、[QMK Firmware](https://github.com/qmk/qmk_firmware)をForkする
https://github.com/qmk/qmk_firmware

### 2. QMK MSYSのインストールとセットアップ
https://msys.qmk.fm/

[QMK MSYS](https://msys.qmk.fm/)の[最新バージョン](https://github.com/qmk/qmk_distro_msys/releases/latest)をダウンロード&インストール。</br>
インストールしたQMK MSYSを開き、

```
$ qmk setup <github_username>/qmk_firmware --home C:\<path>\qmk_firmware
```

でセットアップを行う。
`--home`でQMK Firmwareをcloneしたパスを指定して初期設定が完了。途中いくつかの確認項目は基本的に`Y`で進める。</br>
単に
```
$ qmk setup
```
を行うと本家リポジトリをクローンして環境構築する。

### 3. 構築した環境をテストしてみよう

#### 手元のキーボード用のデフォルトキーマップをコンパイルしてみる。
```
$ qmk compile -kb <keyboard> -km default
```

`<keyboard>`の部分にはファームウェアを書き込む対象のキーボード名が入る。QMKに登録されたキーボードのリストは[ここ](https://github.com/qmk/qmk_firmware/tree/master/keyboards)から確認できる。
例えば、[crkbd](https://shop.yushakobo.jp/products/corne-cherry-v3)のデフォルトキーマップをコンパイルする場合、
`$ qmk compile -kb crkbd/rev1 -km default`
とすればOK。
長いログの後、特にエラーを吐かず` * The firmware size is fine - *****/***** (**** bytes free)`とメッセージが表示されたらコンパイルは無事に完了。QMK MSYSは無事にセットアップできたといえる。

#### デフォルトのキーボードとキーマップを設定ファイルに書き込んでおく

```
$ qmk config user.keyboard=<keyboard>
$ qmk config user.keymap=<github_username>
```

とすることで`~\AppData\Local\QMK.EXE\qmk.exe\qmk.exe.ini`内に上で指定した`<keyboard>`と`<github_username>`が記述され、コンパイルなどの際に都度`-kb`や`-km`でキーボードやキーマップを指定する必要がなくなる。

<a id="anchor2"></a>
# 自分用keymapの作成
以下、`qmk config`で設定したキーボード、キーマップをそれぞれ使用するため`-kb` `-km`オプションの記述は省略する。

```
$ qmk new-keymap
```

をすると、`Ψ <github_username> keymap directory created in: <path>/qmk_firmware/keyboards/crkbd/keymaps/<github_username>`と表示され、自分のGithubユーザー名のkeymapを含むディレクトリがが新規作成される。


<a id="anchor3"></a>
# ファームウェアのコンパイルと書き込み

### 1. コンパイル
自分用のkeymapの作成が完了したところで一度コンパイルをしてみよう。

```
$ qmk compile
```

うまくいけば先ほどと同様` * The firmware size is fine - *****/***** (**** bytes free)`と表示され、新しく作ったkeymapでPro Micro用のファームウェアがコンパイルされた。おめでとうございます。

### 2. 書き込み
続けて、

```cmd
$ qmk flash
```

でコンパイルしたファームウェアをPro Microに書き込む。
`Waiting for USB serial port - reset your controller now (Ctrl+C to cancel)...`と表示され書き込み待機状態になったらPro Microのリセットスイッチを押す。
一通りの読み出し/書き込みの後、一番最後に`Thank you.`と表示されれば書き込みは成功。


<a id="anchor4"></a>
# 自分用keymapの編集
ここからが本番。先程作成したキーマップを好みのエディタで開く。</br>
場所は`<path>/qmk_firmware/keyboards/<keyboard>/keymaps/<github_username>/keymap.c`。
以下はLily58キーボードの例である。

```c:keymap.c
#include QMK_KEYBOARD_H

enum layer_number {
  _QWERTY = 0,
  _LWR,
  _RSE,
  _ADJ,
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

 [_QWERTY] = LAYOUT(
   // ,-----------------------------------------------------.                    ,-----------------------------------------------------.
        KC_GESC,    KC_1,    KC_2,    KC_3,    KC_4,    KC_5,                         KC_6,    KC_7,    KC_8,    KC_9,    KC_0,  KC_EQL,
   // |--------+--------+--------+--------+--------+--------|                    |--------+--------+--------+--------+--------+--------|
         KC_TAB,    KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,                         KC_Y,    KC_U,    KC_I,    KC_O,    KC_P, KC_MINS,
   // |--------+--------+--------+--------+--------+--------|                    |--------+--------+--------+--------+--------+--------|
        KC_LCTL,    KC_A,    KC_S,    KC_D,    KC_F,    KC_G,                         KC_H,    KC_J,    KC_K,    KC_L, KC_SCLN, KC_QUOT,
   // |--------+--------+--------+--------+--------+--------+--------.  ,--------+--------+--------+--------+--------+--------+--------|
        KC_LSFT,    KC_Z,    KC_X,    KC_C,    KC_V,    KC_B, KC_LBRC,    KC_RBRC,    KC_N,    KC_M, KC_COMM,  KC_DOT, KC_SLSH, SFT_T(KC_BSLS),
   // `--------------------------+--------+--------+--------+--------|  |--------+--------+--------+--------+--------------------------'
                                   KC_LALT, KC_LCTL,C(KC_SPC), KC_SPC,     KC_ENT, KC_BSPC,MO(_LWR), KC_RGUI
   //                            `-----------------------------------'  `-----------------------------------'
),

[_LWR] = LAYOUT(
… // 省略
```
キーマップは`uint16_t`型の配列になっており、レイヤーごとにキーマップを好みに設定できる。
`KC_`から始まるキーコードが一般的なアルファベットや記号、数字から音量の調節、マウスキーまで多様に割り振られており、実際のキーボードの配列を模したものの中に自由に記述してゆく。使用可能なキーコード一覧は[QMK公式ドキュメント](https://beta.docs.qmk.fm/using-qmk/simple-keycodes/keycodes)を参照。
レイヤーの移動には`MO(layer)`(押している間のみレイヤーを移動)や`TO(layer)`(押すたびにレイヤーをトグル)などを使う。`MO(layer)`を使用する場合は、移動先のレイヤーの同じキーに`KC_TRNS`あるいは`_______`を指定する。
マウスキーやメディア音量の調節を割り当てる場合、`rules.mk`内で`MOUSEKEY_ENABLE = yes`
や`EXTRAKEY_ENABLE = yes`として機能を有効化する必要があるので注意。

<a id="anchor5"></a>
# レイヤー毎のRGBLEDの設定
viaやRemapに対応したキーマップではプリセットとして幾つかのLEDアニメーションを切り替えることができるようになっているが、ここでは自分が今どのレイヤーにいるのか判別しやすくするために、レイヤーと同時に切り替わるLEDのマッピングを解説する。

### 1. キーボードに実装したLEDの個数などの定義

```c:config.h
#define RGBLIGHT_LAYERS // 機能の有効化
#define RGBLED_NUM 50 // LEDの個数
#define RGBLED_SPLIT { 25, 25 } // (分割キーボードの場合)左右それぞれに実装したLEDの個数
#define RGBLIGHT_MAX_LAYERS 8 // (最大32)
```

### 2. 各LEDの位置を判別しやすくするために番号を振る
多くのキーボードではPro Microから始まり数珠繋ぎになったLEDがS字、あるいはZ字に並んでいる。これは電気回路的な配置の話であり、任意のLEDの位置を指定してその光り方をカスタムするには分かりづらく不都合である。そこで、例えば1行目から各行ごとに左→右となるようにLEDの番号を振り直す。
`config.h`を開き、`#define LED_LAYOUT()`マクロを作成する。以下に示すのはHelixキーボードの例である。

```c:config.h
#define LED_LAYOUT( \
L00, L01, L02, L03, L04, L05,             R00, R01, R02, R03, R04, R05, \
L10, L11, L12, L13, L14, L15,             R10, R11, R12, R13, R14, R15, \
L20, L21, L22, L23, L24, L25,             R20, R21, R22, R23, R24, R25, \
L30, L31, L32, L33, L34, L35, L36    R30, R31, R32, R33, R34, R35, R36 )
{ \
    L05, L04, L03, L02, L01, L00, \
    L10, L11, L12, L13, L14, L15, \
    L25, L24, L23, L22, L21, L20, \
    L30, L31, L32, L33, L34, L35, L36, \
    \
    R00, R01, R02, R03, R04, R05, \
    R15, R14, R13, R12, R11, R10, \
    R20, R21, R22, R23, R24, R25, \
    R36, R35, R34, R33, R32, R31, R30 }
```

前方`()`で囲まれた部分には物理的なキーそのもののレイアウトが入り、例えば`L13`なら左手1行3列のキーであることを示す。ここで注意するのは行列のインデックスが1ではなく0から始まっているということ。`L13`は、左から数えて4つ目、上から数えて2つ目のキーである。
後方`{}`で囲まれた部分にはLEDの電気回路的な並び順が入る。HelixキーボードではLEDがZ字に並んでいるため、それに対応した順を記述する。
次に、それぞれのLEDに任意の番号を振るために`RGBLIGHT_LED_MAP`マクロを定義する。

```c:config.h
#define RGBLIGHT_LED_MAP LED_LAYOUT( \
     0,  1,  2,  3,  4,  5,            19, 20, 21, 22, 23, 24, \
     6,  7,  8,  9, 10, 11,            25, 26, 27, 28, 29, 30, \
    12, 13, 14, 15, 16, 17, 18,    31, 32, 33, 34, 35, 36, 37 )
```

これで`config.h`の編集は完了。ここで振った`0`~`37`までの番号をLEDのインデックスとして`keymap.c`内で使用する。

### 3. レイヤ毎のLEDの光り方を指定する
`keymap.c`に記述する。

`rgblight_segment_t`型の配列を宣言し、先ほど割り振ったインデックスの順に必要な個数ずつ色を指定してゆく。
なお、`config.h`内で定義した`RGBLED_NUM`マクロで指定したものと同数を割り当てないとコンパイルエラーが出るので注意すること。

```c:keymap.c

#ifdef RGBLIGHT_LAYERS
const rgblight_segment_t PROGMEM rgb_layer_1st[] = RGBLIGHT_LAYER_SEGMENTS(
    {0, 1, HSV_RED}, // 開始LEDインデックス, 連続する個数, 光らせる色(ここではプリセットを使用)
    {1, 5, HSV_GREEN}, {6, 3, HSV_OFF}, … // 省略
);

const rgblight_segment_t PROGMEM rgb_layer_2nd[] = RGBLIGHT_LAYER_SEGMENTS(
    // 省略
);

const rgblight_segment_t PROGMEM rgb_layer_3rd[] = RGBLIGHT_LAYER_SEGMENTS
    // 省略
);

const rgblight_segment_t PROGMEM rgb_layer_4th[] = RGBLIGHT_LAYER_SEGMENTS
    // 省略
);
```
必要なレイヤーの数だけ配列を宣言し、LEDのマッピングをする。

続けて、上で用意したLEDのレイヤーとキーマップのレイヤーを対応づけるために以下を記述する。

```c:keymap.c
const rgblight_segment_t* const PROGMEM rgb_layers[] = RGBLIGHT_LAYERS_LIST(
    rgb_layer_1st,
    rgb_layer_2nd,
    rgb_layer_3rd,
    rgb_layer_4th
);

void keyboard_post_init_user(void) {
    rgblight_layers = rgb_layers;
}

layer_state_t layer_state_set_user(layer_state_t state) {
    rgblight_set_layer_state(0, layer_state_cmp(state, _QWERTY));
    rgblight_set_layer_state(1, layer_state_cmp(state, _LWR));
    rgblight_set_layer_state(2, layer_state_cmp(state, _RSE));
    rgblight_set_layer_state(3, layer_state_cmp(state, _ADJ));
    return state;
}

#endif // RGBLIGHT_LAYERS
```
ここで注意するべきは、キーボード毎のファームウェアによって配列の名前が異なっている場合が多いということ。コンパイルに失敗する場合は、上のコードでの`rgb_layer_xxx`, `_QWERTY`, `_LWR`に当たる部分などを今一度見直してみてほしい。

<a id="anchor6"></a>
# おまけ: 左右問わずUSB接続を可能にする
分割型のキーボードではUSBケーブルを挿したPro Microをマスター、TRRSケーブルで接続されたPro Microがスレーブと呼ぶ。
大抵の分割型キーボードではデフォルトの状態で常にマスター側を左手と認識している。
つまり右手のPro MicroにUSBを挿してしまうと、分割されたキーボードが左右反転して認識されてしまい、キーボードとして使うことができない。デスク上のケーブルの取り回しの問題で右手側にUSBケーブルを接続、あるいは状況によって左右どちらのPro MicroにUSB接続してもそれぞれの手を正しく認識するように設定してみよう。
これにはいくつかの方法があるが、ここではPro Micro上のEEPROMに右手側であること、左手側であることをそれぞれ書き込む方法を記述する。

作成した自分のキーマップ内の`config.h`には以下の項目がある。

```c:config.h
/* Select hand configuration */

#define MASTER_LEFT
// #define MASTER_RIGHT
// #define EE_HANDS
```

常にマスターを左側として認識するのは`#define MASTER_LEFT`とされているからである。
3つ目の`#define EE_HANDS`を有効にするために以下のように書き換える。

```c:config.h
/* Select hand configuration */

// #define MASTER_LEFT
// #define MASTER_RIGHT
#define EE_HANDS
```

これでコンパイル、書き込みを行う。

次に、それぞれのPro Microに搭載されたEEPROMに左手 右手の情報を書き込む。
左手 `C:\<path>\qmk_firmware\quantum\split_common\eeprom-lefthand.eep`
右手 `C:\<path>\qmk_firmware\quantum\split_common\eeprom-righthand.eep`
QMK MSYS上であらかじめ`C:\<path>\qmk_firmware\quantum\split_common`に移動しておく。

```
$ cd C:\<path>\qmk_firmware\quantum\split_common
$ avrdude -p atmega32u4 -P $(COM_PORT) -c avr109  -U eeprom:w:eeprom-lefthand.eep
```

ここでEnterキーを押す直前にPro Microのリセットスイッチを押して待機状態にする。
うまくいけば右手も同様に

```
$ avrdude -p atmega32u4 -P $(COM_PORT) -c avr109  -U eeprom:w:eeprom-righthand.eep
```

これで左右どちらのポートにケーブルを接続しても正しく左右を認識するようになった。