続・続・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にて公開。
この記事が気に入ったらサポートをしてみませんか?