1
0
Fork 0

[Keymap Removal] keyboard with most keymaps (#23092)

This commit is contained in:
Joel Challis 2024-02-16 13:25:44 +00:00 committed by GitHub
parent b8646bc40b
commit 78a74ca974
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
426 changed files with 0 additions and 27404 deletions

View file

@ -1,46 +0,0 @@
/* Copyright 2022 Chris Tanaka <https://github.com/christanaka>
*
* 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/>.
*/
#pragma once
/* space savers */
#define DYNAMIC_KEYMAP_LAYER_COUNT 3
#define NO_ACTION_TAPPING
#define NO_ACTION_ONESHOT
#define TAPPING_FORCE_HOLD
// Old configuration
#define OLED_BRIGHTNESS 128
#define OLED_TIMEOUT 30000
#define OLED_UPDATE_INTERVAL 200
// Selectively undefine to save space
// VIA support won't fit otherwise
#ifdef RGBLIGHT_ENABLE
#undef RGBLIGHT_EFFECT_TWINKLE
#endif //RGB LIGHT_ENABLE
// Split configuration
#define SPLIT_TRANSPORT_MIRROR
#define SPLIT_WPM_ENABLE
// Typehud configuration
#define TYPEHUD_FILLGRAPH
#define TYPEHUD_MATRIX_COLS 16
// #define TYPEHUD_MASTER
// #define TYPEHUD_MATRIX_ROTATE_90
// #define TYPEHUD_MATRIX_ROTATE_180
// #define TYPEHUD_MATRIX_ROTATE_270

View file

@ -1,157 +0,0 @@
/* Copyright 2022 Chris Tanaka <https://github.com/christanaka>
*
* 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 QMK_KEYBOARD_H
#include "typehud.h"
// clang-format off
enum layers {
_BASE,
_VIA1,
_VIA2
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_BASE] = LAYOUT_all(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_PAUS,
KC_F13, KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_DEL, KC_HOME,
KC_F14, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_END,
KC_F15, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP,
KC_F16, KC_LSFT, KC_NUHS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN,
KC_F17, KC_LCTL, KC_LGUI, KC_LALT, MO(_VIA1), KC_SPC, KC_SPC, MO(_VIA1), KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
[_VIA1] = LAYOUT_all(
QK_BOOT,KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO
),
[_VIA2] = LAYOUT_all(
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO
)
};
// clang-format on
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU), ENCODER_CCW_CW(KC_MPRV, KC_MNXT) },
[_VIA1] = { ENCODER_CCW_CW(KC_NO, KC_NO), ENCODER_CCW_CW(KC_NO, KC_NO) },
[_VIA2] = { ENCODER_CCW_CW(KC_NO, KC_NO), ENCODER_CCW_CW(KC_NO, KC_NO) }
};
#endif
oled_rotation_t oled_init_user(oled_rotation_t rotation) {
oled_clear();
#ifdef TYPEHUD_MASTER
if (is_keyboard_master()) {
#else
if (!is_keyboard_master()) {
#endif
typehud_init();
}
if (is_keyboard_left())
return OLED_ROTATION_0;
else
return OLED_ROTATION_180;
}
static void render_status(void) {
oled_set_cursor(0, 0);
oled_write_P(PSTR("SNAP75 "), false);
oled_write_P(PSTR("Layer "), false);
switch (get_highest_layer(layer_state)) {
case _VIA1:
oled_write_P(PSTR("FN1 "), false);
break;
case _VIA2:
oled_write_P(PSTR("FN2 "), false);
break;
default: // use BASE case as default
oled_write_P(PSTR("Base"), false);
}
// Host Keyboard LED Status
oled_set_cursor(0, 1);
static led_t persistent_led_state = {0};
led_t led_state = host_keyboard_led_state();
// Only update if the LED state has changed
// Otherwise, the OLED will not turn off if an LED is on.
if (persistent_led_state.raw != led_state.raw) {
persistent_led_state = led_state;
oled_write_ln_P(PSTR(" "), false);
if (led_state.caps_lock) {
oled_set_cursor(0, 1);
oled_write_P(PSTR("CAPS"), false);
}
if (led_state.num_lock) {
oled_set_cursor(5, 1);
oled_write_P(PSTR("NUM"), true);
}
if (led_state.scroll_lock) {
oled_set_cursor(9, 1);
oled_write_P(PSTR("SCR"), false);
}
}
// WPM and max WPM
oled_set_cursor(0, 2);
oled_write_P(PSTR("WPM "), false);
uint8_t current_wpm = get_current_wpm();
oled_write(get_u8_str(current_wpm, '0'), true);
oled_set_cursor(8, 2);
oled_write_P(PSTR("MAX "), false);
static uint8_t max_wpm;
max_wpm = MAX(max_wpm, current_wpm);
oled_write(get_u8_str(max_wpm, '0'), true);
}
bool oled_task_user(void) {
#ifdef TYPEHUD_MASTER
if (is_keyboard_master()) {
#else
if (!is_keyboard_master()) {
#endif
typehud_render();
} else {
render_status();
}
return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
typehud_process_record(record);
return true;
}
bool should_process_keypress(void) {
return true;
}

View file

@ -1,51 +0,0 @@
# Typehud Keymap
VIA compatible keymap that displays a live wpm HUD on your OLED.
<https://nullbits.co/static/file/snap-typehud.webp>
## Configuration
Configuration options (other than the keymap itself) can be found in `typehud/config.h`.
### Graph Type
By default the graph is filled. For a non-filled graph remove or comment out the following line:
```c
#define TYPEHUD_FILLGRAPH
```
### Keyboard Matrix Orientation
To change the keyboard matrix orientation add one of the following:
- `TYPEHUD_MATRIX_ROTATE_90`
- `TYPEHUD_MATRIX_ROTATE_180`
- `TYPEHUD_MATRIX_ROTATE_270`
### Keyboard Matrix Key Overrides
If the number of physical keys doesn't match the keyboard matrix rows/columns you can override it:
```c
#define TYPEHUD_MATRIX_ROWS 6
#define TYPEHUD_MATRIX_COLS 16
```
In addition if the position of the physical keys doesn't match the matrix you can override it. Negative numbers will shift the keys left/up and positive numbers will shift the keys right/down:
```c
#define TYPEHUD_MATRIX_ROW_SHIFT -1
#define TYPEHUD_MATRIX_COL_SHIFT -2
```
### Split Keyboard Side
For split keyboards, the keymap assumes it will be rendered to the slave side.
To render to master instead, add the following configuration line:
```c
#define TYPEHUD_MASTER
```

View file

@ -1,6 +0,0 @@
OLED_ENABLE = yes
WPM_ENABLE = yes
VIA_ENABLE = yes
ENCODER_MAP_ENABLE = yes
SRC += typehud.c

View file

@ -1,349 +0,0 @@
/* Copyright 2023 Jay Greco
*
* 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 "typehud.h"
static bool is_initialized;
static uint16_t timer;
static int8_t bar_height;
static uint8_t wpm_arr[_GRAPH_WIDTH];
static uint8_t point_arr[_GRAPH_WIDTH];
static void
render_graph(uint8_t wpm),
render_caret(void),
render_axis(void),
render_bar(void),
render_init(void);
/*
* Renders the wpm counter.
*/
static void render_wpm(uint8_t wpm) {
oled_set_cursor(0, 0);
oled_write("WPM", false);
oled_set_cursor(0, 1);
oled_write(get_u8_str(wpm, '0'), false);
}
/*
* Renders the keyboard matrix.
*/
static void render_matrix(keyrecord_t *record) {
uint8_t x = _MATRIX_X;
uint8_t y = _MATRIX_Y;
uint8_t width = _MATRIX_WIDTH;
uint8_t height = _MATRIX_HEIGHT;
#ifdef SPLIT_KEYBOARD
uint8_t rows = _NML_MATRIX_ROWS;
uint8_t cols = _NML_MATRIX_COLS;
#endif
// On initial render draw the matrix outline
if (!is_initialized) {
for (uint8_t i = 1; i <= width - 2; i++) {
oled_write_pixel(x + i, y, true);
oled_write_pixel(x + i, y + height - 1, true);
}
for (uint8_t j = 1; j <= height - 2; j++) {
oled_write_pixel(x, y + j, true);
oled_write_pixel(x + width - 1, y + j, true);
}
return;
}
// Determine position based on matrix rotation
// For split keyboards the keys on the right half get appended as additional rows and
// have their columns reset at 0
#ifdef SPLIT_KEYBOARD
uint8_t row = (record->event.key.row % rows);
uint8_t col = record->event.key.col;
if (record->event.key.row >= rows) {
col += (cols / 2);
}
#else
uint8_t row = record->event.key.row;
uint8_t col = record->event.key.col;
#endif
#ifdef TYPEHUD_MATRIX_ROW_SHIFT
row += TYPEHUD_MATRIX_ROW_SHIFT;
#endif
#ifdef TYPEHUD_MATRIX_COL_SHIFT
col += TYPEHUD_MATRIX_COL_SHIFT;
#endif
// Scale position to key size
uint8_t size = _MATRIX_SIZE;
row *= size;
col *= size;
// Render key in matrix
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
#if defined(TYPEHUD_MATRIX_ROTATE_90)
uint8_t key_x = x + width - 1 - size - row;
uint8_t key_y = y + 1 + col;
#elif defined(TYPEHUD_MATRIX_ROTATE_180)
uint8_t key_x = x + width - 1 - size - col;
uint8_t key_y = y + height - 1 - size - row;
#elif defined(TYPEHUD_MATRIX_ROTATE_270)
uint8_t key_x = x + 1 + row;
uint8_t key_y = y + height - 1 - size - col;
#else
uint8_t key_x = x + 1 + col;
uint8_t key_y = y + 1 + row;
#endif
oled_write_pixel(key_x + i, key_y + j, record->event.pressed);
}
}
}
/*
* Renders the graph.
*/
static void render_graph(uint8_t wpm) {
uint8_t x = _GRAPH_X;
uint8_t y = _GRAPH_Y + _GRAPH_HEIGHT;
uint8_t width = _GRAPH_WIDTH;
uint8_t height = _GRAPH_HEIGHT;
// Handle intial graph render
if (!is_initialized) {
for (uint8_t i = 0; i < width; i++) {
oled_write_pixel(x + i, y, true);
}
return;
}
uint8_t i = 0;
// Shift all graph points except last to the left and re-render
for (; i < width - 1; i++) {
int8_t point_delta = point_arr[i + 1] - point_arr[i];
#ifdef TYPEHUD_FILLGRAPH
if (point_delta < 0) {
#else
if (point_delta != 0) {
#endif
oled_write_pixel(x + i, y - point_arr[i], false);
}
wpm_arr[i] = wpm_arr[i + 1];
point_arr[i] = point_arr[i + 1];
if (point_delta != 0) {
oled_write_pixel(x + i, y - point_arr[i], true);
}
}
// Clear last graph point
if (wpm > wpm_arr[i] && point_arr[i] + 1 <= height) {
#ifndef TYPEHUD_FILLGRAPH
oled_write_pixel(x + i, y - point_arr[i], false);
#endif
point_arr[i] = point_arr[i] + 1;
} else if ((wpm < wpm_arr[i] && point_arr[i] - 1 >= 0) || (wpm <= 0 && point_arr[i] > 0)) {
oled_write_pixel(x + i, y - point_arr[i], false);
point_arr[i] = point_arr[i] - 1;
}
// Render last graph point
wpm_arr[i] = wpm;
if (point_arr[i] != point_arr[i - 1]) {
oled_write_pixel(x + i, y - point_arr[i], true);
}
}
/*
* Renders the caret.
*/
static void render_caret(void) {
uint8_t x = _GRAPH_X + _GRAPH_WIDTH + _GRAPH_RPAD + _CARET_WIDTH;
uint8_t y = 0;
uint8_t width = _CARET_WIDTH;
uint8_t height = _CARET_HEIGHT;
uint8_t g_width = _GRAPH_WIDTH;
uint8_t g_height = _GRAPH_HEIGHT;
// Handle initial caret render
if (!is_initialized) {
y = g_height - point_arr[g_width - 1];
for (uint8_t i = 0; i < width; i++) {
for (uint8_t j = i; j < height - i; j++) {
oled_write_pixel(x - i, y - j, true);
}
}
return;
}
// Handle caret updates and re-render
int8_t point_delta = point_arr[g_width - 1] - point_arr[g_width - 2];
if (point_delta > 0) {
y = g_height - point_arr[g_width - 2];
if (y - height + 1 > 0) {
for (uint8_t i = 0; i < width; i++) {
oled_write_pixel(x - i, y - i, false);
oled_write_pixel(x - i, y - height + i, true);
}
}
} else if (point_delta < 0) {
y = g_height - point_arr[g_width - 1];
if (y - height + 1 > 0) {
for (uint8_t i = 0; i < width; i++) {
oled_write_pixel(x - i, y - height + i, false);
oled_write_pixel(x - i, y - i, true);
}
}
}
}
/*
* Renders the axis.
*/
static void render_axis(void) {
uint8_t x = _AXIS_X;
uint8_t y = _AXIS_HEIGHT;
uint8_t width = _AXIS_WIDTH;
uint8_t height = _AXIS_HEIGHT;
uint8_t tick_width = _AXIS_TICK_WIDTH;
uint8_t subtick_width = _AXIS_SUBTICK_WIDTH;
uint8_t interval = _AXIS_INTERVAL;
uint8_t tick_interval = _AXIS_TICK_INTERVAL;
for (uint8_t j = 0; j <= height; j += interval) {
uint8_t curr_tick_width = 0;
// Determine tick width and draw extra point if at interval
if (j % tick_interval == 0) {
curr_tick_width = tick_width;
oled_write_pixel(x, y - j, true);
} else {
curr_tick_width = subtick_width;
}
// Draw tick
for (uint8_t i = 0; i < curr_tick_width; i++) {
oled_write_pixel(x + width - i, y - j, true);
}
}
}
/*
* Renders the input bar.
*/
static void render_bar(void) {
uint8_t x = _BAR_X;
uint8_t width = _BAR_WIDTH;
uint8_t height = _BAR_HEIGHT;
// Increment bar height
bar_height = (bar_height + 1) % height;
// When bar resets back to 0, clear bar pixels
if (bar_height % height == 0) {
for (uint8_t i = 0; i < width; i++) {
for (uint8_t j = 0; j < height; j++) {
oled_write_pixel(x + i, j, false);
}
}
}
// Draw new bar pixels
for (uint8_t i = 0; i < width; i++) {
oled_write_pixel(x + i, height - bar_height, true);
}
}
/*
* Renders the initial frame for all components.
*/
static void render_init(void) {
render_graph(0);
render_caret();
render_matrix(NULL);
render_axis();
}
/*
* Initializes and resets the typehud.
*/
void typehud_init(void) {
// Reset variables
is_initialized = false;
timer = 0;
bar_height = -1;
for (uint8_t i = 0; i < _GRAPH_WIDTH; i++) {
wpm_arr[i] = 0;
point_arr[i] = 0;
}
// Draw the initial graph
for (uint8_t i = 0; i < _GRAPH_WIDTH; i++) {
oled_write_pixel(_GRAPH_X + i, _GRAPH_HEIGHT, true);
}
}
/*
* Renders the typehud.
*/
void typehud_render(void) {
uint8_t wpm = get_current_wpm();
// Run initial rendering once
if (!is_initialized) {
render_init();
is_initialized = true;
}
// Render wpm
render_wpm(wpm);
// Render next graph and caret frame when timer reaches refresh rate
if (timer_elapsed(timer) > _GRAPH_REFRESH) {
render_graph(wpm);
render_caret();
timer = timer_read();
}
}
/*
* Handles keypresses for the typehud.
*/
void typehud_process_record(keyrecord_t *record) {
// For split keyboards, only draw on correct side
#ifdef SPLIT_KEYBOARD
# ifdef TYPEHUD_MASTER
if (!is_keyboard_master()) {
# else
if (is_keyboard_master()) {
# endif
return;
}
#endif
// Render/update matrix
render_matrix(record);
// Render/update input bar on keypress
if (record->event.pressed) {
render_bar();
}
}

View file

@ -1,87 +0,0 @@
/* Copyright 2022 Chris Tanaka <https://github.com/christanaka>
*
* 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 QMK_KEYBOARD_H
// clang-format off
#define _OLED_WIDTH (OLED_DISPLAY_WIDTH - 1)
#define _OLED_HEIGHT (OLED_DISPLAY_HEIGHT - 1)
#ifdef SPLIT_KEYBOARD
#define _PHYSICAL_PARTS 2
#else
#define _PHYSICAL_PARTS 1
#endif
#ifdef TYPEHUD_MATRIX_ROWS
#define _NML_MATRIX_ROWS TYPEHUD_MATRIX_ROWS
#else
# ifdef SPLIT_KEYBOARD
#define _NML_MATRIX_ROWS (MATRIX_ROWS / 2)
# else
#define _NML_MATRIX_ROWS MATRIX_ROWS
# endif
#endif
#ifdef TYPEHUD_MATRIX_COLS
#define _NML_MATRIX_COLS TYPEHUD_MATRIX_COLS
#else
#define _NML_MATRIX_COLS (MATRIX_COLS * _PHYSICAL_PARTS)
#endif
#define _MATRIX_SIZE 2
#if defined(TYPEHUD_MATRIX_ROTATE_90) || defined(TYPEHUD_MATRIX_ROTATE_270)
#define _MATRIX_WIDTH (_NML_MATRIX_ROWS * _MATRIX_SIZE + 2)
#define _MATRIX_HEIGHT (_NML_MATRIX_COLS * _MATRIX_SIZE + 2)
#else
#define _MATRIX_WIDTH (_NML_MATRIX_COLS * _MATRIX_SIZE + 2)
#define _MATRIX_HEIGHT (_NML_MATRIX_ROWS * _MATRIX_SIZE + 2)
#endif
#define _MATRIX_X 0
#define _MATRIX_Y (_OLED_HEIGHT - _MATRIX_HEIGHT + 1)
#define _MATRIX_RPAD 2
#define _MATRIX_PAD_WIDTH (_MATRIX_WIDTH + _MATRIX_RPAD)
#define _BAR_WIDTH 3
#define _BAR_HEIGHT _OLED_HEIGHT
#define _BAR_X (_OLED_WIDTH - _BAR_WIDTH)
#define _AXIS_WIDTH 5
#define _AXIS_HEIGHT _OLED_HEIGHT
#define _AXIS_TICK_WIDTH 3
#define _AXIS_SUBTICK_WIDTH 2
#define _AXIS_INTERVAL 3
#define _AXIS_TICK_INTERVAL 15
#define _AXIS_RPAD 2
#define _AXIS_PAD_WIDTH (_AXIS_WIDTH + _AXIS_RPAD)
#define _AXIS_X (_OLED_WIDTH - _BAR_WIDTH - _AXIS_PAD_WIDTH)
#define _CARET_WIDTH 3
#define _CARET_HEIGHT 5
#define _GRAPH_RPAD 2
#define _GRAPH_MAX_WIDTH (_OLED_WIDTH - _BAR_WIDTH - _AXIS_PAD_WIDTH - _CARET_WIDTH - _GRAPH_RPAD - _MATRIX_PAD_WIDTH)
#define _GRAPH_WIDTH (_GRAPH_MAX_WIDTH - 4)
#define _GRAPH_HEIGHT 31
#define _GRAPH_REFRESH 300
#define _GRAPH_X (_MATRIX_WIDTH + _MATRIX_RPAD)
#define _GRAPH_Y 0
// clang-format on
void
typehud_init(void),
typehud_render(void),
typehud_process_record(keyrecord_t *record);