続・続・JISplit89を作ってみた

さてこの記事の続き。

JISplit89のLEDを自在に光らせます。

前提としてやりたいこと。
①レイヤー切り替え中は各レイヤーに対応した色にLEDを光らせる
②いろんな色を見比べるモードが欲しい
③デフォルトレイヤーのときはLED調整レイヤー(ADJUSTレイヤー)で指定したLEDパターンで光らせる

難しかった…
LED周りは解説してくれてる人少ないし、マニュアル英語だし…
まあなんとか思い通りのものができたのでよかった。

①レイヤー切り替え中は各レイヤーに対応した色にLEDを光らせる

まずはconfig.hに下記を追加

#define RGBLIGHT_LAYERS

とりあえずレイヤー1、2、3の順にLEDを一括で青、赤、緑にしてみる。
qmk_firmwareリポジトリのkeyboards/jisplit89/rev1/config.hを眺めてみると、どうやらLEDの数は32個らしい(そんなにあったっけ?欠番とかある?)

#define RGBLED_NUM 32

とりあえず、LEDの光らせる配列を作成。
一括で同じ色なのでこう。

 const rgblight_segment_t PROGMEM rgb_default_layer[] = RGBLIGHT_LAYER_SEGMENTS(
   { 0,32, HSV_BLUE}
 );
 
 const rgblight_segment_t PROGMEM rgb_L1_layer[] = RGBLIGHT_LAYER_SEGMENTS(
   { 0,32, HSV_BLUE}
 );

 const rgblight_segment_t PROGMEM rgb_L2_layer[] = RGBLIGHT_LAYER_SEGMENTS(
   { 0,32, HSV_RED}
 );

 const rgblight_segment_t PROGMEM rgb_L3_layer[] = RGBLIGHT_LAYER_SEGMENTS(
   { 0,32, HSV_GREEN}
 );
   
 const rgblight_segment_t* const PROGMEM rgb_layers[] = RGBLIGHT_LAYERS_LIST(
   rgb_default_layer,  // 配列0のためのダミー定義
   rgb_L1_layer,
   rgb_L2_layer,
   rgb_L3_layer
 );

で、レイヤーがセットされたときの関数にレイヤー状態をチェックして対応したLEDのパターンを指定すればよいはず。

layer_state_t layer_state_set_user(layer_state_t state) {
 // LED調整モードの検出
 state = update_tri_layer_state(state, _L1, _L2, _ADJUST);

 // レイヤーによってLED状態を変更
 #ifdef RGBLIGHT_ENABLE
   rgblight_set_layer_state(_L1, state == _L1);
   rgblight_set_layer_state(_L2, state == _L2);
   rgblight_set_layer_state(_L3, state == _L3);
 #endif

 return state;
}

たしかにレイヤー1、2、3に対応したLEDは光ったんだけどADJUSTレイヤーに行ったときに全赤点灯(レイヤー2用)になる…
でもキーの動きはADJUSTレイヤーなのでupdate_tri_layer_stateは効いているはず。

そこでupdate_tri_layer_stateの仕様を公式ドキュメントで調べ始めることに。
ここらへんの公式ドキュメントからレイヤーの仕様を調べていく。

どうやらレイヤーのstateは数値でなくビット配列として使われるらしい。
つまりはレイヤー1がONのときはstateの値は10進数の「1」ではなく、state変数が8ビット(実際はもっと大きかったと思うけど)としたら、

00000010

となっている。
(デフォルトレイヤーをレイヤー番号0として左端から対応するレイヤーのビットが1になる)

デフォルトレイヤーがONならこう。

0000001

update_tri_layer_stateはこの法則でstate変数を書き換える。
つまり、1と2のレイヤー切り替えキーがONのときはstateは、左端が0番目として左から1、2番目のビットが1。

00000110

ADJUSTレイヤーをレイヤー番号4とすると、

state = update_tri_layer_state(state, _L1, _L2, _ADJUST);

update_tri_layer_stateを上記のように使うことでstate変数はレイヤー4をONにして、

00010110

となる。
つまり、レイヤーの状態(state変数)はレイヤー1かつ2かつ4になる。

よって、

   rgblight_set_layer_state(_L1, state == _L1);
   rgblight_set_layer_state(_L2, state == _L2);

