QMKで任意のLEDを光らせるテクニック

自作キーボードのキットによってはフルカラーLEDを追加して、キラキラ光らせるタイプもあります。ゲーミングキーボードのように、虹色に光らせておくのも良いですが、特定のキーだけ違う色で光らせるような演出にもこだわりたいあなたのために、QMKファームウェアの改造テクニックを紹介します。


例えば、Helixでは左右のLEDが独立しており、かつ、回路としてはそれぞれが蛇腹状に配線されているので、数値の調整がかなり面倒です。

まずは、プログラム上のLEDの位置と、実際に配置しているLEDの位置を合わせましょう。基礎となるファームウェアのソースコードから「config.h」を探し、以下の宣言を追加、もしくは修正をします。

rgbnum.h
/* キーボードに接続しているLEDの総数 */
#define RGBLED_NUM 64

/* 分割キーボードなら、メインとサブにそれぞれ接続している数も宣言する */
#define RGBLED_SPLIT {32, 32}
続いてLEDの位置をプログラム内部で変換するための表を作成します。「LED_LAYOUT」では実際の配線と論理的な配線の変換を行い、「RGBLIGHT_LED_MAP」によって最終的なLED番号を割り当てます。これらはマクロなので、キーマップ変換と同様、列挙の最後に「,」を含めるとコンパイルエラーの原因になります。
ledmap.h
/* LEDマッピングの定義 */
#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, \
    L40, L41, L42, L43, L44, L45, L46, R40, R41, R42, R43, R44, R45, R46 \
) { \
    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, \
    L46, L45, L44, L43, L42, L41, L40, \
    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, \
    R40, R41, R42, R43, R44, R45, R46 \
}

#define RGBLIGHT_LED_MAP LED_LAYOUT( \
   0,  1,  2,  3,  4,  5,            37, 36, 35, 34, 33, 32, \
   6,  7,  8,  9, 10, 11,            43, 42, 41, 40, 39, 38, \
  12, 13, 14, 15, 16, 17,            49, 48, 47, 46, 45, 44, \
  18, 19, 20, 21, 22, 23, 24,    56, 55, 54, 53, 52, 51, 50, \
  25, 26, 27, 28, 29, 30, 31,    63, 62, 61, 60, 59, 58, 57)
Helixは左右対称のキーボードなので、番号も左右対称にしてみました。

QMKでは照明レイヤーという機能が用意されており、LEDアニメーションを有効にしたまま、特定の範囲の色だけ変更することができます。8層(RGBLIGHT_MAX_LAYERS宣言で32まで拡張可能)を重ね合わせると、配列順で値の大きいレイヤーの色が上書きされていきます。

レイヤーは、「RGBLIGHT_LAYER_SEGMENTS」マクロで定義した個々のレイヤーを「RGBLIGHT_LAYERS_LIST」にてひとまとめにしたのもを「keymap.c」に記述します。なお、QMKでは原則としてHSV色空間を使用します。
def_layer.c
const rgblight_segment_t PROGMEM rgb_lower_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {1, 5, HSV_RED}, // 1番から連続した5つのLEDを赤にする
    {7, 5, HSV_RED},
    {13, 5, HSV_RED},
    {19, 6, HSV_RED}, // 19番から連続した6つのLEDを赤にする

    {33, 5, HSV_RED},
    {39, 5, HSV_RED},
    {45, 5, HSV_RED},
    {51, 6, HSV_RED}
);

const rgblight_segment_t PROGMEM rgb_raise_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    {1, 5, HSV_CYAN}, // 1番から連続した5つのLEDをシアンにする
    {7, 5, HSV_CYAN},
    {13, 5, HSV_CYAN},
    {19, 6, HSV_CYAN}, // 19番から連続した6つのLEDをシアンにする

    {33, 5, HSV_CYAN},
    {39, 5, HSV_CYAN},
    {45, 5, HSV_CYAN},
    {51, 6, HSV_CYAN}
);

const rgblight_segment_t* const PROGMEM rgb_layers[] = RGBLIGHT_LAYERS_LIST(
    rgb_lower_layer,
    rgb_raise_layer
);
このレイヤー配列をQMKが用意しているグローバル変数「rgblight_layers」に割り当てたら、初期化は完了です。分割キーボードでは、64個のLEDが実際には電気的に接続されていません。そのため、配列の参照をプログラムで調整する必要があるのですが、これはQMKのクリッピング関数を使うことで解決できます。
init_layer.c
// キーボード初期化後に呼ばれる関数
void keyboard_post_init_user(void) {
    // 左側のボードなら色キャッシュ配列の0~31番を、
    // 右側のボードなら色キャッシュ配列の32~63番を反映させる
    rgblight_set_clipping_range(is_keyboard_left() ? 0 : 32, 32);

    // QMKが予約している変数に代入することで、照明レイヤーを初期化
    rgblight_layers = rgb_layers;
}
照明レイヤーの切り替えには「rgblight_set_layer_state」関数を使用します。この例では、キーマップの有効レイヤーと連動させています。
sync_key.c
// レイヤー状態が変更されたときに呼び出される
layer_state_t layer_state_set_user(layer_state_t state) {
    // 変更されたレイヤーと一致する照明レイヤーのみを適用
    rgblight_set_layer_state(0, layer_state_cmp(state, _LOWER));
    rgblight_set_layer_state(1, layer_state_cmp(state, _RAISE));

    return state;
}
あと、単独ならちゃんと動くのに、ケーブルで2つの基板をつなげるとLEDがでたらめな色に変わってしまうようであれば、LEDの大量点灯による電力不足が考えられます。そのときは「#define RGBLIGHT_LIMIT_VAL 35」などで最大輝度を制限すると良いでしょう。
2020/08/20