koktoh の雑記帳

気ままに書いていきます

RGB MATRIX でインジケータをいい感じに制御するコード書いた

はじめに

RGB MATRIX の LED にインジケータの機能を持たせようとするとちょっと面倒だったので、いい感じに制御するコードを書きました。

公開場所

以下で公開しています。

https://github.com/koktoh/rgb_matrix_indicatorgithub.com

使い方

基本的に、上記のリポジトリにある example_xxxx 系のファイルを見れば何となくわかると思います。

ファイルの配置

<keyboard> ディレクトリに rgb_matrix_indicator をコピペします。

<keyboard>
│  config.h
│  keyboard.json
│  readme.md
│  rules.mk
│
├─keymaps
│  └─default
│          keymap.c
│
└─rgb_matrix_indicator
        rgb_matrix_indicator.c
        rgb_matrix_indicator.h

config.h の記述

RGB_INDICATOR_EEPROM_CONFIG_ADDR の設定

独自の設定を EEPROM に保存しているので、それ用の設定です。
これがないと動かないので、そのままコピペしてください。

#ifdef DYNAMIC_KEYMAP_ENABLE
#    ifdef VIA_ENABLE
#        define DYNAMIC_KEYMAP_EEPROM_ADDR (VIA_EEPROM_CONFIG_END)
#    else // VIA_ANABLE
#        define DYNAMIC_KEYMAP_EEPROM_ADDR (EECONFIG_SIZE)
#    endif // VIA_ENABLE

#    define DYNAMIC_KEYMAP_EEPROM_MAX_ADDR (TOTAL_EEPROM_BYTE_COUNT - 1)
#    define DYNAMIC_KEYMAP_LAYER_COUNT 4
#    define DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR (DYNAMIC_KEYMAP_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * MATRIX_ROWS * MATRIX_COLS * 2))

#    ifdef ENCODER_MAP_ENABLE
#        define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR + (DYNAMIC_KEYMAP_LAYER_COUNT * NUM_ENCODERS * 2 * 2))
#    else // ENCODER_MAP_ENABLE
#        define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (DYNAMIC_KEYMAP_ENCODER_EEPROM_ADDR)
#    endif // ENCODER_MAP_ENABLE

#    define DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR - DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR + 1)

#    define RGB_INDICATOR_EEPROM_CONFIG_ADDR (DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE)
#else // DYNAMIC_KEYMAP_ENABLE
#    define RGB_INDICATOR_EEPROM_CONFIG_ADDR (EECONFIG_SIZE)
#endif // DYNAMIC_KEYMAP_ENABLE

LED の設定

以下のインジケータとして使用する LED のインデックスを設定します。

  • レイヤー
  • Num Lock
  • Caps Lock
  • Scroll Lock
  • Compose
  • Kana

define されない場合、各インジケータは表示されません。
インジケータとして不要であれば、 define しないでおけば OK です。

XXXX_INDICATOR_LED_INDEXXXXX_INDICATOR_LED_INDEXES のどちらかだけを define してください。

1つの LED をインジケータとして使用する

一番普通の使い方だと思います。

設定されたインデックスの LED が、そのインジケータとして使用されます。

#define LAYER_INDICATOR_LED_INDEX 0

#define NUMLOCK_INDICATOR_LED_INDEX 1
#define CAPSLOCK_INDICATOR_LED_INDEX 2
#define SCROLLLOCK_INDICATOR_LED_INDEX 3
#define COMPOSE_INDICATOR_LED_INDEX 4
#define KANA_INDICATOR_LED_INDEX 5

複数の LED をインジケータとして使用する

例えば、「10番目と20番目の LED を Num Lock のインジケータとして使いたい」というときに設定します。(需要があるのかはわからんけど……)
指定されたインデックスの LED は全部同じ色に光ります。
LED はいくつでも指定できます。

#define LAYER_INDICATOR_LED_INDEXES { 0, 1 }

