🚨

Corne CherryでレイヤーごとにLEDを切り替える

2022/01/21に公開

QMKを使って、Corne Cherry(crkbd)のバックライトLEDを制御しようとしてハマったことを記録します。

やりたいこと

crkbdでレイヤーごとに点灯するLEDを切り替える。

はじめに

VIAではLEDの細かい制御はできないので、QMK Firmwareを使います。基になるキーマップは、crkbd/keymaps/defaultをコピーしたものとします。

QMKによるLED制御

QMKには、4種類のLED制御方法がありますが、今回は、RGB LightingRGB Matrixを試しました。どちらも、やりたいことは実現できますが、RGB Matrixの方が、LEDアニメーションが充実しています。

共通の設定

LED制御を有効にするとファームウェアサイズを消費するので、必須ではないですが、ファームウェアサイズを削減するオプションをrules.mkに追加しておきます。

yourkeymap/rules.mk
  OLED_ENABLE = yes
  OLED_DRIVER = SSD1306
+ MOUSEKEY_ENABLE = no
+ EXTRAKEY_ENABLE = no
+ LTO_ENABLE = yes

この設定は、crkbd/rules.mkを上書きする設定になります。

crkbdのバックライトLED配置

0-5、27-32はアンダーグローで、バックライトLEDは以下の配置になっています。


    {  24,  23,  18,  17,  10,   9 },          {  36,  37,  44,  45,  50,   51 },
    {  25,  22,  19,  16,  11,   8 },          {  35,  38,  43,  46,  49,   52 },
    {  26,  21,  20,  15,  12,   7 },          {  34,  39,  42,  47,  48,   53 },
{ NO_LED, NO_LED, NO_LED,  14,  13,   6 }, { 33,  40,  41,  NO_LED, NO_LED, NO_LED }

RGB Lightingの場合

まず、RGB Lightingを有効化します。

yourkeymap/rules.mk
+ RGBLIGHT_ENABLE = yes
+ RGB_MATRIX_ENABLE = no

RGB Lightingには、まさにレイヤーごとにLEDを切り替えるLighting Layersが準備されているのでこれを使う設定をします。

yourkeymap/config.h
  #ifdef RGBLIGHT_ENABLE
+   #define RGBLIGHT_LAYERS
-   #define RGBLIGHT_ANIMATIONS  // ファームウェアサイズ削減
    #undef RGBLED_NUM
-   #define RGBLED_NUM 27
+   #define RGBLED_NUM 54        // 左右でユニークな番号を使って制御
+   #undef RGBLED_SPLIT
+   #define RGBLED_SPLIT { 27, 27 }  // defaultだと{6, 6}バックライトLEDのみになっている
    #define RGBLIGHT_LIMIT_VAL 120
    #define RGBLIGHT_HUE_STEP 10
    #define RGBLIGHT_SAT_STEP 17
    #define RGBLIGHT_VAL_STEP 17
  #endif

デフォルト設定がおかしい気がしたので、PR出してみました。
2022-01-22 追記:マージ待ちのIssue #15779がありました。RGBLED_NUMRGBLED_SPLITの設定は不要になります。

あとは、ドキュメント通り、以下のような設定をするだけです。

yourkeymap/keymap.c
const rgblight_segment_t PROGMEM raise_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    // undergrow
    {0,   6, HSV_OFF},
    {27,  6, HSV_OFF},
    // backlight
    {6,  21, HSV_GOLD},
    {33, 21, HSV_GOLD}
);
const rgblight_segment_t PROGMEM lower_layer[] = RGBLIGHT_LAYER_SEGMENTS(
    // 略
);
const rgblight_segment_t* const PROGMEM my_rgb_layers[] = RGBLIGHT_LAYERS_LIST(
    raise_layer,
    lower_layer
);
void keyboard_post_init_user(void) {
    rgblight_layers = my_rgb_layers;
}
layer_state_t layer_state_set_user(layer_state_t state) {
    rgblight_set_layer_state(0, layer_state_cmp(state, _RAISE));
    rgblight_set_layer_state(1, layer_state_cmp(state, _LOWER));
    return state;
}

RGB Matrixの場合

keyboards/crkbdに説明がありますが、一部修正の必要があります。

まず、RGB Matrixを有効化します。

yourkeymap/rules.mk
+ RGBLIGHT_ENABLE = no
+ RGB_MATRIX_ENABLE = yes

次に、マスターのレイヤー情報をスレーブに共有する設定をします。

yourkeymap/config.h
  #ifdef RGB_MATRIX_ENABLE
+ #   define SPLIT_LAYER_STATE_ENABLE
  #   define RGB_MATRIX_KEYPRESSES // reacts to keypresses
  // 略
  #endif

RGB Matrixには、レイヤーごとにLEDを切り替える機能はないので、rgb_matrix_indicators_advanced_userを使います。色の指定にはドキュメントにならい、RGBではなくHSVを使います。

yourkeymap/keymap.c
#ifdef RGB_MATRIX_ENABLE

// 明度の上限を抑える
void set_color(int index, uint8_t hsvred, uint8_t hsvgreen, uint8_t hsvblue) {
    HSV hsv = (HSV){hsvred, hsvgreen, hsvblue};
    if (hsv.v > rgb_matrix_get_val()) {
        hsv.v = rgb_matrix_get_val();
    }
    RGB rgb = hsv_to_rgb(hsv);
    rgb_matrix_set_color(index, rgb.r, rgb.g, rgb.b);
}

void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
    // RGB_MATRIX_SOLID_COLOR(1)のときに、自作LEDロジックが動くようにする
    if (rgb_matrix_get_mode() != 1) {
       return;
    }

    // 一度全消灯
    rgb_matrix_set_color_all(RGB_OFF);

    // レイヤーごとにLEDを切り替える
    switch (get_highest_layer(layer_state | default_layer_state)) {
      case _RAISE:
        if (is_keyboard_left()) {
          // left
          set_color(8, HSV_YELLOW);
          set_color(11, HSV_YELLOW);
          // ・・・
        }else{
          // right
          set_color(37, HSV_BLUE);
          set_color(44, HSV_BLUE);
          // ・・・
        }
        break;
      case _LOWER:
        // 略
        break;
      default:
        break;
    }
}

#endif // RGB_MATRIX_ENABLE

以上で、レイヤーごとに点灯するLEDを切り替えることができました。

Discussion