548 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			548 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// Copyright 2022 Chris Hoage (@chrishoage)
 | 
						|
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
						|
 | 
						|
#include "spleeb.h"
 | 
						|
#include "transactions.h"
 | 
						|
 | 
						|
#ifdef CONSOLE_ENABLE
 | 
						|
#    include "print.h"
 | 
						|
#endif // CONSOLE_ENABLE
 | 
						|
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
#    include "drivers/sensors/cirque_pinnacle_gestures.h"
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
#if defined(POINTING_DEVICE_ENABLE) || defined(SPLEEB_ENCODER_MODE_MAP_ENABLE)
 | 
						|
typedef union {
 | 
						|
    uint16_t raw;
 | 
						|
    struct {
 | 
						|
        uint8_t pointer_default_dpi : 4; // 16 steps available.
 | 
						|
        uint8_t pointer_sniping_dpi : 2; // 4 steps available.
 | 
						|
        uint8_t enc_modes[NUM_ENCODERS];
 | 
						|
        bool    is_dragscroll_enabled : 1;
 | 
						|
        bool    is_sniping_enabled : 1;
 | 
						|
    } __attribute__((packed));
 | 
						|
} spleeb_config_t;
 | 
						|
 | 
						|
static spleeb_config_t g_spleeb_config = {0};
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Set the value of `config` from EEPROM.
 | 
						|
 *
 | 
						|
 * Note that `is_dragscroll_enabled` and `is_sniping_enabled` are purposefully
 | 
						|
 * ignored since we do not want to persist this state to memory.  In practice,
 | 
						|
 * this state is always written to maximize write-performances.  Therefore, we
 | 
						|
 * explicitly set them to `false` in this function.
 | 
						|
 */
 | 
						|
