Small code snippets
Here I collected some code snippets.
You can use these as pointers to implement your desired functionality.
Multi-function rotary encoder
Change the encoder’s behavour when it is pressed as a key.
bool secondary_function = false;
enum custom_keycodes {
ENC_MODE = SAFE_RANGE
};
// Define what encoder does depending on direction flag.
void encoder_update_user(uint8_t index, bool clockwise) {
if (clockwise) {
if (secondary_function) {
tap_code(KC_DOWN);
} else {
tap_code(KC_RIGHT);
}
} else {
if (secondary_function) {
tap_code(KC_UP);
} else {
tap_code(KC_LEFT);
}
}
}
// When custom keycode ENC_MODE is clicked, switch encoder direction
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case ENC_MODE:
if (record->event.pressed) {
secondary_function = !secondary_function;
}
return false; // Skip all further processing of this key
default:
return true; // Process all other keycodes normally
}
}
Multi-function, layer-aware rotary encoder
Make the previous example work differently based on the active layer.
Note
You will need the process_record_user
function, the custom_keycodes
enum and the secondary_function
boolean from the previous example.
enum layer_name {
_BASE,
_FN
};
// Define what encoder does depending on direction flag.
void encoder_update_user(uint8_t index, bool clockwise) {
// the first encoder, in case you have more
if (index == 0) {
if (layer_state_is(_BASE)) {
if (clockwise) {
if (secondary_function) {
tap_code(KC_RIGHT);
}
else {
tap_code(KC_UP);
}
}
else {
if (secondary_function) {
tap_code(KC_LEFT);
}
else {
tap_code(KC_DOWN);
}
}
}
else if (layer_state_is(_FN)) {
if (clockwise) {
if (secondary_function) {
tap_code(KC_F12);
}
else {
tap_code(KC_VOLU);
}
}
else {
if (secondary_function) {
tap_code(KC_F11);
}
else {
tap_code(KC_VOLD);
}
}
}
}
}
Turn on Numlock for a specific layer
And turn it off on other layers
layer_state_t layer_state_set_user(layer_state_t state) {
switch (get_highest_layer(state)) {
case _NUM:
if (!host_keyboard_led_state().num_lock) {
tap_code16(KC_NLCK);
}
break;
default: // for any other layers, or the default layer
if (host_keyboard_led_state().num_lock) {
tap_code16(KC_NLCK);
}
break;
}
return state;
}
Change the behaviour of one key by another
This is really similar to the encoder one
bool switcheroo = false;
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case CL_BS:
if (record->event.pressed) {
switcheroo = !switcheroo; // Change CapsLock into BackSpace
}
return false; // Skip all further processing of this key
case KC_CAPS:
if (record->event.pressed) {
if (switcheroo) {
tap_code(KC_CAPS);
} else {
tap_code(KC_BSPC);
}
return true; // Let QMK send the enter press/release events
default:
return true; // Process all other keycodes normally
}
}
Use lighting as timer indicator
This was made for a friend as a visual indicator for a spell cooldown.
The example uses QMK’s Backlight feature, but adapting it to RGB Lighting/Matrix is as easy as changing the called functions.
The “game mode” can be turned off/on with NumLock and is triggered by KC_L
.
static uint32_t game_timer;
static bool game_mode = false;
static bool timer_running = false;
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case KC_NLCK:
if (record->event.pressed) {
game_mode = !game_mode;
}
return true;
case KC_L:
if (record->event.pressed && game_mode && !timer_running) {
game_timer = timer_read32();
timer_running = true;
backlight_enable();
}
return true;
}
return true;
}
void matrix_scan_user(void) {
if (timer_running && timer_elapsed32(game_timer) >= 90000) {
timer_running = false;
backlight_disable();
}
}