#define NUMLOCK_INDICATOR_LED_INDEXES { 2, 3 }
#define CAPSLOCK_INDICATOR_LED_INDEXES { 4, 5, 6 }
#define SCROLLLOCK_INDICATOR_LED_INDEXES { 7, 8, 9, 10 }
#define COMPOSE_INDICATOR_LED_INDEXES { 11, 12 }
#define KANA_INDICATOR_LED_INDEXES { 13, 14 }

その他設定

普通の RGB MATRIX とかであるようなやつを揃えています。

#define LAYER_INDICATOR_BASE_COLOR HSV_CYAN // Default is HSV_RED
#define LAYER_INDICATOR_STEP 17             // Default is 25
#define INDICATOR_HUE_STEP 4                // Default is 8
#define INDICATOR_SAT_STEP 8                // Default is 17
#define INDICATOR_VAL_STEP 8                // Default is 17
#define INDICATOR_LIMIT_VAL 127             // Default is 255

keymap.c の記述

基本的に example_keymap.c を見てもらえればわかるかなと思います。

初期化

rgb_matrix_indicator を初期化します。
EEPROM に保存していた設定を読み込みます。

void keyboard_post_init_user(void) {
    rgb_matrix_indicator_init();
}

EEPROM リセット

EE_CLR とかで EEPROM がリセットされた時に、デフォルト値を設定します。
これを書いておかないと EEPROM がリセットされても、 rgb_matrix_indicator の設定がリセットされません。

void eeconfig_init_user(void) {
    eeconfig_init_rgb_matrix_indicator();
}

キーコードの処理

これを忘れると rgb_matrix_indicator 用のキーコードの処理がされないので気を付けてください。

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    /* ---- とりあえずここにこれを書いておけば OK ---- */
    bool p_rgb_indicator = process_record_rgb_matirx_indicator(keycode, record);
    if (!p_rgb_indicator) {
        return false;
    }
}

カスタムキーコードを定義する場合は RGB_INDICATOR_SAFE_RANGE を使用してください。

enum custom_keycodes {
    CUSTOM1 = RGB_INDICATOR_SAFE_RANGE,
    CUSTOM2,
    CUSTOM3,
    CUSTOM4,
}

.
.
.

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    /* ---- とりあえずここにこれを書いておけば OK ---- */
    bool p_rgb_indicator = process_record_rgb_matirx_indicator(keycode, record);
    if (!p_rgb_indicator) {
        return false;
    }

    /* ---- 別にカスタムキーコードを定義して使う場合は、ここから下に書く ---- */
    switch (keycode) {
        case CUSTOM1:
            if (record->event.pressed) {
                // Do something when pressed
            } else {
                // Do something else when release
            }
            return false;
        case CUSTOM2:
            if (record->event.pressed) {
                // Do something when pressed
            } else {
                // Do something else when release
            }
            return false;
        case CUSTOM3:
            if (record->event.pressed) {
                // Do something when pressed
            } else {
                // Do something else when release
            }
            return false;
        case CUSTOM4:
            if (record->event.pressed) {
                // Do something when pressed
            } else {
                // Do something else when release
            }
            return false;
        default:
            return true; // Process all other keycodes normally
    }
}

インジケータの処理

インジケータを更新して正しく光らせるための処理です。
これを忘れると正しく動きません。

簡単な使用

とりあえずこう書いておけば動きます。

bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
    update_layer_indicator(get_highest_layer(layer_state | default_layer_state));
    update_indicators(host_keyboard_led_state());

    return false;
}

カスタマイズ

ちょっとカスタマイズしたいと思ったら、以下のように書いてください。

bool rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
    /* ---- レイヤーインジケータのカスタマイズ ---- */
    switch (get_highest_layer(layer_state | default_layer_state)) {
        case _BASE:
            layer_indicator_set_hsv(HSV_CYAN);
            break;
        case _LAYER1:
            layer_indicator_set_hsv(HSV_MAGENTA);
            break;
        case _LAYER2:
            layer_indicator_set_hsv(HSV_ORANGE);
            break;
        case _LAYER3:
            layer_indicator_set_hsv(HSV_PURPLE);
            break;
        default:
            break;
    }

    /* ---- その他インジケータのカスタマイズ ---- */
    if (host_keyboard_led_state().num_lock) {
        numlock_indicator_set_hsv(HSV_AZURE);
    } else {
        numlock_indicator_off();
    }

    if (host_keyboard_led_state().caps_lock) {
        capslock_indicator_set_hsv(HSV_YELLOW);
    } else {
        capslock_indicator_off();
    }

    return false;
}

