[自作キーボード]QMKファームウェアでシリアルLED(WS2812B)に対応する ~Lighting Layers機能~

目次

Abstract

  • 前回記事に続いてQMKでシリアルLEDを使う記事
  • Lighting Layers機能を使ってみる
  • ソースコードは前回記事の続きから

Introduction

前回はLED用の操作関数直接叩いて制御してましたが、今回はLighing Layer機能と呼ばれるレイヤでLEDを管理する機能を使おうと思います。Lighting Layer機能はLED設定をレイヤ管理できる機能で、Capsロック状態のとき用、特定のキーレイヤに移動してる時用などLEDの発光(配色)パターンをあらかじめ作っておき、状態に合わせて切り替えることができます。 RGB Lightingのレイヤ機能については以下のページに詳細があるので、それに従って作成していきます。

QMK Doc, Lighting Layers
 ※ただ、RGB Lightningのページではinfo.json使わない古い記載方法しかないので、そちらはinfo.json Referenceのページを参考にしてます

Lighting Layerの概要

↑のリンク記載されてますので詳細はそちらに。概要は以下

  • 機能
    • RGB Light機能で管理している全てのLEDの色設定をレイヤごとに管理することができます
    • 最大32のレイヤを持つことができる
  • 注意点
    • RGB Light機能との組み合わせでのみ使用可能
      • RGB Matrix機能との組み合わせは不可

QMK Documentsに実行例の動画が載ってたので参考まで
Youtube: Lighting Layers in QMK on an ErgoDash

Method

試すために必要なことは以下の3つです。

  1. Lightingレイヤー機能の有効化
  2. Lightingレイヤーの作成、設定
  3. 状態に応じたLayerの制御

1. Lighting Layer機能の有効化

  • info.json内のrgblight - layersキーでenabledをtrueにして有効化します。
  • また、同じキー内でレイヤーの最大数(max),blink機能の有効無効も定義できます
    • blink機能は使う予定無いのでここではfalseにしてます

info.json

    "rgblight": {
        "led_count": 2,
        "layers": {
            "blink": false,
            "enabled": true,
            "max": 8,
        }
    },

2. Lighting Layerの設定

  • keymap.c内に定義します。
  • 個別のLighting LayerとそれらのLightingレイヤーを格納するレイヤーリストの定義、起動時の初期レイヤーの設定が必要です

Lighting Layer

  • Layerの名前、そのLayerにしたときの各LEDのHSV設定をします。
  • layerの名前
    • 特に制約は無いです。
    • 例では初期Layerとして、default_layer, caps_lock状態のLayerとしてcapslock_layerの2つを定義しています
  • Layern内の各LEDのHSV設定
    • RGBLIGHT_LAYER_SEGMENTSマクロを使って定義します。
    • 定義方法は以下
      • {start_index, end_index, hue, sat, val}
        • start_index ~ end_index間のLEDに対してHSVの設定をします。
        • 実装している全てのLEDにセットも可能ですし、一部だけ配色をオーバーライドするみたいなことも可能です。
          • レイヤ切り替えで数字行だけFn1-12に置き換えしてるときに、数字行だけ色変えするとかも可能
        • 1つの{}で全LEDを設定してもよいですし、複数に分けて設定しても良いです。
          • 例ではdefaultレイヤは全LEDを一括で設定、4番目のLEDだけを赤色にオーバーライドしてます。

keymap.c

// キーレイヤ名の定義
enum {
    DEFAULT_LAYER,
    CAPSLOCK_LAYER
};

// デフォルトのLighting Layer (全LEDを白色設定)
const rgblight_segment_t PROGMEM default_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {0, 8, 0, 0, 94}
);

// CapsLock用のLighting Layer (4番目のLEDだけ赤色でオーバーライド)
const rgblight_segment_t PROGMEM capslock_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {3, 1, 0, 255, 200}
);

Lighting Layerリスト

  • RGBLIGHT_LAYERS_LISTマクロを使って定義します
  • やることとしては、個別に定義したLightingLayerを格納するだけです

keymap.c

const rgblight_segment_t* const PROGMEM my_rgb_layers[] = RGBLIGHT_LAYERS_LIST(
    default_layer,
    capslock_layer
);