static void read_spleeb_config_from_eeprom(spleeb_config_t* config) {
 | 
						|
    config->raw                   = eeconfig_read_kb() & 0xffff;
 | 
						|
    config->is_dragscroll_enabled = false;
 | 
						|
    config->is_sniping_enabled    = false;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Save the value of `config` to eeprom.
 | 
						|
 *
 | 
						|
 * Note that all values are written verbatim, including whether drag-scroll
 | 
						|
 * and/or sniper mode are enabled.  `read_spleeb_config_from_eeprom(…)`
 | 
						|
 * resets these 2 values to `false` since it does not make sense to persist
 | 
						|
 * these across reboots of the board.
 | 
						|
 */
 | 
						|
static void write_spleeb_config_to_eeprom(spleeb_config_t* config) {
 | 
						|
    eeconfig_update_kb(config->raw);
 | 
						|
}
 | 
						|
 | 
						|
void eeconfig_init_kb(void) {
 | 
						|
    g_spleeb_config.raw                 = 0;
 | 
						|
    g_spleeb_config.pointer_default_dpi = 4;
 | 
						|
 | 
						|
#    ifdef SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
    for (size_t i = 0; i < NUM_ENCODERS; i++) {
 | 
						|
        if (spleeb_encoder_mode_map[i][0].initalized) {
 | 
						|
            spleeb_enc_mode_t* first_enc_mode = &spleeb_encoder_mode_map[i][0];
 | 
						|
            g_spleeb_config.enc_modes[i]      = first_enc_mode->mode;
 | 
						|
        }
 | 
						|
    }
 | 
						|
#    endif // SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
 | 
						|
    write_spleeb_config_to_eeprom(&g_spleeb_config);
 | 
						|
    eeconfig_init_user();
 | 
						|
}
 | 
						|
 | 
						|
void matrix_init_kb(void) {
 | 
						|
    read_spleeb_config_from_eeprom(&g_spleeb_config);
 | 
						|
    matrix_init_user();
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_config_sync_handler(uint8_t initiator2target_buffer_size, const void* initiator2target_buffer, uint8_t target2initiator_buffer_size, void* target2initiator_buffer) {
 | 
						|
    if (initiator2target_buffer_size == sizeof(g_spleeb_config)) {
 | 
						|
        memcpy(&g_spleeb_config, initiator2target_buffer, sizeof(g_spleeb_config));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void keyboard_post_init_kb(void) {
 | 
						|
    transaction_register_rpc(RPC_ID_KB_CONFIG_SYNC, spleeb_config_sync_handler);
 | 
						|
    keyboard_post_init_user();
 | 
						|
}
 | 
						|
 | 
						|
void housekeeping_task_kb(void) {
 | 
						|
    if (is_keyboard_master()) {
 | 
						|
        // Keep track of the last state, so that we can tell if we need to propagate to slave.
 | 
						|
        static spleeb_config_t last_spleeb_config = {0};
 | 
						|
        static uint32_t        last_sync          = 0;
 | 
						|
        bool                   needs_sync         = false;
 | 
						|
 | 
						|
        // Check if the state values are different.
 | 
						|
        if (memcmp(&g_spleeb_config, &last_spleeb_config, sizeof(g_spleeb_config))) {
 | 
						|
            needs_sync = true;
 | 
						|
            memcpy(&last_spleeb_config, &g_spleeb_config, sizeof(g_spleeb_config));
 | 
						|
        }
 | 
						|
        // Send to slave every 500ms regardless of state change.
 | 
						|
        if (timer_elapsed32(last_sync) > 500) {
 | 
						|
            needs_sync = true;
 | 
						|
        }
 | 
						|
 | 
						|
        // Perform the sync if requested.
 | 
						|
        if (needs_sync) {
 | 
						|
            if (transaction_rpc_send(RPC_ID_KB_CONFIG_SYNC, sizeof(g_spleeb_config), &g_spleeb_config)) {
 | 
						|
                last_sync = timer_read32();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    // No need to invoke the user-specific callback, as it's been called
 | 
						|
    // already.
 | 
						|
}
 | 
						|
#endif // defined(POINTING_DEVICE_ENABLE) || defined(SPLEEB_ENCODER_MODE_MAP_ENABLE)
 | 
						|
 | 
						|
#ifdef SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Handle the encoder mode action when triggered by encoder_update_kb
 | 
						|
 *
 | 
						|
 * Weakly defined fuction intended to be overridden in a users keymap
 | 
						|
 */
 | 
						|
__attribute__((weak)) void spleeb_encoder_mode_trigger(uint8_t mode, bool clockwise) {}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    uint8_t            index;
 | 
						|
    spleeb_enc_mode_t* enc_mode;
 | 
						|
} spleeb_found_enc_mode_t;
 | 
						|
 | 
						|
static spleeb_found_enc_mode_t spleeb_get_found_encoder_mode(spleeb_config_t* config, uint8_t index) {
 | 
						|
    spleeb_found_enc_mode_t found_enc_mode;
 | 
						|
 | 
						|
    for (size_t i = 0; i < SPLEEB_ENCODER_MODE_COUNT; i++) {
 | 
						|
        spleeb_enc_mode_t* cur_enc_mode = &spleeb_encoder_mode_map[index][i];
 | 
						|
        if (cur_enc_mode->mode == config->enc_modes[index]) {
 | 
						|
            found_enc_mode.index    = i;
 | 
						|
            found_enc_mode.enc_mode = cur_enc_mode;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return found_enc_mode;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Step through the defined encoder modes for the encoder at the given
 | 
						|
 * index
 | 
						|
 *
 | 
						|
 * Step though the modes defined in spleeb_encoder_mode_map at the users keymap.
 | 
						|
 * Use a null terminator at the first character on the name property for the
 | 
						|
 * enc_mode struct to determine if we've reached the end of the defined encoder
 | 
						|
 * modes. When this happens loop back to the beginning.
 | 
						|
 */
 | 
						|
static void spleeb_step_encoder_mode(spleeb_config_t* config, uint8_t index) {
 | 
						|
    spleeb_found_enc_mode_t cur_enc_mode  = spleeb_get_found_encoder_mode(config, index);
 | 
						|
    spleeb_enc_mode_t*      next_enc_mode = &spleeb_encoder_mode_map[index][(cur_enc_mode.index + 1) % SPLEEB_ENCODER_MODE_COUNT];
 | 
						|
 | 
						|
    if (!next_enc_mode->initalized) {
 | 
						|
        next_enc_mode = &spleeb_encoder_mode_map[index][0];
 | 
						|
    }
 | 
						|
 | 
						|
    if (next_enc_mode->initalized) {
 | 
						|
        config->enc_modes[index] = next_enc_mode->mode;
 | 
						|
        write_spleeb_config_to_eeprom(config);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
bool encoder_update_kb(uint8_t index, bool clockwise) {
 | 
						|
    if (!encoder_update_user(index, clockwise)) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    spleeb_encoder_mode_trigger(g_spleeb_config.enc_modes[index], clockwise);
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
#endif // SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
/** \brief Return the current value of the pointer's default DPI. */
 | 
						|
static uint16_t get_pointer_default_dpi(spleeb_config_t* config) {
 | 
						|
    return (uint16_t)config->pointer_default_dpi * SPLEEB_DEFAULT_DPI_CONFIG_STEP + SPLEEB_MINIMUM_DEFAULT_DPI;
 | 
						|
}
 | 
						|
 | 
						|
/** \brief Return the current value of the pointer's sniper-mode DPI. */
 | 
						|
static uint16_t get_pointer_sniping_dpi(spleeb_config_t* config) {
 | 
						|
    return (uint16_t)config->pointer_sniping_dpi * SPLEEB_SNIPING_DPI_CONFIG_STEP + SPLEEB_MINIMUM_SNIPING_DPI;
 | 
						|
}
 | 
						|
 | 
						|
/** \brief Return the current value of the pointer's default DPI. */
 | 
						|
static uint16_t get_pointer_current_dpi(spleeb_config_t* config) {
 | 
						|
    if (config->is_sniping_enabled) {
 | 
						|
        return get_pointer_sniping_dpi(config);
 | 
						|
    } else {
 | 
						|
        return get_pointer_default_dpi(config);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/** \brief Set the appropriate DPI for the input config. */
 | 
						|
static void maybe_update_pointing_device_cpi(spleeb_config_t* config) {
 | 
						|
    if (config->is_sniping_enabled) {
 | 
						|
        pointing_device_set_cpi(get_pointer_sniping_dpi(config));
 | 
						|
    } else {
 | 
						|
        pointing_device_set_cpi(get_pointer_default_dpi(config));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Update the pointer's default DPI to the next or previous step.
 | 
						|
 *
 | 
						|
 * Increases the DPI value if `forward` is `true`, decreases it otherwise.
 | 
						|
 * The increment/decrement steps are equal to SPLEEB_DEFAULT_DPI_CONFIG_STEP.
 | 
						|
 */
 | 
						|
static void step_pointer_default_dpi(spleeb_config_t* config, bool forward) {
 | 
						|
    config->pointer_default_dpi += forward ? 1 : -1;
 | 
						|
    maybe_update_pointing_device_cpi(config);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Update the pointer's sniper-mode DPI to the next or previous step.
 | 
						|
 *
 | 
						|
 * Increases the DPI value if `forward` is `true`, decreases it otherwise.
 | 
						|
 * The increment/decrement steps are equal to SPLEEB_SNIPING_DPI_CONFIG_STEP.
 | 
						|
 */
 | 
						|
static void step_pointer_sniping_dpi(spleeb_config_t* config, bool forward) {
 | 
						|
    config->pointer_sniping_dpi += forward ? 1 : -1;
 | 
						|
    maybe_update_pointing_device_cpi(config);
 | 
						|
}
 | 
						|
 | 
						|
uint16_t spleeb_get_pointer_default_dpi(void) {
 | 
						|
    return get_pointer_default_dpi(&g_spleeb_config);
 | 
						|
}
 | 
						|
 | 
						|
uint16_t spleeb_get_pointer_sniping_dpi(void) {
 | 
						|
    return get_pointer_sniping_dpi(&g_spleeb_config);
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_cycle_pointer_default_dpi_noeeprom(bool forward) {
 | 
						|
    step_pointer_default_dpi(&g_spleeb_config, forward);
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_cycle_pointer_default_dpi(bool forward) {
 | 
						|
    step_pointer_default_dpi(&g_spleeb_config, forward);
 | 
						|
    write_spleeb_config_to_eeprom(&g_spleeb_config);
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_cycle_pointer_sniping_dpi_noeeprom(bool forward) {
 | 
						|
    step_pointer_sniping_dpi(&g_spleeb_config, forward);
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_cycle_pointer_sniping_dpi(bool forward) {
 | 
						|
    step_pointer_sniping_dpi(&g_spleeb_config, forward);
 | 
						|
    write_spleeb_config_to_eeprom(&g_spleeb_config);
 | 
						|
}
 | 
						|
 | 
						|
bool spleeb_get_pointer_sniping_enabled(void) {
 | 
						|
    return g_spleeb_config.is_sniping_enabled;
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_set_pointer_sniping_enabled(bool enable) {
 | 
						|
    g_spleeb_config.is_sniping_enabled = enable;
 | 
						|
    maybe_update_pointing_device_cpi(&g_spleeb_config);
 | 
						|
}
 | 
						|
 | 
						|
bool spleeb_get_pointer_dragscroll_enabled(void) {
 | 
						|
    return g_spleeb_config.is_dragscroll_enabled;
 | 
						|
}
 | 
						|
 | 
						|
void spleeb_set_pointer_dragscroll_enabled(bool enable) {
 | 
						|
    g_spleeb_config.is_dragscroll_enabled = enable;
 | 
						|
    cirque_pinnacle_enable_cursor_glide(enable);
 | 
						|
    maybe_update_pointing_device_cpi(&g_spleeb_config);
 | 
						|
}
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
void pointing_device_init_kb(void) {
 | 
						|
    maybe_update_pointing_device_cpi(&g_spleeb_config);
 | 
						|
 | 
						|
    // only glide on drag scroll
 | 
						|
    cirque_pinnacle_enable_cursor_glide(false);
 | 
						|
 | 
						|
    set_auto_mouse_enable(true);
 | 
						|
    pointing_device_init_user();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Augment the pointing device behavior.
 | 
						|
 *
 | 
						|
 * Drag-scroll implementation borrowed from https://github.com/qmk/qmk_firmware/pull/18218
 | 
						|
 */
 | 
						|
static void pointing_device_task_spleeb(report_mouse_t* mouse_report) {
 | 
						|
    static int16_t scroll_x = 0;
 | 
						|
    static int16_t scroll_y = 0;
 | 
						|
    if (g_spleeb_config.is_dragscroll_enabled) {
 | 
						|
        scroll_x -= mouse_report->x;
 | 
						|
        scroll_y += mouse_report->y;
 | 
						|
        mouse_report->h = scroll_x / SPLEEB_DRAGSCROLL_DIVISOR;
 | 
						|
        mouse_report->v = scroll_y / SPLEEB_DRAGSCROLL_DIVISOR;
 | 
						|
        mouse_report->x = 0;
 | 
						|
        mouse_report->y = 0;
 | 
						|
        scroll_x -= (int16_t)mouse_report->h * SPLEEB_DRAGSCROLL_DIVISOR;
 | 
						|
        scroll_y -= (int16_t)mouse_report->v * SPLEEB_DRAGSCROLL_DIVISOR;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
 | 
						|
    if (is_keyboard_master()) {
 | 
						|
        pointing_device_task_spleeb(&mouse_report);
 | 
						|
 | 
						|
        mouse_report = pointing_device_task_user(mouse_report);
 | 
						|
    }
 | 
						|
 | 
						|
    return mouse_report;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Outputs the Spleeb configuration to console.
 | 
						|
 *
 | 
						|
 * Prints the in-memory configuration structure to console, for debugging.
 | 
						|
 * Includes:
 | 
						|
 *   - raw value
 | 
						|
 *   - drag-scroll: on/off
 | 
						|
 *   - sniping: on/off
 | 
						|
 *   - default DPI: internal table index/actual DPI
 | 
						|
 *   - sniping DPI: internal table index/actual DPI
 | 
						|
 */
 | 
						|
static void debug_spleeb_config_to_console(spleeb_config_t* config) {
 | 
						|
#    ifdef CONSOLE_ENABLE
 | 
						|
    pd_dprintf("(spleeb) process_record_kb: config = {\n"
 | 
						|
               "\traw = 0x%u,\n"
 | 
						|
               "\t{\n"
 | 
						|
               "\t\tis_dragscroll_enabled=%u\n"
 | 
						|
               "\t\tis_sniping_enabled=%u\n"
 | 
						|
               "\t\tdefault_dpi=0x%X (%u)\n"
 | 
						|
               "\t\tsniping_dpi=0x%X (%u)\n"
 | 
						|
               "\t}\n"
 | 
						|
               "}\n",
 | 
						|
               config->raw, config->is_dragscroll_enabled, config->is_sniping_enabled, config->pointer_default_dpi, get_pointer_default_dpi(config), config->pointer_sniping_dpi, get_pointer_sniping_dpi(config));
 | 
						|
#    endif // CONSOLE_ENABLE
 | 
						|
}
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
 | 
						|
    if (!process_record_user(keycode, record)) {
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
        debug_spleeb_config_to_console(&g_spleeb_config);
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
    switch (keycode) {
 | 
						|
        case POINTER_DEFAULT_DPI_FORWARD:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_cycle_pointer_default_dpi(true);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case POINTER_DEFAULT_DPI_REVERSE:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_cycle_pointer_default_dpi(false);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case POINTER_SNIPING_DPI_FORWARD:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_cycle_pointer_sniping_dpi(true);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case POINTER_SNIPING_DPI_REVERSE:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_cycle_pointer_sniping_dpi(false);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case SNIPING_MODE:
 | 
						|
            spleeb_set_pointer_sniping_enabled(record->event.pressed);
 | 
						|
            break;
 | 
						|
        case SNIPING_MODE_TOGGLE:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_set_pointer_sniping_enabled(!spleeb_get_pointer_sniping_enabled());
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case DRAGSCROLL_MODE:
 | 
						|
            spleeb_set_pointer_dragscroll_enabled(record->event.pressed);
 | 
						|
            break;
 | 
						|
        case DRAGSCROLL_MODE_TOGGLE:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_set_pointer_dragscroll_enabled(!spleeb_get_pointer_dragscroll_enabled());
 | 
						|
            }
 | 
						|
            break;
 | 
						|
    }
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
#ifdef SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
    switch (keycode) {
 | 
						|
        case ENC_MODE_STEP_LEFT:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_step_encoder_mode(&g_spleeb_config, 0);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        case ENC_MODE_STEP_RIGHT:
 | 
						|
            if (record->event.pressed) {
 | 
						|
                spleeb_step_encoder_mode(&g_spleeb_config, 1);
 | 
						|
            }
 | 
						|
            break;
 | 
						|
    }
 | 
						|
#endif // SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
    if ((keycode >= POINTER_DEFAULT_DPI_FORWARD && keycode <= ENC_MODE_STEP_RIGHT) || IS_MOUSEKEY(keycode)) {
 | 
						|
        debug_spleeb_config_to_console(&g_spleeb_config);
 | 
						|
    }
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
bool is_mouse_record_kb(uint16_t keycode, keyrecord_t* record) {
 | 
						|
    switch (keycode) {
 | 
						|
        case DRAGSCROLL_MODE:
 | 
						|
        case SNIPING_MODE:
 | 
						|
            return true;
 | 
						|
        default:
 | 
						|
            return false;
 | 
						|
    }
 | 
						|
 | 
						|
    return is_mouse_record_user(keycode, record);
 | 
						|
}
 | 
						|
 | 
						|
#endif // POINTING_DEVICE_ENABLE
 | 
						|
 | 
						|
#ifdef OLED_ENABLE
 | 
						|
 | 
						|
static void render_layer(void) {
 | 
						|
    oled_write_P(PSTR("LAYER: "), false);
 | 
						|
 | 
						|
    switch (get_highest_layer(layer_state)) {
 | 
						|
        case 0:
 | 
						|
            oled_write_ln_P(PSTR("\xC0\xC1"), false);
 | 
						|
            break;
 | 
						|
        case 1:
 | 
						|
            oled_write_ln_P(PSTR("\xC2\xC3"), false);
 | 
						|
            break;
 | 
						|
        case 2:
 | 
						|
            oled_write_ln_P(PSTR("\xC4\xC5"), false);
 | 
						|
            break;
 | 
						|
        case 3:
 | 
						|
            oled_write_ln_P(PSTR("\xC6\xC7"), false);
 | 
						|
            break;
 | 
						|
        case 4:
 | 
						|
            oled_write_ln_P(PSTR("\xC8\xC9"), false);
 | 
						|
            break;
 | 
						|
        case 5:
 | 
						|
            oled_write_ln_P(PSTR("\xCA\xCB"), false);
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            oled_write_ln_P(get_u8_str(get_highest_layer(layer_state) + 0x30, ' '), true);
 | 
						|
    }
 | 
						|
 | 
						|
    oled_write_ln_P("", false);
 | 
						|
}
 | 
						|
 | 
						|
static void render_mods(void) {
 | 
						|
    uint8_t modifiers = get_mods();
 | 
						|
 | 
						|
    oled_write_ln_P(PSTR("MODS:"), false);
 | 
						|
    oled_write_ln_P("", false);
 | 
						|
    oled_write_P(PSTR("\325\326"), (modifiers & MOD_MASK_SHIFT));
 | 
						|
    oled_write_P(PSTR("\327\330"), (modifiers & MOD_MASK_CTRL));
 | 
						|
    oled_write_P(PSTR("\331\332"), (modifiers & MOD_MASK_ALT));
 | 
						|
    oled_write_ln_P(PSTR("\333\334"), (modifiers & MOD_MASK_GUI));
 | 
						|
    oled_write_ln_P("", false);
 | 
						|
}
 | 
						|
 | 
						|
static void render_lock(void) {
 | 
						|
    led_t led_state = host_keyboard_led_state();
 | 
						|
 | 
						|
    oled_write_P(PSTR("LOCK: "), false);
 | 
						|
    oled_write_P(PSTR("\235\236"), led_state.caps_lock);
 | 
						|
    oled_write_ln_P(PSTR("\275\276"), led_state.num_lock);
 | 
						|
}
 | 
						|
 | 
						|
static void render_pointer(void) {
 | 
						|
#    ifdef POINTING_DEVICE_ENABLE
 | 
						|
    oled_write_ln_P(PSTR("POINTER:"), false);
 | 
						|
    oled_write_ln_P("", false);
 | 
						|
    oled_write_P(PSTR("dpi:"), false);
 | 
						|
    oled_write_ln_P(get_u16_str(get_pointer_current_dpi(&g_spleeb_config), ' '), false);
 | 
						|
    oled_write_ln_P("", false);
 | 
						|
#    endif // POINTING_DEVICE_ENABLE
 | 
						|
}
 | 
						|
 | 
						|
#    ifdef SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
static uint8_t spleeb_get_encoder_mode(spleeb_config_t* config, uint8_t index) {
 | 
						|
    spleeb_found_enc_mode_t found_enc_mode = spleeb_get_found_encoder_mode(config, index);
 | 
						|
    return found_enc_mode.enc_mode->mode;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * \brief Map an encoder mode to a string to be displayed on the OLED
 | 
						|
 *
 | 
						|
 * Weakly defined fuction intended to be overridden in a users keymap. My be
 | 
						|
 * omitted if no OLED is used.
 | 
						|
 */
 | 
						|
__attribute__((weak)) const char* spleeb_encoder_mode_string(uint8_t mode) {
 | 
						|
    return get_u8_str(mode, ' ');
 | 
						|
}
 | 
						|
#    endif //  SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
 | 
						|
static void render_encoder(void) {
 | 
						|
#    ifdef SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
    oled_write_ln_P(PSTR("ENCODER:"), false);
 | 
						|
    oled_write_ln_P("", false);
 | 
						|
    oled_write_P(PSTR("R: "), false);
 | 
						|
    oled_write_ln_P(spleeb_encoder_mode_string(spleeb_get_encoder_mode(&g_spleeb_config, 1)), false);
 | 
						|
    oled_write_P(PSTR("L: "), false);
 | 
						|
    oled_write_ln_P(spleeb_encoder_mode_string(spleeb_get_encoder_mode(&g_spleeb_config, 0)), false);
 | 
						|
#    endif //  SPLEEB_ENCODER_MODE_MAP_ENABLE
 | 
						|
}
 | 
						|
 | 
						|
static void render_status(void) {
 | 
						|
    render_layer();
 | 
						|
    render_mods();
 | 
						|
    render_lock();
 | 
						|
    render_pointer();
 | 
						|
    render_encoder();
 | 
						|
}
 | 
						|
 | 
						|
oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
 | 
						|
    return OLED_ROTATION_90;
 | 
						|
}
 | 
						|
 | 
						|
bool oled_task_kb(void) {
 | 
						|
    if (is_keyboard_master()) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!oled_task_user()) {
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    render_status();
 | 
						|
    return false;
 | 
						|
}
 | 
						|
#endif // OLED_ENABLE
 |