~ruther/qmk_firmware

134b60bb252056e50ebfd8f95522fdd6e4b432d5 — Less/Rikki 1 year, 8 months ago 35be48f
[keyboard] tominabox1/le_chiffre oled rework (#21611)

Co-authored-by: Drashna Jaelre <drashna@live.com>
M keyboards/tominabox1/le_chiffre/keymaps/default/keymap.c => keyboards/tominabox1/le_chiffre/keymaps/default/keymap.c +49 -96
@@ 88,115 88,68 @@ combo_t key_combos[] = {
};
#endif

#ifdef OLED_ENABLE // Special thanks to Sickbabies for this great OLED widget!
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    return OLED_ROTATION_90; // rotates for proper orientation
}

void render_lechiffre_logo(void) {
    static const char PROGMEM lechiffre_logo[] = {
       // 'lechiffre_logo', 32x20px
    0x00, 0x3e, 0x20, 0x20, 0x00, 0x18, 0x2c, 0xa8, 0x80, 0x00, 0x1c, 0x22, 0x22, 0x00, 0x3e, 0x08,
    0x30, 0x00, 0x34, 0x00, 0x3c, 0x0a, 0x00, 0xbc, 0x8a, 0x00, 0x38, 0x08, 0x00, 0x18, 0x2c, 0x28,
    0x00, 0xb6, 0xb6, 0x00, 0xdb, 0xdb, 0x00, 0x6d, 0x6d, 0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00,
    0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00, 0x6d, 0x6d, 0x00, 0xdb, 0xdb, 0x00, 0xb6, 0xb6, 0x00,
    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00,
    0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00};

    oled_write_raw_P(lechiffre_logo, sizeof(lechiffre_logo));
}

static void render_layer_status(void) {
    oled_write_P(PSTR("-----"), false);
    switch (get_highest_layer(layer_state)) {
        case _BASE:
            oled_write_ln_P(PSTR("BASE"), false);
            break;
        case _NUM_SYM:
            oled_write_ln_P(PSTR(" SYM"), false);
            break;
        case _NAV:
            oled_write_ln_P(PSTR(" NAV"), false);
            break;
        default:
            oled_write_ln_P(PSTR("?????"), false);
    }
}

#    define KEYLOG_LEN 11
char     keylog_str[KEYLOG_LEN] = {};
uint8_t  keylogs_str_idx        = 0;
uint16_t log_timer              = 0;

const char code_to_name[60] = {
    ' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
    'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
    'R', 'E', 'B', 'T', '_', '-', '=', '[', ']', '\\',
    '#', ';', '\'', '`', ',', '.', '/', ' ', ' ', ' '};

void add_keylog(uint16_t keycode) {
    if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
        keycode = keycode & 0xFF;
    }

    for (uint8_t i = KEYLOG_LEN - 1; i > 0; i--) {
        keylog_str[i] = keylog_str[i - 1];
    }
    if (keycode < 60) {
        keylog_str[0] = code_to_name[keycode];
    }
    keylog_str[KEYLOG_LEN - 1] = 0;

    log_timer = timer_read();
}

void update_log(void) {
    if (timer_elapsed(log_timer) > 750) {
        add_keylog(0);
    }
}

// Text only renders
void render_keylogger_status(void) {
    oled_write_P(PSTR("-----"), false);
    oled_write(keylog_str, false);
}

void render_keylock_status(led_t led_state) {
    oled_write_P(PSTR("-----"), false);
    oled_write_P(PSTR("C"), led_state.caps_lock);
    oled_write_P(PSTR(" "), false);
    oled_write_P(PSTR("N"), led_state.num_lock);
    oled_write_P(PSTR(" "), false);
    oled_write_P(PSTR("S"), led_state.scroll_lock);
    // oled_write_ln_P(PSTR(" "), false);
}
#ifdef OLED_ENABLE

// Add additional layer names here if desired. Only first 5 characters will be copied to display.
const char PROGMEM layer_base[]    = "BASE";
const char PROGMEM layer_num_sym[] = " SYM";
const char PROGMEM layer_nav[]     = " NAV";
// Add layer name variables to array here. Make sure these are in order.
const char* const PROGMEM layer_names[] = {
    layer_base,
    layer_num_sym,
    layer_nav
};