レイヤーは update_layer_indicator(uint8_t layer_state) を使って、他のインジケータは独自で実装する(逆も然り)とかも可能です。

rules.mk の記述

ソースを追加するだけです。

SRC += rgb_matrix_indicator/rgb_matrix_indicator.c

レイヤーインジケータについて

レイヤーのインジケータは少し特殊になっています。

config.h で以下のように設定しました。

#define LAYER_INDICATOR_BASE_COLOR HSV_CYAN // Default is HSV_RED
#define LAYER_INDICATOR_STEP 17             // Default is 25

LAYER_INDICATOR_BASE_COLOR は、レイヤー0番が選択されているときの LED の色です。
レイヤー1番になると、LAYER_INDICATOR_STEP の分だけ Hue に加算された色になります。(ウェブとかの HSV のカラーパレットとかでどんな感じか見てもらえれば)
2番ではさらに LAYER_INDICATOR_STEP の分だけ加算され……というように、自動で色が設定されます。

あまりにもレイヤーが多かったり、 LAYER_INDICATOR_STEP の値が小さいと、色が一周して違うレイヤーが同じ色になったり、レイヤーが変わっても色の変化が小さすぎてわかりにくくなったりします。

インジケータの処理カスタマイズ に書いたように、レイヤーごとに自分で色を設定することもできるので、好みによって変えてください。

キーコードについて

rgb_matrix_indicator では、RGB MATRIX に関係するキーコードの動作を変更しています

キーコード 変更前の動作 変更後の動作
RGB_TOG すべての LED が点灯 / 消灯する インジケータ以外の LED が点灯 / 消灯する
RGB_MOD から RGB_M_SW まで それぞれの動作 インジケータ以外の LED が消灯している場合、何も実行されない

また、独自のキーコードを定義しています。

キーコード エイリアス 説明
RGB_INDICATOR_HUE_UP RGB_IHI インジケータ LED の Hue を加算する
RGB_INDICATOR_HUE_DOWN RGB_IHD インジケータ LED の Hue を減算する
RGB_INDICATOR_SATURATION_UP RGB_ISI インジケータ LED の Saturation を加算する
RGB_INDICATOR_SATURATION_DOWN RGB_ISD インジケータ LED の Saturation を減算する
RGB_INDICATOR_VALUE_UP RGB_IVI インジケータ LED の Value (明るさ)を加算する
RGB_INDICATOR_VALUE_DOWN RGB_IVD インジケータ LED の Value (明るさ)を減算する

これらのキーコードによる操作は、レイヤー以外のすべてのインジケータ LED に反映されます。
つまり、 RGB_IHI を実行すると、 Num Lock も Caps Lock もすべて同じ色に変化します。

RGB_IVI / RGB_IVD はレイヤー含めたすべてのインジケータ LED に反映されます。

API

void rgb_matrix_indicator_init(void)

rgb_matrix_indicator を初期化する。

void eeconfig_init_rgb_matrix_indicator(void)

rgb_matirx_indicator の EEPROM 領域をリセットする。

void disable_rgb_effect(void)

インジケータ以外の LED を消灯する。

bool process_record_rgb_matirx_indicator(uint16_t keycode, keyrecord_t *record)

rgb_matrix_indicator で定義されたキーコードの処理。

void update_layer_indicator(uint8_t layer_state)

レイヤーインジケータ LED の表示を更新する。

void update_indicators(led_t led_state)

レイヤー以外の全インジケータ LED の表示を更新する。

void layer_indicator_set_hsv(uint8_t hue, uint8_t sat, uint8_t val)

