keychron_qmk_firmware/docs/features/led_indicators.md
2024-06-22 09:10:58 +01:00

4.9 KiB

LED Indicators

::: tip LED indicators on split keyboards will require state information synced to the slave half (e.g. #define SPLIT_LED_STATE_ENABLE). See data sync options for more details. :::

QMK provides methods to read 5 of the LEDs defined in the HID spec:

  • Num Lock
  • Caps Lock
  • Scroll Lock
  • Compose
  • Kana

There are three ways to get the lock LED state:

  • Configuration options in config.h
  • Implement led_update_* function
  • Call led_t host_keyboard_led_state()

::: warning The host_keyboard_led_state() may reflect an updated state before led_update_user() is called. :::

Deprecated functions that provide the LED state as uint8_t:

  • uint8_t host_keyboard_leds()

Configuration Options

To configure the indicators, #define these in your config.h:

Define Default Description
LED_NUM_LOCK_PIN Not defined The pin that controls the Num Lock LED
LED_CAPS_LOCK_PIN Not defined The pin that controls the Caps Lock LED
LED_SCROLL_LOCK_PIN Not defined The pin that controls the Scroll Lock LED
LED_COMPOSE_PIN Not defined The pin that controls the Compose LED
LED_KANA_PIN Not defined The pin that controls the Kana LED
LED_PIN_ON_STATE 1 The state of the indicator pins when the LED is "on" - 1 for high, 0 for low

Unless you are designing your own keyboard, you generally should not need to change the above config options.

LED update function

When the configuration options do not provide enough flexibility, the following callbacks allow custom control of the LED behavior. These functions will be called when one of those 5 LEDs changes state:

  • Keyboard/revision: bool led_update_kb(led_t led_state)
  • Keymap: bool led_update_user(led_t led_state)

Both receives LED state as a struct parameter. Returning true in led_update_user() will allow the keyboard level code in led_update_kb() to run as well. Returning false will override the keyboard level code, depending on how the keyboard level function is set up.

Example of keyboard LED update implementation

This is a template indicator function that can be implemented on keyboard level code:

bool led_update_kb(led_t led_state) {
    bool res = led_update_user(led_state);
    if(res) {
        // gpio_write_pin sets the pin high for 1 and low for 0.
        // In this example the pins are inverted, setting
        // it low/0 turns it on, and high/1 turns the LED off.
        // This behavior depends on whether the LED is between the pin
        // and VCC or the pin and GND.
        gpio_write_pin(B0, !led_state.num_lock);
        gpio_write_pin(B1, !led_state.caps_lock);
        gpio_write_pin(B2, !led_state.scroll_lock);
        gpio_write_pin(B3, !led_state.compose);
        gpio_write_pin(B4, !led_state.kana);
    }
    return res;
}

Example of user LED update implementation

This is an incomplete example will play a sound if Caps Lock is turned on or off. It returns true to allow keyboard LED function to maintain their state.

#ifdef AUDIO_ENABLE
  float caps_on[][2] = SONG(CAPS_LOCK_ON_SOUND);
  float caps_off[][2] = SONG(CAPS_LOCK_OFF_SOUND);
#endif

bool led_update_user(led_t led_state) {
    #ifdef AUDIO_ENABLE
    static uint8_t caps_state = 0;
    if (caps_state != led_state.caps_lock) {
        led_state.caps_lock ? PLAY_SONG(caps_on) : PLAY_SONG(caps_off);
        caps_state = led_state.caps_lock;
    }
    #endif
    return true;
}

Host keyboard LED state

The host_keyboard_led_state() function will report the LED state returned from the host computer as led_t. This is useful for reading the LED state outside led_update_*. For example, you can get the boolean state of Caps Lock from the host with:

bool caps = host_keyboard_led_state().caps_lock;

led_update_ports()

This function writes the LED state to the actual hardware. Call it manually from your led_update_*() callbacks to modify the handling of the standard keyboard LEDs. For example when repurposing a standard LED indicator as layer indicator.

Setting Physical LED State

Some keyboard implementations provide convenient methods for setting the state of the physical LEDs.

Ergodox Boards

The Ergodox implementations provide ergodox_right_led_1/2/3_on/off() to turn individual LEDs on or off, as well as ergodox_right_led_on/off(uint8_t led) to turn them on or off by their index.

In addition, it is possible to specify the brightness level of all LEDs with ergodox_led_all_set(uint8_t n); of individual LEDs with ergodox_right_led_1/2/3_set(uint8_t n); or by index with ergodox_right_led_set(uint8_t led, uint8_t n).

Ergodox boards also define LED_BRIGHTNESS_LO for the lowest brightness and LED_BRIGHTNESS_HI for the highest brightness (which is the default).