void render_mod_status(uint8_t modifiers) {
    oled_write_P(PSTR("-----"), false);
    oled_write_ln_P(PSTR("SHFT"), (modifiers & MOD_MASK_SHIFT));
    oled_write_ln_P(PSTR("ALT"), (modifiers & MOD_MASK_ALT));
    oled_write_ln_P(PSTR("CTRL"), (modifiers & MOD_MASK_CTRL));
    oled_write_ln_P(PSTR("GUI"), (modifiers & MOD_MASK_GUI));
}
static char oled_layer_buf[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static layer_state_t top_layer_cache;

/* BEGIN STANDARD QMK FUNCTIONS */
bool oled_task_user(void) {
    render_lechiffre_logo();
    oled_write_raw_P(lechiffre_logo, sizeof(lechiffre_logo));
    // Renders the current keyboard state (layer, lock, caps, scroll, etc);
    oled_set_cursor(0, 3);
    render_layer_status(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
    oled_write_P(oled_section_break, false);
    render_layer_status(oled_layer_buf);
    oled_write_P(oled_section_break, false);
    render_mod_status(get_mods() | get_oneshot_mods());
    oled_write_P(oled_section_break, false);
    render_keylock_status(host_keyboard_led_state());
    oled_write_P(oled_section_break, false);
    render_keylogger_status();

    return false;
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
    if (record->event.pressed) {
        add_keylog(keycode);
        add_keylog(keycode, record);
    }

    return true;
}

// If we don't force an update during initialization, the layer name buffer will start out blank.
layer_state_t default_layer_state_set_user(layer_state_t state) {
    update_layer_namebuf(get_highest_layer(state), true);
    return state;
}
layer_state_t layer_state_set_user(layer_state_t state) {
    update_layer_namebuf(get_highest_layer(state | default_layer_state), false);
    return state;
}

/* END STANDARD QMK FUNCTIONS */
/* BEGIN CUSTOM HELPER FUNCTION FOR OLED */
// Avoid excessive copying by only updating the layer name buffer when the layer changes
void update_layer_namebuf(layer_state_t layer, bool force_update) {
    if (force_update || layer != top_layer_cache) {
        top_layer_cache = layer;
        if (layer < ARRAY_SIZE(layer_names)) {
            memcpy_P(oled_layer_buf, pgm_read_ptr(&layer_names[layer]), ARRAY_SIZE(oled_layer_buf) - 1);
        } else {
            memcpy(oled_layer_buf, get_u8_str(layer, ' '), ARRAY_SIZE(oled_layer_buf) - 1);
        }
    }
}
#endif

M keyboards/tominabox1/le_chiffre/keymaps/via/keymap.c => keyboards/tominabox1/le_chiffre/keymaps/via/keymap.c +9 -97
@@ 32,106 32,17 @@ const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
};
#endif

#ifdef OLED_ENABLE // Special thanks to Sickbabies for this great OLED widget!
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
    return OLED_ROTATION_90; // rotates for proper orientation
}

void render_lechiffre_logo(void) {
    static const char PROGMEM lechiffre_logo[] = {
       // 'lechiffre_logo', 32x20px
    0x00, 0x3e, 0x20, 0x20, 0x00, 0x18, 0x2c, 0xa8, 0x80, 0x00, 0x1c, 0x22, 0x22, 0x00, 0x3e, 0x08,
    0x30, 0x00, 0x34, 0x00, 0x3c, 0x0a, 0x00, 0xbc, 0x8a, 0x00, 0x38, 0x08, 0x00, 0x18, 0x2c, 0x28,
    0x00, 0xb6, 0xb6, 0x00, 0xdb, 0xdb, 0x00, 0x6d, 0x6d, 0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00,
    0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00, 0x6d, 0x6d, 0x00, 0xdb, 0xdb, 0x00, 0xb6, 0xb6, 0x00,
    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00,
    0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00};

    oled_write_raw_P(lechiffre_logo, sizeof(lechiffre_logo));
}

// static void render_layer_status(void) {
//     oled_write_P(PSTR("-----"), false);
//     switch (get_highest_layer(layer_state)) {
//         case _BASE:
//             oled_write_ln_P(PSTR("BASE"), false);
//             break;
//         case _NUM_SYM:
//             oled_write_ln_P(PSTR(" SYM"), false);
//             break;
//         case _NAV:
//             oled_write_ln_P(PSTR(" NAV"), false);
//             break;
//         default:
//             oled_write_ln_P(PSTR("?????"), false);
//     }
// }

#    define KEYLOG_LEN 11
char     keylog_str[KEYLOG_LEN] = {};
uint8_t  keylogs_str_idx        = 0;
uint16_t log_timer              = 0;

const char code_to_name[60] = {
    ' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
    'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
    'R', 'E', 'B', 'T', '_', '-', '=', '[', ']', '\\',
    '#', ';', '\'', '`', ',', '.', '/', ' ', ' ', ' '};

void add_keylog(uint16_t keycode) {
    if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
        keycode = keycode & 0xFF;
    }

    for (uint8_t i = KEYLOG_LEN - 1; i > 0; i--) {
        keylog_str[i] = keylog_str[i - 1];
    }
    if (keycode < 60) {
        keylog_str[0] = code_to_name[keycode];
    }
    keylog_str[KEYLOG_LEN - 1] = 0;

    log_timer = timer_read();
}