レイヤーインジケータ LED を指定した色に設定する。
HSV_RED などをそのまま使用可能。
valINDICATOR_LIMIT_VAL を超える値が指定された場合、 INDICATOR_LIMIT_VAL の値が使用される。

void numlock_indicator_set_hsv(uint8_t hue, uint8_t sat, uint8_t val)

Num Lock インジケータ LED を指定した色に設定する。
HSV_RED などをそのまま使用可能。
valINDICATOR_LIMIT_VAL を超える値が指定された場合、 INDICATOR_LIMIT_VAL の値が使用される。

これを使用した場合、 RGB_IHI, RGB_IHD, RGB_ISI, RGB_ISD のキーコードによる変更は反映されない。
RGB_IVI, RGB_IVD のキーコードは反映される。

void numlock_indicator_off(void)

Num Lock インジケータ LED を消灯する。

void capslock_indicator_set_hsv(uint8_t hue, uint8_t sat, uint8_t val)

Caps Lock インジケータ LED を指定した色に設定する。
HSV_RED などをそのまま使用可能。
valINDICATOR_LIMIT_VAL を超える値が指定された場合、 INDICATOR_LIMIT_VAL の値が使用される。

これを使用した場合、 RGB_IHI, RGB_IHD, RGB_ISI, RGB_ISD のキーコードによる変更は反映されない。
RGB_IVI, RGB_IVD のキーコードは反映される。

void capslock_indicator_off(void)

Caps Lock インジケータ LED を消灯する。

void scrolllock_indicator_set_hsv(uint8_t hue, uint8_t sat, uint8_t val)

Scroll Lock インジケータ LED を指定した色に設定する。
HSV_RED などをそのまま使用可能。
valINDICATOR_LIMIT_VAL を超える値が指定された場合、 INDICATOR_LIMIT_VAL の値が使用される。

これを使用した場合、 RGB_IHI, RGB_IHD, RGB_ISI, RGB_ISD のキーコードによる変更は反映されない。
RGB_IVI, RGB_IVD のキーコードは反映される。

void scrolllock_indicator_off(void)

Scroll Lock インジケータ LED を消灯する。

void compose_indicator_set_hsv(uint8_t hue, uint8_t sat, uint8_t val)

Compose インジケータ LED を指定した色に設定する。
HSV_RED などをそのまま使用可能。
valINDICATOR_LIMIT_VAL を超える値が指定された場合、 INDICATOR_LIMIT_VAL の値が使用される。

これを使用した場合、 RGB_IHI, RGB_IHD, RGB_ISI, RGB_ISD のキーコードによる変更は反映されない。
RGB_IVI, RGB_IVD のキーコードは反映される。

void compose_indicator_off(void)

Compose インジケータ LED を消灯する。

void kana_indicator_set_hsv(uint8_t hue, uint8_t sat, uint8_t val)

Kana インジケータ LED を指定した色に設定する。
HSV_RED などをそのまま使用可能。
valINDICATOR_LIMIT_VAL を超える値が指定された場合、 INDICATOR_LIMIT_VAL の値が使用される。

これを使用した場合、 RGB_IHI, RGB_IHD, RGB_ISI, RGB_ISD のキーコードによる変更は反映されない。
RGB_IVI, RGB_IVD のキーコードは反映される。

void kana_indicator_off(void)

Kana インジケータ LED を消灯する。

VIA 対応について

一応、VIA で使用する EEPROM 領域は侵さないようになっていると思います。(RGB_INDICATOR_EEPROM_CONFIG_ADDR の設定

しかし、面倒でちゃんとは確認していないので、不具合等があれば、 issue 立てたり X(旧 Twitter) で突っ込んだりしてください。

また、独自キーコードを設定する場合は Any(n) などで頑張ってください。

おわりに

以上、 RGB MATRIX をいい感じにするコードを書いた報告とその解説でした。

どんな動きするかは実際使ってみて確かめてみてください。

不具合があったり、要望があったらさらに手を入れるかもしれません。
もちろん PR も大歓迎です。