レイヤーリストの有効化, 初期レイヤーの設定

  • keyboard_post_init_user()内に記載します。
  • ↑で定義したレイヤーリストはkeyboard_post_init_user()rgblight_layersに代入することで有効化されます
    • ここで急に出てくるrgblight_layers変数はquantum/rgblight/rgblight.c内で定義されているもの
      • 内部的にはrgblight_layersがNULLかどうかで処理が分かれている。(NULLだと機能無効)
  • レイヤーの設定はvoid rgblight_set_layer_state(uint8_t layer, bool enabled)関数で行います
    • 第一引数のlayerはレイヤー番号、第二引数はtrueにすれば有効化されます
    • 例ではDEFAUL_LAYERを初期レイヤーとして設定してます
void keyboard_post_init_user(void) {
    // 定義したLayerリストの有効化
    rgblight_layers = my_rgb_layers;

    // 起動時のLayerを設定
    rgblight_set_layer_state(DEFAULT_LAYER, true);
}

3. 状態に応じたLayerの制御

  • 特定のキーが押されたときとか、キーボードの状態に応じてレイヤーを変更できます。
  • ここではキーボードインジゲーター、キーレイヤーに応じてLightingレイヤーを変える場合を紹介します
    • 特定キーが押されたときは単純に、process_record_user()でキーイベント見て同じことやるだけなので。

キーボードインジゲーター(CapsLockなど)に応じた制御

  • キーボードのインジゲーターとしてよくある以下の5つの状態に応じて制御を変えたい場合
    • Num Lock, Caps Lock, Scroll Lock, Compose, Kana
  • 上記のインジケータ状態は下記のページにLEDインジゲータとして説明されています
  • インゲータ状態が変わったときに呼ばれる関数はhost_keyboard_led_state(), led_update_user()の2種類有ります。
    • どちらも引数led_t led_stateで現在のインジゲータの状態を取得できますが、今回はled_update_user()の方を使います。
      • 引数のled_t型はquantum/led.hで以下のように定義された構造体です。
        • 構造体内にはnumLockやcapsLockのON/OFFがbool値で入ってるのでそれを見て判断する感じです。

quantum/led.h

typedef union {
    uint8_t raw;
    struct {
        bool    num_lock : 1;
        bool    caps_lock : 1;
        bool    scroll_lock : 1;
        bool    compose : 1;
        bool    kana : 1;
        uint8_t reserved : 3;
    };
} led_t;

led_update_user()で引数led_stateの状態に応じてレイヤーをセットしてあげれば、CapsLockのときだけLightingレイヤを変えるなどの動作が可能です。下記はCapsLock状態でのみ色を変える例

keymap.c

bool led_update_user(led_t led_state) {
    // capslock状態に応じてcapsレイヤーのON/OFFは変える
    rgblight_set_layer_state(CAPSLOCK_LAYER, led_state.caps_lock);
    return true;
} 

キーレイヤーに応じて制御

  • キーレイヤーが変更されたときに呼ばれる関数は以下の2種類があります
    • default_layer_state_set_user(layer_state_t state)
      • デフォルトのレイヤから何かしら変更があったときに呼ばれる関数
    • layer_state_t layer_state_set_user(layer_state_t state)
      • デフォルトレイヤにかかわらずレイヤが変わったときに呼ばれる関数?
  • 引数のlayer_state_tは現在どのレイヤが有効化が判断できますので、それを使ってキーレイヤ状態に応じてLightingレイヤーを変更します

Result

検証用機材

前回記事のように2個のLEDだけだとレイヤの管理パターンがわかりにくいので、8つのWS2812B Rev.5をつなげたボードを作成しました。

↓回路図

↓適当なユニバーサル基盤に実装したもの

結果

お試しで以下の4つのレイヤを切り替え機能を作成しました

  • layer0: デフォルトレイヤ(キーレイヤ0), 全LED白色
  • layer1: CapsLockレイヤ, 中央左だけ赤色にオーバーライド
  • layer2: キーレイヤー1, 上段だけ青色にオーバーライド
  • layer3: キーレイヤー2, 全LEDを別色に設定

↓実際に動作させてるときの動画
キーボードの上段中央がCapsLock, 上段右/下段右がレイヤー切り替えMO(1)/MO(2)のキーを割り当てています。

Conclusion

あらかじめ色んなパターンのLED発光パターンを用意してオーバーライドできるので、色んな使い道がありそうで便利ですね。 次回ですが、キーボードのLEDが常時発光していると眩しいですし、キー押下とかで手動で制御するのもめんどくさいので明るさセンサを使用して、暗いときだけ光らせるようにしてみたいと思います。

Appendix