void update_log(void) {
    if (timer_elapsed(log_timer) > 750) {
        add_keylog(0);
    }
}

// Text only renders
void render_keylogger_status(void) {
    oled_write_P(PSTR("-----"), false);
    oled_write(keylog_str, false);
}

void render_keylock_status(led_t led_state) {
    oled_write_P(PSTR("-----"), false);
    oled_write_P(PSTR("C"), led_state.caps_lock);
    oled_write_P(PSTR(" "), false);
    oled_write_P(PSTR("N"), led_state.num_lock);
    oled_write_P(PSTR(" "), false);
    oled_write_P(PSTR("S"), led_state.scroll_lock);
    // oled_write_ln_P(PSTR(" "), false);
}

void render_mod_status(uint8_t modifiers) {
    oled_write_P(PSTR("-----"), false);
    oled_write_ln_P(PSTR("SHFT"), (modifiers & MOD_MASK_SHIFT));
    oled_write_ln_P(PSTR("ALT"), (modifiers & MOD_MASK_ALT));
    oled_write_ln_P(PSTR("CTRL"), (modifiers & MOD_MASK_CTRL));
    oled_write_ln_P(PSTR("GUI"), (modifiers & MOD_MASK_GUI));
}

#ifdef OLED_ENABLE
bool oled_task_user(void) {
    render_lechiffre_logo();
    oled_write_raw_P(lechiffre_logo, sizeof(lechiffre_logo));
    oled_set_cursor(0, 3);
    // render_layer_status();    // Renders the current keyboard state (layer, lock, caps, scroll, etc)
    oled_write_P(oled_section_break, false);
    render_layer_status(get_u8_str(get_highest_layer(layer_state | default_layer_state), ' '));
    oled_write_P(oled_section_break, false);
    render_mod_status(get_mods() | get_oneshot_mods());
    oled_write_P(oled_section_break, false);
    render_keylock_status(host_keyboard_led_state());
    oled_write_P(oled_section_break, false);
    render_keylogger_status();

    return false;


@@ 139,8 50,9 @@ bool oled_task_user(void) {

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    if (record->event.pressed) {
        add_keylog(keycode);
        add_keylog(keycode, record);
    }

    return true;
}
#endif

A keyboards/tominabox1/le_chiffre/le_chiffre.c => keyboards/tominabox1/le_chiffre/le_chiffre.c +123 -0
@@ 0,0 1,123 @@
// Copyright 2020 tominabox1 (@tominabox1)
// Copyright 2019 @foostan
// Copyright 2020 Drashna Jaelre <@drashna>
// Copyright 2023 QMK Contributors <@qmk>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "quantum.h"
#include "le_chiffre.h"

#if defined(OLED_ENABLE) // Special thanks to Sickbabies for this great OLED widget!

/* CONSTANTS */
const char PROGMEM code_to_name[53] = {
    'a', 'b', 'c', 'd', 'e', 'f',  'g', 'h', 'i',  'j',
    'k', 'l', 'm', 'n', 'o', 'p',  'q', 'r', 's',  't',
    'u', 'v', 'w', 'x', 'y', 'z',  '1', '2', '3',  '4',
    '5', '6', '7', '8', '9', '0',  'R', 'E', 'B',  'T',
    '_', '-', '=', '[', ']', '\\', '#', ';', '\'', '`',
    ',', '.', '/'
};

const char PROGMEM lechiffre_logo[96] = {
    // 'lechiffre_logo', 32x20px
    0x00, 0x3e, 0x20, 0x20, 0x00, 0x18, 0x2c, 0xa8, 0x80, 0x00, 0x1c, 0x22, 0x22, 0x00, 0x3e, 0x08,
    0x30, 0x00, 0x34, 0x00, 0x3c, 0x0a, 0x00, 0xbc, 0x8a, 0x00, 0x38, 0x08, 0x00, 0x18, 0x2c, 0x28,
    0x00, 0xb6, 0xb6, 0x00, 0xdb, 0xdb, 0x00, 0x6d, 0x6d, 0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00,
    0x00, 0xdb, 0xdb, 0x00, 0xdb, 0xdb, 0x00, 0x6d, 0x6d, 0x00, 0xdb, 0xdb, 0x00, 0xb6, 0xb6, 0x00,
    0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00,
    0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00
};

const char PROGMEM oled_section_break[6] = OLED_SECTION_BREAK;
/* END CONSTANTS */

/* TRACKERS */
static char     keylog_str[KEYLOG_LEN] = {};
static uint16_t log_timer              = 0;
/* END TRACKERS */

/* BEGIN STANDARD QMK FUNCTIONS */

oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
    return OLED_ROTATION_90;
}

