qmk_firmware/users/drashna/oled/oled_stuff.c
Jeff Epler 9632360caa
Use a macro to compute the size of arrays at compile time (#18044)
* Add ARRAY_SIZE and CEILING utility macros

* Apply a coccinelle patch to use ARRAY_SIZE

* fix up some straggling items

* Fix 'make test:secure'

* Enhance ARRAY_SIZE macro to reject acting on pointers

The previous definition would not produce a diagnostic for
```
int *p;
size_t num_elem = ARRAY_SIZE(p)
```
but the new one will.

* explicitly get definition of ARRAY_SIZE

* Convert to ARRAY_SIZE when const is involved

The following spatch finds additional instances where the array is
const and the division is by the size of the type, not the size of
the first element:
```
@ rule5a using "empty.iso" @
type T;
const T[] E;
@@

- (sizeof(E)/sizeof(T))
+ ARRAY_SIZE(E)

@ rule6a using "empty.iso" @
type T;
const T[] E;
@@

- sizeof(E)/sizeof(T)
+ ARRAY_SIZE(E)
```

* New instances of ARRAY_SIZE added since initial spatch run

* Use `ARRAY_SIZE` in docs (found by grep)

* Manually use ARRAY_SIZE

hs_set is expected to be the same size as uint16_t, though it's made
of two 8-bit integers

* Just like char, sizeof(uint8_t) is guaranteed to be 1

This is at least true on any plausible system where qmk is actually used.

Per my understanding it's universally true, assuming that uint8_t exists:
https://stackoverflow.com/questions/48655310/can-i-assume-that-sizeofuint8-t-1

* Run qmk-format on core C files touched in this branch

Co-authored-by: Stefan Kerkmann <karlk90@pm.me>
2022-08-30 10:20:04 +02:00

998 lines
42 KiB
C

/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2021 John Ezra - wpm graph
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "drashna.h"
#ifdef UNICODE_COMMON_ENABLE
# include "process_unicode_common.h"
# include "keyrecords/unicode.h"
#endif
#ifdef AUDIO_CLICKY
# include "process_clicky.h"
#endif
#if defined(AUTOCORRECTION_ENABLE)
# include "keyrecords/autocorrection/autocorrection.h"
#endif
#include <string.h>
bool is_oled_enabled = true;
extern bool host_driver_disabled;
uint32_t oled_timer = 0;
char keylog_str[OLED_KEYLOGGER_LENGTH] = {0};
static uint16_t log_timer = 0;
#ifdef OLED_DISPLAY_VERBOSE
const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0};
#endif
deferred_token kittoken;
// clang-format off
static const char PROGMEM code_to_name[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B c D E F
' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', // 0x
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', // 1x
'3', '4', '5', '6', '7', '8', '9', '0', 20, 19, 27, 26, 22, '-', '=', '[', // 2x
']','\\', '#', ';','\'', '`', ',', '.', '/', 128,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA, // 3x
0xDB,0xDC,0xDD,0xDE,0XDF,0xFB,'P', 'S', 19, ' ', 17, 30, 16, 16, 31, 26, // 4x
27, 25, 24, 'N', '/', '*', '-', '+', 23, '1', '2', '3', '4', '5', '6', '7', // 5x
'8', '9', '0', '.','\\', 'A', 0, '=', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 6x
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 7x
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 8x
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // 9x
' ', ' ', ' ', ' ', ' ', 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // Ax
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // Bx
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // Cx
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', // Dx
'C', 'S', 'A', 'C', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 24, 26, 24, // Ex
25,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D,0x9D, 24, 25, 27, 26, ' ', ' ', ' ' // Fx
};
// clang-format on
/**
* @brief parses pressed keycodes and saves to buffer
*
* @param keycode Keycode pressed from switch matrix
* @param record keyrecord_t data structure
*/
void add_keylog(uint16_t keycode, keyrecord_t *record) {
if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) || (keycode >= QK_MODS && keycode <= QK_MODS_MAX)) {
if (((keycode & 0xFF) == KC_BSPC) && mod_config(get_mods() | get_oneshot_mods()) & MOD_MASK_CTRL) {
memset(keylog_str, ' ', OLED_KEYLOGGER_LENGTH);
return;
}
if (record->tap.count) {
keycode &= 0xFF;
} else if (keycode > 0xFF) {
return;
}
}
if (keycode > 0xFF) {
return;
}
memmove(keylog_str, keylog_str + 1, OLED_KEYLOGGER_LENGTH - 1);
if (keycode < ARRAY_SIZE(code_to_name)) {
keylog_str[(OLED_KEYLOGGER_LENGTH - 1)] = pgm_read_byte(&code_to_name[keycode]);
}
log_timer = timer_read();
}
/**
* @brief Keycode handler for oled display.
*
* This adds pressed keys to buffer, but also resets the oled timer
*
* @param keycode Keycode from matrix
* @param record keyrecord data struture
* @return true
* @return false
*/
bool process_record_user_oled(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
oled_timer_reset();
add_keylog(keycode, record);
}
return true;
}
void oled_timer_reset(void) {
oled_timer = timer_read32();
}
/**
* @brief Renders keylogger buffer to oled
*
*/
void render_keylogger_status(uint8_t col, uint8_t line) {
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(col, line);
#endif
oled_write_P(PSTR(OLED_RENDER_KEYLOGGER), false);
oled_write(keylog_str, false);
#ifdef OLED_DISPLAY_VERBOSE
oled_advance_page(true);
#endif
}
/**
* @brief Renders default layer state (aka layout) to oled
*
*/
void render_default_layer_state(uint8_t col, uint8_t line) {
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(col, line);
#endif
oled_write_P(PSTR(OLED_RENDER_LAYOUT_NAME), false);
switch (get_highest_layer(default_layer_state)) {
case _QWERTY:
oled_write_P(PSTR(OLED_RENDER_LAYOUT_QWERTY), false);
break;
case _COLEMAK_DH:
oled_write_P(PSTR(OLED_RENDER_LAYOUT_COLEMAK_DH), false);
break;
case _COLEMAK:
oled_write_P(PSTR(OLED_RENDER_LAYOUT_COLEMAK), false);
break;
case _DVORAK:
oled_write_P(PSTR(OLED_RENDER_LAYOUT_DVORAK), false);
break;
}
#ifdef OLED_DISPLAY_VERBOSE
oled_advance_page(true);
#endif
}
/**
* @brief Renders the active layers to the OLED
*
*/
void render_layer_state(uint8_t col, uint8_t line) {
#ifdef OLED_DISPLAY_VERBOSE
// clang-format off
static const char PROGMEM tri_layer_image[][3][24] = {
// base
{
{
0x00, 0x00, 0x00, 0x80, 0x80, 0x40,
0x40, 0x20, 0x20, 0x10, 0x10, 0x08,
0x08, 0x10, 0x10, 0x20, 0x20, 0x40,
0x40, 0x80, 0x80, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x88, 0x88, 0x5D,
0x5D, 0x3E, 0x3E, 0x7C, 0x7C, 0xF8,
0xF8, 0x7C, 0x7C, 0x3E, 0x3E, 0x5D,
0x5D, 0x88, 0x88, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x02, 0x02, 0x04, 0x04, 0x08,
0x08, 0x04, 0x04, 0x02, 0x02, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00
}
},
// raise
{
{
0x00, 0x00, 0x00, 0x80, 0x80, 0xC0,
0xC0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF8,
0xF8, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0,
0xC0, 0x80, 0x80, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x88, 0x88, 0x55,
0x55, 0x23, 0x23, 0x47, 0x47, 0x8F,
0x8F, 0x47, 0x47, 0x23, 0x23, 0x55,
0x55, 0x88, 0x88, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x02, 0x02, 0x04, 0x04, 0x08,
0x08, 0x04, 0x04, 0x02, 0x02, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00
}
},
// lower
{
{
0x00, 0x00, 0x00, 0x80, 0x80, 0x40,
0x40, 0x20, 0x20, 0x10, 0x10, 0x08,
0x08, 0x10, 0x10, 0x20, 0x20, 0x40,
0x40, 0x80, 0x80, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x88, 0x88, 0xD5,
0xD5, 0xE2, 0xE2, 0xC4, 0xC4, 0x88,
0x88, 0xC4, 0xC4, 0xE2, 0xE2, 0xD5,
0xD5, 0x88, 0x88, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x03, 0x03, 0x07, 0x07, 0x0F,
0x0F, 0x07, 0x07, 0x03, 0x03, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00
}
},
// adjust
{
{
0x00, 0x00, 0x00, 0x80, 0x80, 0x40,
0xC0, 0x60, 0xA0, 0x50, 0xB0, 0x58,
0xA8, 0x50, 0xB0, 0x60, 0xA0, 0x40,
0xC0, 0x80, 0x80, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x88, 0x88, 0x5D,
0xD5, 0x6B, 0xB6, 0x6D, 0xD6, 0xAD,
0xDA, 0x6D, 0xD6, 0x6B, 0xB6, 0x5D,
0xD5, 0x88, 0x88, 0x00, 0x00, 0x00
},
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x03, 0x02, 0x05, 0x06, 0x0D,
0x0A, 0x05, 0x06, 0x03, 0x02, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00
}
},
// blank
{
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
},
// better gamepad
{
{ 0, 0, 0,192,224,224,112,240,240,240,240,144,144,240,240,240,240,112,224,224,192, 0, 0, 0 },
{ 128,248,255,255,255,254,252,230,195,195,230,255,255,254,247,227,246,253,254,255,255,255,248,128 },
{ 7, 15, 15, 15, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 15, 15, 15, 7 }
},
// mouse
{
{ 0, 0, 0, 0, 0, 0, 0, 0,192, 32, 32, 32,160, 32, 32, 32,192, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0,240, 15, 0, 0, 0, 3, 0, 0, 0, 15,240, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 3, 6, 4, 4, 4, 4, 4, 4, 4, 6, 3, 0, 0, 0, 0, 0, 0 }
}
};
// clang-format on
uint8_t layer_is[4] = {0, 4, 4, 4};
if (layer_state_is(_ADJUST)) {
layer_is[0] = 3;
} else if (layer_state_is(_RAISE)) {
layer_is[0] = 1;
} else if (layer_state_is(_LOWER)) {
layer_is[0] = 2;
}
if (layer_state_is(_MOUSE)) {
layer_is[1] = 6;
}
if (layer_state_is(_GAMEPAD)) {
layer_is[2] = 5;
}
oled_set_cursor(col, line);
oled_write_raw_P(tri_layer_image[layer_is[0]][0], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 4, line);
oled_write_raw_P(tri_layer_image[layer_is[1]][0], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 8, line);
oled_write_raw_P(tri_layer_image[layer_is[2]][0], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 13, line);
oled_write_P(PSTR("Diablo2"), layer_state_is(_DIABLOII));
oled_advance_page(true);
oled_set_cursor(col, line + 1);
oled_write_raw_P(tri_layer_image[layer_is[0]][1], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 4, line + 1);
oled_write_raw_P(tri_layer_image[layer_is[1]][1], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 8, line + 1);
oled_write_raw_P(tri_layer_image[layer_is[2]][1], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 13, line + 1);
oled_write_P(PSTR("Diablo3"), layer_state_is(_DIABLO));
oled_advance_page(true);
oled_set_cursor(col, line + 2);
oled_write_raw_P(tri_layer_image[layer_is[0]][2], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 4, line + 2);
oled_write_raw_P(tri_layer_image[layer_is[1]][2], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 8, line + 2);
oled_write_raw_P(tri_layer_image[layer_is[2]][2], sizeof(tri_layer_image[0][0]));
oled_set_cursor(col + 13, line + 2);
oled_write_P(PSTR("Media"), layer_state_is(_MEDIA));
#else
oled_write_P(PSTR(OLED_RENDER_LAYER_NAME), false);
oled_write_P(PSTR(OLED_RENDER_LAYER_LOWER), layer_state_is(_LOWER));
oled_write_P(PSTR(OLED_RENDER_LAYER_RAISE), layer_state_is(_RAISE));
#endif
oled_advance_page(true);
}
/**
* @brief Renders the current lock status to oled
*
* @param led_usb_state Current keyboard led state
*/
void render_keylock_status(led_t led_usb_state, uint8_t col, uint8_t line) {
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(col, line);
#endif
#ifdef CAPS_WORD_ENABLE
led_usb_state.caps_lock |= is_caps_word_on();
#endif
oled_write_P(PSTR(OLED_RENDER_LOCK_NAME), false);
#if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
#endif
oled_write_P(PSTR(OLED_RENDER_LOCK_NUML), led_usb_state.num_lock);
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state.caps_lock);
#if defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state.scroll_lock);
#endif
}
/**
* @brief Renders the matrix scan rate to the host system
*
*/
void render_matrix_scan_rate(uint8_t padding, uint8_t col, uint8_t line) {
#ifdef DEBUG_MATRIX_SCAN_RATE
oled_set_cursor(col, line);
oled_write_P(PSTR("MS:"), false);
if (padding) {
for (uint8_t n = padding; n > 0; n--) {
oled_write_P(PSTR(" "), false);
}
}
oled_write(get_u16_str(get_matrix_scan_rate(), ' '), false);
#endif
}
/**
* @brief Renders the modifier state
*
* @param modifiers Modifiers to check against (real, weak, onesheot, etc;)
*/
void render_mod_status(uint8_t modifiers, uint8_t col, uint8_t line) {
static const char PROGMEM mod_status[5][3] = {{0xE8, 0xE9, 0}, {0xE4, 0xE5, 0}, {0xE6, 0xE7, 0}, {0xEA, 0xEB, 0}, {0xEC, 0xED, 0}};
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(col, line);
#endif
oled_write_P(PSTR(OLED_RENDER_MODS_NAME), false);
#if defined(OLED_DISPLAY_VERBOSE)
oled_write_P(mod_status[0], (modifiers & MOD_BIT(KC_LSHIFT)));
oled_write_P(mod_status[!keymap_config.swap_lctl_lgui ? 3 : 4], (modifiers & MOD_BIT(KC_LGUI)));
oled_write_P(mod_status[2], (modifiers & MOD_BIT(KC_LALT)));
oled_write_P(mod_status[1], (modifiers & MOD_BIT(KC_LCTL)));
oled_write_P(mod_status[1], (modifiers & MOD_BIT(KC_RCTL)));
oled_write_P(mod_status[2], (modifiers & MOD_BIT(KC_RALT)));
oled_write_P(mod_status[!keymap_config.swap_lctl_lgui ? 3 : 4], (modifiers & MOD_BIT(KC_RGUI)));
oled_write_P(mod_status[0], (modifiers & MOD_BIT(KC_RSHIFT)));
#else
oled_write_P(mod_status[0], (modifiers & MOD_MASK_SHIFT));
oled_write_P(mod_status[!keymap_config.swap_lctl_lgui ? 3 : 4], (modifiers & MOD_MASK_GUI));
oled_write_P(PSTR(" "), false);
oled_write_P(mod_status[2], (modifiers & MOD_MASK_ALT));
oled_write_P(mod_status[1], (modifiers & MOD_MASK_CTRL));
#endif
}
#ifdef SWAP_HANDS_ENABLE
extern bool swap_hands;
#endif
void render_bootmagic_status(uint8_t col, uint8_t line) {
/* Show Ctrl-Gui Swap options */
static const char PROGMEM logo[][2][3] = {
{{0x97, 0x98, 0}, {0xb7, 0xb8, 0}},
{{0x95, 0x96, 0}, {0xb5, 0xb6, 0}},
};
bool is_bootmagic_on;
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(col, line);
// oled_set_cursor(7, 3);
is_bootmagic_on = !keymap_config.swap_lctl_lgui;
#else
is_bootmagic_on = keymap_config.swap_lctl_lgui;
#endif
#ifdef OLED_DISPLAY_VERBOSE
if (keymap_config.swap_lctl_lgui)
#else
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NAME), false);
oled_write_P(PSTR(" "), false);
#endif
{
oled_write_P(logo[1][0], is_bootmagic_on);
#ifdef OLED_DISPLAY_VERBOSE
} else {
#endif
oled_write_P(logo[0][0], !is_bootmagic_on);
}
#ifndef OLED_DISPLAY_VERBOSE
oled_write_P(logo[1][1], is_bootmagic_on);
oled_write_P(logo[0][1], !is_bootmagic_on);
#endif
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NKRO), keymap_config.nkro);
oled_write_P(PSTR(" "), false);
#if defined(AUTOCORRECTION_ENABLE) || defined(AUTOCORRECT_ENABLE)
oled_write_P(PSTR("CRCT"), autocorrect_is_enabled());
oled_write_P(PSTR(" "), false);
#else
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NOGUI), keymap_config.no_gui);
#endif
#ifdef OLED_DISPLAY_VERBOSE
oled_set_cursor(col, line + 1);
if (keymap_config.swap_lctl_lgui) {
oled_write_P(logo[1][1], is_bootmagic_on);
} else {
oled_write_P(logo[0][1], !is_bootmagic_on);
}
#endif
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_ONESHOT), is_oneshot_enabled());
#ifdef SWAP_HANDS_ENABLE
oled_write_P(PSTR(" "), false);
oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_SWAP), swap_hands);
oled_write_P(PSTR(" "), false);
#endif
}
#if defined(CUSTOM_POINTING_DEVICE)
extern bool tap_toggling;
#endif
void render_user_status(uint8_t col, uint8_t line) {
#ifdef AUDIO_ENABLE
bool is_audio_on = false, l_is_clicky_on = false;
# ifdef SPLIT_KEYBOARD
is_audio_on = user_state.audio_enable;
# ifdef AUDIO_CLICKY
l_is_clicky_on = user_state.audio_clicky_enable;
# endif
# else
is_audio_on = is_audio_on();
# ifdef AUDIO_CLICKY
l_is_clicky_on = is_clicky_on();
# endif
# endif
#endif
#if defined(OLED_DISPLAY_VERBOSE)
oled_set_cursor(col, line);
#endif
oled_write_P(PSTR(OLED_RENDER_USER_NAME), false);
#if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
#endif
#if defined(RGB_MATRIX_ENABLE)
oled_write_P(PSTR(OLED_RENDER_USER_ANIM), userspace_config.rgb_matrix_idle_anim);
# if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
# endif
#elif defined(CUSTOM_POINTING_DEVICE)
static const char PROGMEM mouse_lock[3] = {0xF2, 0xF3, 0};
oled_write_P(mouse_lock, tap_toggling);
#endif
#ifdef AUDIO_ENABLE
static const char PROGMEM audio_status[2][3] = {{0xE0, 0xE1, 0}, {0xE2, 0xE3, 0}};
oled_write_P(audio_status[is_audio_on], false);
# ifdef AUDIO_CLICKY
static const char PROGMEM audio_clicky_status[2][3] = {{0xF4, 0xF5, 0}, {0xF6, 0xF7, 0}};
oled_write_P(audio_clicky_status[l_is_clicky_on && is_audio_on], false);
# if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
# endif
# endif
#endif
static const char PROGMEM rgb_layer_status[2][3] = {{0xEE, 0xEF, 0}, {0xF0, 0xF1, 0}};
oled_write_P(rgb_layer_status[userspace_config.rgb_layer_change], false);
static const char PROGMEM cat_mode[2][3] = {{0xF8, 0xF9, 0}, {0xF6, 0xF7, 0}};
oled_write_P(cat_mode[0], host_driver_disabled);
#if defined(UNICODE_COMMON_ENABLE)
static const char PROGMEM uc_mod_status[5][3] = {{0xEC, 0xED, 0}, {0x20, 0x20, 0}, {0x20, 0x20, 0}, {0x20, 0x20, 0}, {0xEA, 0xEB, 0}};
oled_write_P(uc_mod_status[get_unicode_input_mode()], false);
#endif
if (userspace_config.nuke_switch) {
#if !defined(OLED_DISPLAY_VERBOSE)
oled_write_P(PSTR(" "), false);
#endif
static const char PROGMEM nukem_good[2] = {0xFA, 0};
oled_write_P(nukem_good, false);
#if !defined(OLED_DISPLAY_VERBOSE)
oled_advance_page(true);
#endif
}
#if defined(OLED_DISPLAY_VERBOSE)
oled_advance_page(true);
#endif
}
void render_rgb_hsv(uint8_t col, uint8_t line) {
oled_set_cursor(col, line);
oled_write_P(PSTR("HSV: "), false);
#ifdef RGB_MATRIX_ENABLE
oled_write(get_u8_str(rgb_matrix_get_hue(), ' '), false);
oled_write_P(PSTR(", "), false);
oled_write(get_u8_str(rgb_matrix_get_sat(), ' '), false);
oled_write_P(PSTR(", "), false);
oled_write(get_u8_str(rgb_matrix_get_val(), ' '), false);
#elif RGBLIGHT_ENABLE
oled_write(get_u8_str(rgblight_get_hue(), ' '), false);
oled_write_P(PSTR(", "), false);
oled_write(get_u8_str(rgblight_get_sat(), ' '), false);
oled_write_P(PSTR(", "), false);
oled_write(get_u8_str(rgblight_get_val(), ' '), false);
#endif
}
void render_wpm(uint8_t padding, uint8_t col, uint8_t line) {
#ifdef WPM_ENABLE
oled_set_cursor(col, line);
oled_write_P(PSTR(OLED_RENDER_WPM_COUNTER), false);
if (padding) {
for (uint8_t n = padding; n > 0; n--) {
oled_write_P(PSTR(" "), false);
}
}
oled_write(get_u8_str(get_current_wpm(), ' '), false);
#endif
}
//============= USER CONFIG PARAMS ===============
// wpm graph originally designed by john-ezra
// for 128x128:
// max_lines_graph = 54;
// vertical_offset = 64;
// for 128x64:
// max_lines_graph = 64;
// vertical_offset = 0;
void render_wpm_graph(uint8_t max_lines_graph, uint8_t vertical_offset) {
#ifdef WPM_ENABLE
static uint16_t timer = 0;
static uint8_t x = OLED_DISPLAY_HEIGHT - 1;
uint8_t currwpm = get_current_wpm();
float max_wpm = OLED_WPM_GRAPH_MAX_WPM;
if (timer_elapsed(timer) > OLED_WPM_GRAPH_REFRESH_INTERVAL) { // check if it's been long enough before refreshing graph
x = (max_lines_graph - 1) - ((currwpm / max_wpm) * (max_lines_graph - 1)); // main calculation to plot graph line
for (uint8_t i = 0; i <= OLED_WPM_GRAPH_GRAPH_LINE_THICKNESS - 1; i++) { // first draw actual value line
oled_write_pixel(3, x + i + vertical_offset, true);
}
# ifdef OLED_WPM_GRAPH_VERTICAL_LINE
static uint8_t vert_count = 0;
if (vert_count == OLED_WPM_GRAPH_VERTCAL_LINE_INTERVAL) {
vert_count = 0;
while (x <= (max_lines_graph - 1)) {
oled_write_pixel(3, x + vertical_offset, true);
x++;
}
} else {
for (uint8_t i = (max_lines_graph - 1); i > x; i--) {
if (i % OLED_WPM_GRAPH_AREA_FILL_INTERVAL == 0) {
oled_write_pixel(3, i + vertical_offset, true);
}
}
vert_count++;
}
# else
for (int i = (max_lines_graph - 1); i > x; i--) {
if (i % OLED_WPM_GRAPH_AREA_FILL_INTERVAL == 0) {
oled_write_pixel(3, i + vertical_offset, true);
}
}
# endif
# include <math.h>
uint8_t y_start = ceil(vertical_offset / 8);
uint8_t y_length = y_start + ceil(max_lines_graph / 8);
oled_pan_section(false, y_start, y_length, 3, 125); // then move the entire graph one pixel to the right
timer = timer_read(); // refresh the timer for the next iteration
}
#endif
}
#if defined(POINTING_DEVICE_ENABLE)
void render_pointing_dpi_status(uint16_t cpi, uint8_t padding, uint8_t col, uint8_t line) {
oled_set_cursor(col, line);
oled_write_P(PSTR("CPI:"), false);
if (padding) {
for (uint8_t n = padding - 1; n > 0; n--) {
oled_write_P(PSTR(" "), false);
}
}
oled_write(get_u16_str(cpi, ' '), false);
}
#endif
// WPM-responsive animation stuff here
#define OLED_SLEEP_FRAMES 2
#define OLED_SLEEP_SPEED 10 // below this wpm value your animation will idle
#define OLED_WAKE_FRAMES 2 // uncomment if >1
#define OLED_WAKE_SPEED OLED_SLEEP_SPEED // below this wpm value your animation will idle
#define OLED_KAKI_FRAMES 3
#define OLED_KAKI_SPEED 40 // above this wpm value typing animation to triggere
#define OLED_RTOGI_FRAMES 2
//#define OLED_LTOGI_FRAMES 2
//#define ANIM_FRAME_DURATION 500 // how long each frame lasts in ms
// #define SLEEP_TIMER 60000 // should sleep after this period of 0 wpm, needs fixing
#define OLED_ANIM_SIZE 36
#define OLED_ANIM_ROWS 4
#define OLED_ANIM_MAX_FRAMES 3
#if (OLED_SLEEP_FRAMES > OLED_ANIM_MAX_FRAMES) || (OLED_WAKE_FRAMES > OLED_ANIM_MAX_FRAMES) || (OLED_KAKI_FRAMES > OLED_ANIM_MAX_FRAMES) || (OLED_RTOGI_FRAMES > OLED_ANIM_MAX_FRAMES)
# error frame size too large
#endif
static uint8_t animation_frame = 0;
static uint8_t animation_type = 0;
void render_kitty(uint8_t col, uint8_t line) {
// Images credit j-inc(/James Incandenza) and pixelbenny.
// Credit to obosob for initial animation approach.
// heavily modified by drashna because he's a glutton for punishment
// clang-format off
static const char PROGMEM animation[4][OLED_ANIM_MAX_FRAMES][OLED_ANIM_ROWS][OLED_ANIM_SIZE] = {
// sleep frames
{
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xa8, 0x48, 0xa8, 0x18, 0x08, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x80, 0x44, 0x84, 0x06, 0x05, 0x04, 0x80, 0x40, 0x20, 0x10, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x18, 0x04, 0x04, 0x02, 0x7a, 0x86, 0x01, 0x80, 0x80, 0x01, 0x03, 0x05, 0x07, 0x01, 0x00, 0x00, 0x80, 0x83, 0x45, 0xfa, 0x3c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28, 0x28, 0x29, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39, 0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x3a, 0x2a, 0x26, 0x22, 0x80, 0xc0, 0x80, 0x00, 0x24, 0x34, 0x2c, 0xe4, 0x60, 0x10, 0x70, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x38, 0x04, 0x02, 0x02, 0x01, 0x79, 0x87, 0x01, 0x80, 0x81, 0x83, 0x05, 0x05, 0x03, 0x01, 0x00, 0x00, 0x80, 0x43, 0x05, 0xfa, 0x3c, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x33, 0x24, 0x28, 0x28, 0x28, 0x29, 0x29, 0x3a, 0x18, 0x1c, 0x39, 0x24, 0x24, 0x3a, 0x2d, 0x26, 0x31, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00 }
}
},
// wake frames
{
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80, 0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x80, 0x40, 0x40, 0x5c, 0x00, 0x01, 0x41, 0x01, 0x00, 0x5c, 0x40, 0x40, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x00, 0x80, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x30, 0x08, 0x10, 0x60, 0x80, 0x00, 0x80, 0x60, 0x10, 0x08, 0x30, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x90, 0x12, 0x0a, 0x02, 0xf4, 0x09, 0x0d, 0xf1, 0x04, 0x02, 0x0a, 0x12, 0x90, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x80, 0xe1, 0x12, 0x0a, 0x06, 0x01, 0x81, 0x00, 0x06, 0x0a, 0x12, 0xe1, 0x80, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x11, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1c, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 }
}
},
// kaki frames
{
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x40, 0x80, 0x80, 0x80, 0x00, 0xfc, 0x84, 0x08, 0x08, 0x10, 0x20, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1e, 0x60, 0x80, 0x00, 0x00, 0x91, 0xa1, 0x80, 0x00, 0x00, 0x22, 0x84, 0x40, 0x50, 0x48, 0xc1, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x41, 0x82, 0xe2, 0x12, 0x0a, 0x06, 0x00, 0x80, 0x88, 0x4f, 0x02, 0x22, 0xe2, 0x9f, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x14, 0x10, 0x10, 0x10, 0x10, 0x10, 0x14, 0x14, 0x1f, 0x1a, 0x0a, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x06, 0x1a, 0x22, 0xc2, 0x04, 0x04, 0x04, 0x07, 0x00, 0xc0, 0x20, 0x10, 0x80, 0x80, 0x01, 0x01, 0x02, 0xfc, 0xfe, 0x02, 0x3c, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d, 0x55, 0x50, 0x94, 0xf0, 0x10, 0x09, 0x08, 0x00, 0x80, 0x00, 0x06, 0x09, 0x1b, 0xee, 0x00, 0x00, 0x00, 0x00, 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c, 0x14, 0x16, 0x15, 0x14, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x01, 0x02, 0x04, 0x04, 0x03, 0x80, 0x40, 0x40, 0x20, 0x00, 0x01, 0x02, 0x8c, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0d, 0x8d, 0x55, 0x50, 0x94, 0xf0, 0x10, 0x0a, 0x0e, 0x1d, 0x95, 0x24, 0x24, 0x27, 0x13, 0xe1, 0x01, 0x01, 0x01, 0x01, 0x02, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x14, 0x14, 0x10, 0x10, 0x11, 0x1f, 0x10, 0x10, 0x18, 0x0f, 0x18, 0x10, 0x10, 0x1f, 0x19, 0x18, 0x1c, 0x14, 0x14, 0x17, 0x14, 0x14, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00, 0x00 }
}
},
// rtogi frames
{
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x0f, 0x90, 0x10, 0x20, 0xf0, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x88, 0xc7, 0xc4, 0x62, 0x23, 0x11, 0x3f, 0x00, 0x00, 0x00, 0x00 },
{ 0x80, 0x40, 0x20, 0x10, 0x88, 0xcc, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
},
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x1f, 0xa0, 0x20, 0x40, 0x80, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x48, 0x47, 0x88, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x28, 0x6b, 0x40, 0xa0, 0x99, 0x86, 0xff, 0x00, 0x00, 0x00, 0x00 },
{ 0x0f, 0x11, 0x22, 0x44, 0x48, 0x4c, 0x43, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xc0, 0x80, 0x80, 0xc0, 0xe1, 0xfe, 0xb8, 0x88, 0x0c, 0x04, 0x06, 0x06, 0x06, 0x0e, 0x0e, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
}
}
};
// clang-format on
for (uint8_t i = 0; i < 4; i++) {
oled_set_cursor(col, line + i);
oled_write_raw_P(animation[animation_type][animation_frame][i], OLED_ANIM_SIZE);
}
}
void render_unicode_mode(uint8_t col, uint8_t line) {
#ifdef CUSTOM_UNICODE_ENABLE
oled_set_cursor(col, line);
oled_write_ln_P(PSTR("Unicode:"), false);
switch (typing_mode) {
case UCTM_WIDE:
oled_write_P(PSTR(" Wide"), false);
break;
case UCTM_SCRIPT:
oled_write_P(PSTR(" Script"), false);
break;
case UCTM_BLOCKS:
oled_write_P(PSTR(" Blocks"), false);
break;
case UCTM_REGIONAL:
oled_write_P(PSTR(" Regional"), false);
break;
case UCTM_AUSSIE:
oled_write_P(PSTR(" Aussie"), false);
break;
case UCTM_ZALGO:
oled_write_P(PSTR(" Zalgo"), false);
break;
case UCTM_NO_MODE:
oled_write_P(PSTR(" Normal"), false);
break;
default:
oled_write_P(PSTR(" Unknown"), false);
break;
}
#endif
}
uint32_t kitty_animation_phases(uint32_t triger_time, void *cb_arg) {
static uint32_t anim_frame_duration = 500;
#ifdef CUSTOM_POINTING_DEVICE
if (tap_toggling) {
animation_frame = (animation_frame + 1) % OLED_RTOGI_FRAMES;
animation_type = 3;
anim_frame_duration = 300;
} else
#endif
{
#ifdef WPM_ENABLE
if (get_current_wpm() <= OLED_SLEEP_SPEED) {
#endif
animation_frame = (animation_frame + 1) % OLED_SLEEP_FRAMES;
animation_type = 0;
anim_frame_duration = 500;
#ifdef WPM_ENABLE
} else if (get_current_wpm() > OLED_WAKE_SPEED) {
animation_frame = (animation_frame + 1) % OLED_WAKE_FRAMES;
animation_type = 1;
anim_frame_duration = 800;
} else if (get_current_wpm() >= OLED_KAKI_SPEED) {
animation_frame = (animation_frame + 1) % OLED_KAKI_FRAMES;
animation_type = 2;
anim_frame_duration = 500;
}
#endif
}
return anim_frame_duration;
}
void render_mouse_mode(uint8_t col, uint8_t line) {
#if (defined(KEYBOARD_bastardkb_charybdis) || defined(KEYBOARD_handwired_tractyl_manuform)) && defined(POINTING_DEVICE_ENABLE)
// credit and thanks to jaspertandy on discord for these images
static const char PROGMEM mouse_logo[3][2][16] = {// mouse icon
{{0, 0, 0, 252, 2, 2, 2, 58, 2, 2, 2, 252, 0, 0, 0, 0}, {0, 0, 63, 96, 64, 64, 64, 64, 64, 64, 64, 96, 63, 0, 0, 0}},
// crosshair icon
{{128, 240, 136, 228, 146, 138, 202, 127, 202, 138, 146, 228, 136, 240, 128, 0}, {0, 7, 8, 19, 36, 40, 41, 127, 41, 40, 36, 19, 8, 7, 0, 0}},
// dragscroll icon
{{0, 0, 112, 136, 156, 2, 15, 1, 15, 2, 140, 68, 56, 0, 0, 0}, {0, 0, 2, 6, 15, 28, 60, 124, 60, 28, 15, 6, 2, 0, 0, 0}}};
uint8_t image_index = 0;
# ifdef OLED_DISPLAY_TEST
image_index = animation_frame;
# else
if (charybdis_get_pointer_sniping_enabled()) {
image_index = 1;
} else if (charybdis_get_pointer_dragscroll_enabled()) {
image_index = 2;
}
# endif
oled_set_cursor(col, line);
oled_write_raw_P(mouse_logo[image_index][0], 16);
oled_set_cursor(col, line + 1);
oled_write_raw_P(mouse_logo[image_index][1], 16);
#endif
}
void render_status_right(void) {
#if defined(KEYBOARD_handwired_tractyl_manuform)
oled_set_cursor(7, 0);
oled_write_P(PSTR("Manuform"), true);
#elif defined(KEYBOARD_bastardkb_charybdis)
oled_set_cursor(6, 0);
oled_write_P(PSTR("Charybdis"), true);
#elif defined(KEYBOARD_splitkb_kyria)
oled_set_cursor(8, 0);
oled_write_P(PSTR("Kyria"), true);
#else
oled_set_cursor(8, 0);
oled_write_P(PSTR("Right"), true);
#endif
#if defined(OLED_DISPLAY_VERBOSE)
render_default_layer_state(1, 1);
#else
render_default_layer_state(0, 0);
#endif
/* Show Keyboard Layout */
render_layer_state(1, 2);
render_mod_status(get_mods() | get_oneshot_mods(), 1, 5);
#if !defined(OLED_DISPLAY_VERBOSE) && defined(WPM_ENABLE) && !defined(STM32F303xC)
render_wpm(2, 7, 1);
#endif
render_keylock_status(host_keyboard_led_state(), 1, 6);
}
void render_status_left(void) {
#if defined(OLED_DISPLAY_VERBOSE)
render_kitty(0, 1);
# if defined(KEYBOARD_handwired_tractyl_manuform)
oled_set_cursor(7, 0);
oled_write_P(PSTR("Tractyl"), true);
# elif defined(KEYBOARD_bastardkb_charybdis)
oled_set_cursor(6, 0);
oled_write_P(PSTR("Charybdis"), true);
# elif defined(KEYBOARD_splitkb_kyria)
oled_set_cursor(7, 0);
oled_write_P(PSTR("SplitKB"), true);
# elif defined(KEYBOARD_handwired_fingerpunch_rockon)
oled_set_cursor(7, 0);
oled_write_P(PSTR("Rock On"), true);
# else
oled_set_cursor(8, 0);
oled_write_P(PSTR("Left"), true);
# endif
# if defined(WPM_ENABLE)
render_wpm(1, 7, 1);
# elif defined(DEBUG_MATRIX_SCAN_RATE)
render_matrix_scan_rate(1, 7, 1);
# endif
# if (defined(KEYBOARD_bastardkb_charybdis) || defined(KEYBOARD_handwired_tractyl_manuform)) && defined(POINTING_DEVICE_ENABLE)
render_pointing_dpi_status(charybdis_get_pointer_sniping_enabled() ? charybdis_get_pointer_sniping_dpi() : charybdis_get_pointer_default_dpi(), 1, 7, 2);
render_mouse_mode(17, 1);
# elif defined(WPM_ENABLE) && defined(DEBUG_MATRIX_SCAN_RATE)
render_matrix_scan_rate(1, 7, 2);
# endif
/* Show Keyboard Layout */
render_bootmagic_status(7, 3);
render_user_status(1, 5);
render_keylogger_status(1, 6);
#else
render_default_layer_state(0, 0);
/* Show Keyboard Layout */
render_bootmagic_status(7, 3);
render_user_status(1, 5);
render_keylogger_status(1, 6);
#endif
}
__attribute__((weak)) void oled_render_large_display(bool side) {
if (!side) {
render_unicode_mode(1, 14);
}
}
__attribute__((weak)) oled_rotation_t oled_init_keymap(oled_rotation_t rotation) {
return rotation;
}
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
if (is_keyboard_master()) {
memset(keylog_str, ' ', OLED_KEYLOGGER_LENGTH);
}
kittoken = defer_exec(3000, kitty_animation_phases, NULL);
oled_clear();
oled_render();
return oled_init_keymap(rotation);
}
__attribute__((weak)) bool oled_task_keymap(void) {
return true;
}
bool oled_task_user(void) {
#ifndef OLED_DISPLAY_TEST
if (!is_oled_enabled) {
oled_off();
return false;
} else
#endif
{
oled_on();
}
if (!oled_task_keymap()) {
return false;
}
#if defined(OLED_DISPLAY_VERBOSE)
static const char PROGMEM header_image[] = {
0, 192, 32, 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 7, 15, 31, 63, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 63, 31, 15, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 192, 0,
// 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0
};
oled_write_raw_P(header_image, sizeof(header_image));
#endif
#ifndef OLED_DISPLAY_TEST
if (is_keyboard_left()) {
#endif
render_status_left();
#if defined(OLED_DISPLAY_128X128)
oled_render_large_display(true);
#endif
#ifndef OLED_DISPLAY_TEST
} else {
render_status_right();
# if defined(OLED_DISPLAY_128X128)
oled_render_large_display(false);
# endif
}
#endif
#if defined(OLED_DISPLAY_VERBOSE)
uint8_t num_of_rows;
# if defined(OLED_DISPLAY_128X128)
num_of_rows = 15;
# else
num_of_rows = 7;
# endif
for (uint8_t i = 1; i < num_of_rows; i++) {
oled_set_cursor(0, i);
oled_write_raw_P(display_border, sizeof(display_border));
oled_set_cursor(21, i);
oled_write_raw_P(display_border, sizeof(display_border));
}
static const char PROGMEM footer_image[] = {0, 3, 4, 8, 16, 32, 64, 128, 128, 128, 128, 128, 128, 128, 192, 224, 240, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 240, 224, 192, 128, 128, 128, 128, 128, 128, 128, 64, 32, 16, 8, 4, 3, 0};
oled_set_cursor(0, num_of_rows);
oled_write_raw_P(footer_image, sizeof(footer_image));
#endif
return false;
}
extern bool oled_initialized;
__attribute__((weak)) void matrix_scan_oled(void) {
is_oled_enabled = !(timer_elapsed32(oled_timer) > 60000);
}