は両方stateが一致するので後の方のレイヤー2のパターンがLEDに反映されてしまうということ。
もうちょっと調べるとget_highest_layerって関数があるらしい。
これを使うと一番上位(レイヤー番号が大きい)のレイヤーが取得できるらしい。

なのでこんな感じにすると、ADJUSTレイヤーがONのときは他のrgblight_set_layer_stateに引っかからなくなるので無事にADJUSTレイヤー用のLEDパターンが反映された!

layer_state_t layer_state_set_user(layer_state_t state) {
 // LED調整モードの検出
 state = update_tri_layer_state(state, _L1, _L2, _ADJUST);

 // レイヤーによってLED状態を変更
 #ifdef RGBLIGHT_ENABLE
   rgblight_set_layer_state(_L1, get_highest_layer(state) == _L1);
   rgblight_set_layer_state(_L2, get_highest_layer(state) == _L2);
   rgblight_set_layer_state(_L3, get_highest_layer(state) == _L3);
 #endif

 return state;
}

②いろんな色を見比べるモードが欲しい

MOUSEレイヤーにしたときは全部のLEDを別々の色にしてみようという計画。
LEDはHSV色空間で色を表現する。
docs/feature_rgblight.mdに色名の定義が書かれていたのでそこに書いてる18色+消灯を各LEDに割り当ててみる。

  const rgblight_segment_t PROGMEM rgb_mouse_layer[] = RGBLIGHT_LAYER_SEGMENTS(
   { 0, 1, HSV_WHITE},            // Esc
   { 1, 1, HSV_RED},              // F1
   { 2, 1, HSV_CORAL},            // F2
   { 3, 1, HSV_ORANGE},           // F3
   { 4, 1, HSV_GOLDENROD},        // F4
   { 5, 1, HSV_GOLD},             // F5

   // 6, 7, 8, 9, 10              // LED Tape

   {11, 1, HSV_BLACK},            // Blocker

   {12, 1, HSV_YELLOW},           // F6
   {13, 1, HSV_CHARTREUSE},       // F7
   {14, 1, HSV_GREEN},            // F8
   {15, 1, HSV_SPRINGGREEN},      // F9
   {16, 1, HSV_TURQUOISE},        // F10
   {17, 1, HSV_TEAL},             // F11
   {18, 1, HSV_CYAN},             // F12
   {19, 1, HSV_AZURE},            // Del
   {20, 1, HSV_BLUE},             // PScr

   {21, 1, HSV_PURPLE},           // Home
   {22, 1, HSV_MAGENTA},          // End
   {23, 1, HSV_PINK},             // PgUP
   {24, 1, HSV_BLACK}             // PgDN

   // 25, 26, 27, 28, 29, 30, 31  // LED Tape
 );

消灯(HSV_BLACK)の定義はこれ。

#define HSV_BLACK 0, 0, 0

上記のコメントのキー名はデフォルトキーマップに準ずるやつ。
何度もビルド→反映を繰り返して気づいたのがLEDの32個の中にはLEDテープも含まれていたということ。
(LEDテープは実装してなかったのでなかなか気づけなかった。)
数的には合うのでおそらくこれで合ってるはず。

①と同じように反映する関数を入れればOK

③デフォルトレイヤーのときはLED調整レイヤー(ADJUSTレイヤー)で指定したLEDパターンで光らせる

さて、ここで気付いた(実際は上でうすうすおかしいことに気付いてた)んだけど、レイヤーを切り替えてLEDが切り替わると元のパターンに戻らない…

レイヤー2に切り替え→レイヤー2のLEDパターン
  ↓
レイヤー1に切り替え→レイヤー1のLEDパターン
  ↓
デフォルトレイヤーに戻す→レイヤー1のLEDパターンのまま
  ↓
ADJUSTレイヤーでLEDモード指定→そのモードになる

リセットする何かが必要なはず…

なんかいろいろ調べたらこうすればいいっぽい。

// キーボード初期化後に呼ばれる関数
void keyboard_post_init_user(void) {
 #ifdef RGBLIGHT_ENABLE
   // レイヤーのLED情報を読み込み
   rgblight_layers = rgb_layers;
 #endif
}

キーボード初期化イベント時に呼ばれる関数があるので、そこでレイヤーのLED情報を再指定すればよいみたいね。

これで一通りやりたいことはできた。

キーマップはGitHubにて公開。

この記事が気に入ったらサポートをしてみませんか?