bool oled_task_kb(void) {
    if (!oled_task_user()) {
        return false;
    }
    oled_write_raw_P(lechiffre_logo, sizeof(lechiffre_logo));
    oled_set_cursor(0, 3);
    oled_write_P(oled_section_break, false);
    render_layer_status(get_u8_str(get_highest_layer(layer_state | default_layer_state), ' '));
    oled_write_P(oled_section_break, false);
    render_mod_status(get_mods() | get_oneshot_mods());
    oled_write_P(oled_section_break, false);
    render_keylock_status(host_keyboard_led_state());
    return true;
}

/* END STANDARD QMK FUNCTIONS */
/* BEGIN CUSTOM HELPER FUNCTIONS FOR OLED */

/**
 * Sickbabies deserves credit for the original OLED implementation,
 * however most of the keylogging code appears to have been lifted from crkbd
 * -- which is why @foostan and @drashna are now credited here as well.
 *
 * Improvements were lifted from crkbd again in 2023, with gratitude.
 */
void add_keylog(uint16_t keycode, keyrecord_t *record) {
    if (IS_QK_MOD_TAP(keycode) && record->tap.count) {
        keycode = QK_MOD_TAP_GET_TAP_KEYCODE(keycode);
    } else if (IS_QK_LAYER_TAP(keycode) && record->tap.count) {
        keycode = QK_LAYER_TAP_GET_TAP_KEYCODE(keycode);
    } else if (IS_QK_MODS(keycode)) {
        keycode = QK_MODS_GET_BASIC_KEYCODE(keycode);
    }

    if (keycode >= KC_A && keycode < KC_CAPS) {
        keycode -= KC_A; // shift to first letter of alphabet
        for (uint8_t i = KEYLOG_LEN - 1; i > 0; i--) {
            keylog_str[i] = keylog_str[i - 1];
        }
        keylog_str[0] = pgm_read_byte(&(code_to_name[keycode]));
        keylog_str[KEYLOG_LEN - 1] = 0x00;
    }

    log_timer = timer_read();
}

void render_keylock_status(led_t led_state) {
    oled_write_P(PSTR("C"), led_state.caps_lock);
    oled_advance_char();
    oled_write_P(PSTR("N"), led_state.num_lock);
    oled_advance_char();
    oled_write_P(PSTR("S"), led_state.scroll_lock);
}

void render_keylogger_status(void) {
    // zero out log after 30s idle time
    if (strlen(keylog_str) > 0 && timer_elapsed(log_timer) > 30000) {
        keylog_str[0] = 0x00;
        oled_advance_page(true);
        oled_advance_page(true);
    }
    oled_write(keylog_str, false);
}

void render_layer_status(const char* layer_name) {
    oled_write(layer_name, false);
    if (strlen(layer_name) < oled_max_chars()) {
        oled_advance_page(true);
    }
}

void render_mod_status(uint8_t modifiers) {
    oled_write_ln_P(PSTR("SHFT"), (modifiers & MOD_MASK_SHIFT));
    oled_write_ln_P(PSTR("ALT"), (modifiers & MOD_MASK_ALT));
    oled_write_ln_P(PSTR("CTRL"), (modifiers & MOD_MASK_CTRL));
    oled_write_ln_P(PSTR("GUI"), (modifiers & MOD_MASK_GUI));
}
#endif // OLED_ENABLE

A keyboards/tominabox1/le_chiffre/le_chiffre.h => keyboards/tominabox1/le_chiffre/le_chiffre.h +17 -0
@@ 0,0 1,17 @@
// Copyright 2020 tominabox1 (@tominabox1) and sickbabies
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#define KEYLOG_LEN 11

extern const char PROGMEM code_to_name[53];
extern const char PROGMEM lechiffre_logo[96];
extern const char PROGMEM oled_section_break[6];

void add_keylog(uint16_t keycode, keyrecord_t* record);
void render_keylock_status(led_t led_state);
void render_keylogger_status(void);
void render_layer_status(const char* layer_name);
void render_mod_status(uint8_t modifiers);
void update_layer_namebuf(layer_state_t layer, bool force_update);

A keyboards/tominabox1/le_chiffre/post_config.h => keyboards/tominabox1/le_chiffre/post_config.h +14 -0
@@ 0,0 1,14 @@
// Copyright 2023 The QMK Community (@qmk)
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#if defined(OLED_ENABLE)
#    if !defined(OLED_UPDATE_INTERVAL)
#        define OLED_UPDATE_INTERVAL 5
#    endif

#    if !defined(OLED_SECTION_BREAK)
#        define OLED_SECTION_BREAK "-----"
#    endif
#endif

Do not follow this link