summaryrefslogtreecommitdiff
path: root/users
diff options
context:
space:
mode:
Diffstat (limited to 'users')
-rw-r--r--users/ajp10304/ajp10304.c10
-rw-r--r--users/ajp10304/ajp10304.h2
-rw-r--r--users/ajp10304/readme.md21
-rw-r--r--users/bcat/bcat.c10
-rw-r--r--users/bcat/bcat.h36
-rw-r--r--users/bcat/bcat_oled.c216
-rw-r--r--users/bcat/bcat_oled.h55
-rw-r--r--users/bcat/bcat_oled_pet.h73
-rw-r--r--users/bcat/bcat_oled_pet_isda.c134
-rw-r--r--users/bcat/bcat_oled_pet_luna.c168
-rw-r--r--users/bcat/bcat_rgblight.c (renamed from users/drashna/rgb_matrix_stuff.h)13
-rwxr-xr-xusers/bcat/compile.sh52
-rw-r--r--users/bcat/config.h79
-rw-r--r--users/bcat/readme.md3
-rw-r--r--users/bcat/rules.mk43
-rw-r--r--users/byungyoonc/byungyoonc.c48
-rw-r--r--users/byungyoonc/byungyoonc.h (renamed from users/drashna/rgb_stuff.h)18
-rw-r--r--users/byungyoonc/readme.md14
-rw-r--r--users/byungyoonc/rules.mk1
-rw-r--r--users/byungyoonc/saturated_solid_multisplash.h50
-rw-r--r--users/drashna/callbacks.c211
-rw-r--r--users/drashna/callbacks.h25
-rw-r--r--users/drashna/callbacks.md71
-rw-r--r--users/drashna/config.h69
-rw-r--r--users/drashna/drashna.c357
-rw-r--r--users/drashna/drashna.h81
-rw-r--r--users/drashna/keyrecords/autocorrection/autocorrection.c170
-rw-r--r--users/drashna/keyrecords/autocorrection/autocorrection.h10
-rwxr-xr-xusers/drashna/keyrecords/autocorrection/make_autocorrection_data.py274
-rw-r--r--users/drashna/keyrecords/autocorrection/readme.md301
-rw-r--r--users/drashna/keyrecords/caps_word.c83
-rw-r--r--users/drashna/keyrecords/caps_word.h8
-rw-r--r--users/drashna/keyrecords/capwords.md36
-rw-r--r--users/drashna/keyrecords/keycodes.md18
-rw-r--r--users/drashna/keyrecords/process_records.c (renamed from users/drashna/process_records.c)94
-rw-r--r--users/drashna/keyrecords/process_records.h (renamed from users/drashna/process_records.h)53
-rw-r--r--users/drashna/keyrecords/readme.md9
-rw-r--r--users/drashna/keyrecords/secrets.md (renamed from users/drashna/readme_secrets.md)0
-rw-r--r--users/drashna/keyrecords/tap_dance.md (renamed from users/drashna/readme_tap_dance.md)4
-rw-r--r--users/drashna/keyrecords/tap_dances.c (renamed from users/drashna/tap_dances.c)29
-rw-r--r--users/drashna/keyrecords/tap_dances.h31
-rw-r--r--users/drashna/keyrecords/tapping.c64
-rw-r--r--users/drashna/keyrecords/unicode.c294
-rw-r--r--users/drashna/keyrecords/unicode.md27
-rw-r--r--users/drashna/keyrecords/wrappers.h (renamed from users/drashna/wrappers.h)18
-rw-r--r--users/drashna/keyrecords/wrappers.md (renamed from users/drashna/readme_wrappers.md)0
-rw-r--r--users/drashna/oled/drashna_font.h (renamed from users/drashna/drashna_font.h)4
-rw-r--r--users/drashna/oled/oled_stuff.c1120
-rw-r--r--users/drashna/oled/oled_stuff.h (renamed from users/drashna/oled_stuff.h)42
-rw-r--r--users/drashna/oled/readme.md42
-rw-r--r--users/drashna/oled/sh110x.c860
-rw-r--r--users/drashna/oled_stuff.c446
-rw-r--r--users/drashna/pointing/pointing.c125
-rw-r--r--users/drashna/pointing/pointing.h10
-rw-r--r--users/drashna/pointing/readme.md19
-rw-r--r--users/drashna/post_config.h21
-rw-r--r--users/drashna/readme.md24
-rw-r--r--users/drashna/readme_handlers.md97
-rw-r--r--users/drashna/readme_keycodes.md10
-rw-r--r--users/drashna/rgb/readme.md (renamed from users/drashna/readme_rgb.md)21
-rw-r--r--users/drashna/rgb/rgb_matrix_stuff.c129
-rw-r--r--users/drashna/rgb/rgb_matrix_stuff.h15
-rw-r--r--users/drashna/rgb/rgb_stuff.c (renamed from users/drashna/rgb_stuff.c)63
-rw-r--r--users/drashna/rgb/rgb_stuff.h12
-rw-r--r--users/drashna/rgb_matrix_stuff.c97
-rw-r--r--users/drashna/rgblight_breathe_table.h17
-rw-r--r--users/drashna/rules.mk87
-rw-r--r--users/drashna/split/readme.md29
-rw-r--r--users/drashna/split/transport_sync.c (renamed from users/drashna/transport_sync.c)108
-rw-r--r--users/drashna/split/transport_sync.h26
-rw-r--r--users/drashna/tap_dances.h44
-rw-r--r--users/drashna/template.c17
-rw-r--r--users/drashna/template.h17
-rw-r--r--users/drashna/transport_sync.h36
-rwxr-xr-xusers/ericgebhart/altlocal_keys.c94
-rw-r--r--users/ericgebhart/altlocal_keys.h36
-rw-r--r--users/ericgebhart/base_layers.h283
-rw-r--r--users/ericgebhart/caps_word.c81
-rw-r--r--users/ericgebhart/caps_word.h35
-rw-r--r--users/ericgebhart/combos.def10
-rwxr-xr-xusers/ericgebhart/config.h23
-rwxr-xr-x[-rw-r--r--]users/ericgebhart/core_keys.h233
-rwxr-xr-x[-rw-r--r--]users/ericgebhart/core_keysets.h492
-rw-r--r--users/ericgebhart/edge_keys.h238
-rwxr-xr-x[-rw-r--r--]users/ericgebhart/ericgebhart.c590
-rwxr-xr-x[-rw-r--r--]users/ericgebhart/ericgebhart.h80
-rwxr-xr-xusers/ericgebhart/layers.h677
-rw-r--r--users/ericgebhart/layouts.h720
-rw-r--r--users/ericgebhart/mod_layer.h178
-rwxr-xr-xusers/ericgebhart/oled_stuff.c303
-rwxr-xr-xusers/ericgebhart/oled_stuff.h24
-rwxr-xr-xusers/ericgebhart/process_records.c255
-rwxr-xr-x[-rw-r--r--]users/ericgebhart/readme.md292
-rwxr-xr-xusers/ericgebhart/rules.mk28
-rwxr-xr-xusers/ericgebhart/tap_dances.c269
-rwxr-xr-xusers/ericgebhart/tap_dances.h19
-rw-r--r--users/jonavin/config.h5
-rw-r--r--users/jonavin/readme.md4
-rw-r--r--users/mnil/mnil.c16
-rw-r--r--users/noroadsleft/noroadsleft.c83
-rw-r--r--users/noroadsleft/noroadsleft.h2
-rw-r--r--users/noroadsleft/readme.md43
-rw-r--r--users/riblee/riblee.c45
-rw-r--r--users/riblee/riblee.h1
-rw-r--r--users/scheiklp/koy_keys_on_quertz_de_latin1.h1
-rw-r--r--users/stanrc85/config.h10
-rw-r--r--users/uqs/config.h40
-rw-r--r--users/uqs/rules.mk24
-rw-r--r--users/uqs/uqs.c584
-rw-r--r--users/uqs/uqs.h77
-rw-r--r--users/zigotica/rows.h20
-rw-r--r--users/zigotica/zigotica.h2
112 files changed, 9950 insertions, 2888 deletions
diff --git a/users/ajp10304/ajp10304.c b/users/ajp10304/ajp10304.c
index dd13787d63..b8729b94d7 100644
--- a/users/ajp10304/ajp10304.c
+++ b/users/ajp10304/ajp10304.c
@@ -24,6 +24,10 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
set_single_persistent_default_layer(_QWERTY);
}
return false;
+ case COLEMAK:
+ if (record->event.pressed) {
+ set_single_persistent_default_layer(_COLEMAK);
+ }
case LOWER:
if (record->event.pressed) {
layer_on(_LOWER);
@@ -157,12 +161,14 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
break;
case M_MODE:
if (record->event.pressed) {
- SEND_STRING("PC");
+ send_string("PC ");
+ send_string(get_highest_layer(default_layer_state) == _COLEMAK ? "COLEMAK" : "QWERTY");
}
break;
case M_MODE_MAC:
if (record->event.pressed) {
- SEND_STRING("OSX");
+ send_string("OSX ");
+ send_string(get_highest_layer(default_layer_state) == _COLEMAK ? "COLEMAK" : "QWERTY");
}
break;
}
diff --git a/users/ajp10304/ajp10304.h b/users/ajp10304/ajp10304.h
index ec1ed11c04..130c841607 100644
--- a/users/ajp10304/ajp10304.h
+++ b/users/ajp10304/ajp10304.h
@@ -18,6 +18,7 @@
enum ajp10304_layers {
_QWERTY,
+ _COLEMAK,
_MAC,
_LOWER,
_MLWR,
@@ -34,6 +35,7 @@ enum ajp10304_layers {
enum ajp10304_keycodes {
QWERTY = SAFE_RANGE,
+ COLEMAK,
MAC,
FUNC,
MFNC,
diff --git a/users/ajp10304/readme.md b/users/ajp10304/readme.md
index bfc39535c1..0683f42384 100644
--- a/users/ajp10304/readme.md
+++ b/users/ajp10304/readme.md
@@ -37,6 +37,15 @@ Refer to the README.md of the keyboard you want to flash.
| Shft | Z | X | C | V | B | N | M | ,< | .> | /? | Shft |
| Fn | Ctrl | Alt | GUI |Lower | Bksp |Space |Raise | Shift| MENU | Ctrl | Fn2 |
+##### Main Colemak-DHm Layer
+
+| | | | | | | | | | | | |
+| ---- |:----:| :---:|:---:|:-----:|:----:|:-----:|:-----:|:-----:|:----:|:----:| ----:|
+| Esc | Q | W | F | P | B | J | L | U | Y | ;: | Bksp |
+| Tab | A | R | S | T | G | M | N | E | I | O | Enter|
+| Shft | Z | X | C | D | V | K | H | ,< | .> | /? | Shft |
+| Fn | Ctrl | Alt | GUI | Lower | Bksp | Space | Raise | Shift | MENU | Ctrl | Fn2 |
+
##### Function Layer
Activated when `fn` held in the above `qwerty` layer.
@@ -88,12 +97,12 @@ To finish the recording, press STOP. To replay the macro, press either PLAY1 or
* MAC: Toggle MAC OS extensions to layers. This allows MLWR to be enabled with LOWER,
MRSE with RAISE, MFNC with FUNC and MFNC2 with FUNC2 respectively.
-| | | | | | | | | | | | |
-| :---: |:----:| :---:| :---:| :---:| :---:| :---:| :---:| :---:| :---:| :---:| :---:|
-| ???? | Reset|Qwerty| | | REC1 | REC2 | | | | | Del |
-| CAPS | | | | | PLAY1|PLAY2 | Mute | Vol+ | Play | | |
-| MAC | | | | | STOP1|STOP2 | Prev | Vol- | Next | | |
-| | | | | | | | | DYN | | | |
+| | | | | | | | | | | | |
+| :---: |:----:| :---:| :---:| :---:| :---:| :---:| :---:| :---:| :---:| :---:|:-------:|
+| ???? | Reset|Qwerty| | | REC1 | REC2 | | | | | Del |
+| CAPS | | | | | PLAY1|PLAY2 | Mute | Vol+ | Play | | Qwerty |
+| MAC | | | | | STOP1|STOP2 | Prev | Vol- | Next | | Colemak |
+| | | | | | | | | DYN | | | |
##### Function 2 Layer
Activated when `fn` held in the above `qwerty` layer.
diff --git a/users/bcat/bcat.c b/users/bcat/bcat.c
index f21d282e43..3a407cfac0 100644
--- a/users/bcat/bcat.c
+++ b/users/bcat/bcat.c
@@ -16,16 +16,15 @@
#include "bcat.h"
-#if defined(RGBLIGHT_ENABLE)
-/* Adjust RGB static hue ranges for shorter gradients than default. */
-const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 127, 63, 31, 15};
-#endif
+#include "quantum.h"
static int8_t alt_tab_layer = -1;
+__attribute__((weak)) void process_record_oled(uint16_t keycode, const keyrecord_t *record) {}
__attribute__((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; }
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ process_record_oled(keycode, record);
if (!process_record_keymap(keycode, record)) {
return false;
}
@@ -51,6 +50,9 @@ __attribute__((weak)) layer_state_t layer_state_set_keymap(layer_state_t state)
layer_state_t layer_state_set_user(layer_state_t state) {
state = layer_state_set_keymap(state);
+#if defined(BCAT_ORTHO_LAYERS)
+ state = update_tri_layer_state(state, LAYER_LOWER, LAYER_RAISE, LAYER_ADJUST);
+#endif
if (alt_tab_layer >= 0 && !layer_state_cmp(state, alt_tab_layer)) {
unregister_code(KC_LALT);
alt_tab_layer = -1;
diff --git a/users/bcat/bcat.h b/users/bcat/bcat.h
index 0dae774ec5..4a88acba7d 100644
--- a/users/bcat/bcat.h
+++ b/users/bcat/bcat.h
@@ -16,9 +16,43 @@
#pragma once
-#include "quantum.h"
+#include <stdbool.h>
+#include "keymap.h"
+
+/* Layer numbers shared across keymaps. */
+enum user_layer {
+ /* Base layers: */
+ LAYER_DEFAULT,
+
+#if defined(BCAT_ORTHO_LAYERS)
+ /* Function layers for ortho (and ergo) boards: */
+ LAYER_LOWER,
+ LAYER_RAISE,
+ LAYER_ADJUST,
+#else
+ /* Function layers for traditional boards: */
+ LAYER_FUNCTION_1,
+ LAYER_FUNCTION_2,
+#endif
+};
+
+/* Custom keycodes shared across keymaps. */
enum user_keycode {
MC_ALTT = SAFE_RANGE,
KEYMAP_SAFE_RANGE,
};
+
+/* Keycode aliases shared across keymaps. */
+#define KY_CSPC LCTL(KC_SPC)
+#define KY_ZMIN LCTL(KC_EQL)
+#define KY_ZMOUT LCTL(KC_MINS)
+#define KY_ZMRST LCTL(KC_0)
+
+#if defined(BCAT_ORTHO_LAYERS)
+# define LY_LWR MO(LAYER_LOWER)
+# define LY_RSE MO(LAYER_RAISE)
+#else
+# define LY_FN1 MO(LAYER_FUNCTION_1)
+# define LY_FN2 MO(LAYER_FUNCTION_2)
+#endif
diff --git a/users/bcat/bcat_oled.c b/users/bcat/bcat_oled.c
new file mode 100644
index 0000000000..390c9127b4
--- /dev/null
+++ b/users/bcat/bcat_oled.c
@@ -0,0 +1,216 @@
+/* Copyright 2021 Jonathan Rascher
+ *
+ * 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 "bcat_oled.h"
+
+#include "quantum.h"
+#include "bcat.h"
+
+#if defined(BCAT_OLED_PET)
+# include "bcat_oled_pet.h"
+#endif
+
+#define TRIANGLE_UP 0x1e
+#define TRIANGLE_DOWN 0x1f
+
+#if defined(BCAT_OLED_PET)
+static bool oled_pet_should_jump = false;
+#endif
+
+/* Should be overridden by the keymap to render the OLED contents. For split
+ * keyboards, this function is only called on the master side.
+ */
+__attribute__((weak)) void oled_task_keymap(const oled_keyboard_state_t *keyboard_state) {}
+
+bool oled_task_user(void) {
+#if defined(SPLIT_KEYBOARD)
+ if (is_keyboard_master()) {
+#endif
+ /* Custom OLED timeout implementation that only considers user activity.
+ * Allows the OLED to turn off in the middle of a continuous animation.
+ */
+ static const uint16_t TIMEOUT_MILLIS = 60000 /* 1 min */;
+
+ if (last_input_activity_elapsed() < TIMEOUT_MILLIS) {
+ if (!is_oled_on()) {
+ oled_on();
+ }
+ oled_keyboard_state_t keyboard_state = {
+ .mods = get_mods(),
+ .leds = host_keyboard_led_state(),
+ .wpm = get_current_wpm(),
+ };
+ oled_task_keymap(&keyboard_state);
+ } else if (is_oled_on()) {
+ oled_off();
+ }
+#if defined(SPLIT_KEYBOARD)
+ } else {
+ /* Display logo embedded at standard location in the OLED font on the
+ * slave side. By default, this is a "QMK firmware" logo, but many
+ * keyboards substitute their own logo. Occupies 21x3 character cells.
+ *
+ * Since the slave display buffer never changes, we don't need to worry
+ * about oled_render incorrectly turning the OLED on. Instead, we rely
+ * on SPLIT_OLED_ENABLE to propagate OLED on/off status from master.
+ */
+ static const char PROGMEM logo[] = {
+ // clang-format off
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
+ 0x00,
+ // clang-format on
+ };
+
+ oled_write_P(logo, /*invert=*/false);
+ }
+#endif
+
+ return false;
+}
+
+void render_oled_layers(void) {
+ oled_advance_char();
+ oled_advance_char();
+#if defined(BCAT_ORTHO_LAYERS)
+ oled_write_char(IS_LAYER_ON(LAYER_LOWER) ? TRIANGLE_DOWN : ' ', /*invert=*/false);
+ oled_advance_char();
+ oled_write_char(IS_LAYER_ON(LAYER_RAISE) ? TRIANGLE_UP : ' ', /*invert=*/false);
+#else
+ switch (get_highest_layer(layer_state)) {
+ case LAYER_FUNCTION_1:
+ oled_write_P(PSTR("FN1"), /*invert=*/false);
+ break;
+ case LAYER_FUNCTION_2:
+ oled_write_P(PSTR("FN2"), /*invert=*/false);
+ break;
+ default:
+ oled_write_P(PSTR(" "), /*invert=*/false);
+ break;
+ }
+#endif
+}
+
+void render_oled_indicators(led_t leds) {
+ oled_advance_char();
+ oled_advance_char();
+ oled_write_P(leds.num_lock ? PSTR("NUM") : PSTR(" "), /*invert=*/false);
+ oled_advance_char();
+ oled_advance_char();
+ oled_write_P(leds.caps_lock ? PSTR("CAP") : PSTR(" "), /*invert=*/false);
+ oled_advance_char();
+ oled_advance_char();
+ oled_write_P(leds.scroll_lock ? PSTR("SCR") : PSTR(" "), /*invert=*/false);
+}
+
+void render_oled_wpm(uint8_t wpm) {
+ static const uint16_t UPDATE_MILLIS = 100;
+ static uint32_t update_timeout = 0;
+
+ if (timer_expired32(timer_read32(), update_timeout)) {
+ oled_advance_char();
+ oled_advance_char();
+ oled_write_P(wpm > 0 ? PSTR("WPM") : PSTR(" "), /*invert=*/false);
+ if (wpm > 0) {
+ oled_advance_char();
+ oled_advance_char();
+ oled_write(get_u8_str(wpm, ' '), /*invert=*/false);
+ } else {
+ oled_advance_page(/*clearPageRemainder=*/true);
+ }
+
+ update_timeout = timer_read32() + UPDATE_MILLIS;
+ }
+}
+
+#if defined(BCAT_OLED_PET)
+void process_record_oled(uint16_t keycode, const keyrecord_t *record) {
+ switch (keycode) {
+ case KC_SPACE:
+ if (oled_pet_can_jump()) {
+ oled_pet_should_jump = record->event.pressed;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void redraw_oled_pet(uint8_t col, uint8_t line, bool jumping, oled_pet_state_t state) {
+ oled_set_cursor(col, line);
+ if (jumping) {
+ oled_write_raw_P(oled_pet_frame(state), oled_pet_frame_bytes());
+ oled_set_cursor(col, line + oled_pet_frame_lines());
+ oled_advance_page(/*clearPageRemainder=*/true);
+ } else {
+ oled_advance_page(/*clearPageRemainder=*/true);
+ oled_write_raw_P(oled_pet_frame(state), oled_pet_frame_bytes());
+ }
+}
+
+void render_oled_pet(uint8_t col, uint8_t line, const oled_keyboard_state_t *keyboard_state) {
+ /* Current animation to draw. We track changes to avoid redrawing the same
+ * frame repeatedly, allowing oled_pet_post_render to draw over the
+ * animation frame.
+ */
+ static oled_pet_state_t state = 0;
+ static bool state_changed = true;
+
+ /* Minimum time until the pet comes down after jumping. */
+ static const uint16_t JUMP_MILLIS = 200;
+ static bool jumping = false;
+
+ /* Time until the next animation or jump state change. */
+ static uint32_t update_timeout = 0;
+ static uint32_t jump_timeout = 0;
+
+ /* If the user pressed the jump key, immediately redraw instead of waiting
+ * for the animation frame to update. That way, the pet appears to respond
+ * to jump commands quickly rather than lagging. If the user released the
+ * jump key, wait for the jump timeout to avoid overly brief jumps.
+ */
+ bool redraw = state_changed;
+ if (oled_pet_should_jump && !jumping) {
+ redraw = true;
+ jumping = true;
+ jump_timeout = timer_read32() + JUMP_MILLIS;
+ } else if (!oled_pet_should_jump && jumping && timer_expired32(timer_read32(), jump_timeout)) {
+ redraw = true;
+ jumping = false;
+ }
+
+ /* Draw the actual animation, then move the cursor to the end of the
+ * rendered area. (Note that we take up an extra line to account for
+ * jumping, which shifts the animation up or down a line.)
+ */
+ if (redraw) {
+ redraw_oled_pet(col, line, jumping, state);
+ }
+ oled_pet_post_render(col, line + !jumping, keyboard_state, redraw);
+ oled_set_cursor(col, line + oled_pet_frame_lines() + 1);
+
+ /* If the update timer expired, recompute the pet's animation state. */
+ if (timer_expired32(timer_read32(), update_timeout)) {
+ oled_pet_state_t new_state = oled_pet_next_state(state, keyboard_state);
+ state_changed = new_state != state;
+ state = new_state;
+ update_timeout = timer_read32() + oled_pet_update_millis(keyboard_state);
+ } else {
+ state_changed = false;
+ }
+}
+#endif
diff --git a/users/bcat/bcat_oled.h b/users/bcat/bcat_oled.h
new file mode 100644
index 0000000000..f617e1f064
--- /dev/null
+++ b/users/bcat/bcat_oled.h
@@ -0,0 +1,55 @@
+/* Copyright 2021 Jonathan Rascher
+ *
+ * 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
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "led.h"
+
+/* Keyboard status passed to the oled_task_keymap function and used by the
+ * various keyboard pet implementations.
+ */
+typedef struct {
+ uint8_t mods;
+ led_t leds;
+ uint8_t wpm;
+} oled_keyboard_state_t;
+
+/* Note: Functions below assume a vertical OLED that is 32px (5 chars) wide. */
+
+/* Renders layer status at the cursor. Occupies 5x1 character cells. */
+void render_oled_layers(void);
+
+/* Renders LED indicators (Num/Caps/Scroll Lock) at the cursor. Occupies 5x3
+ * character cells.
+ */
+void render_oled_indicators(led_t leds);
+
+/* Renders calculated WPM count at the cursor. Occupies 5x2 character cells. */
+void render_oled_wpm(uint8_t wpm);
+
+#if defined(BCAT_OLED_PET)
+/* Renders an animated critter at the cursor that can respond to keystrokes,
+ * typing speed, etc. Should be about 5 character cells wide, but exact height
+ * varies depending on the specific OLED pet implementation linked in.
+ *
+ * The rendered image will be one line taller than the OLED pet's animation
+ * frame height to accommodate pets that "jump" when the spacebar is pressed.
+ */
+void render_oled_pet(uint8_t col, uint8_t line, const oled_keyboard_state_t *keyboard_state);
+#endif
diff --git a/users/bcat/bcat_oled_pet.h b/users/bcat/bcat_oled_pet.h
new file mode 100644
index 0000000000..ba8227ab61
--- /dev/null
+++ b/users/bcat/bcat_oled_pet.h
@@ -0,0 +1,73 @@
+/* Copyright 2021 Jonathan Rascher
+ *
+ * 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/>.
+ */
+
+/* Common interface for an OLED pet (animated critter that reacts to typing).
+ * Please link exactly one accompanying .c file to implement these functions.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bcat_oled.h"
+
+/* Opaque token representing a single frame of the OLED pet animation.
+ * Different pet implementations have different valid state values, but the
+ * zero value must always represent the default state of the pet at startup.
+ */
+typedef uint16_t oled_pet_state_t;
+
+/* Returns the number of bytes used to represent the animation frame (in
+ * oled_write_raw_P format). Note that every state the pet supports is expected
+ * to have the same frame size.
+ */
+uint16_t oled_pet_frame_bytes(void);
+
+/* Returns the number of lines of the OLED occupied by the animation. Note that
+ * every state the pet supports is expected to have the same frame size. The
+ * returned value does not include the one line of padding that render_oled_pet
+ * uses to account for "jumping".
+ */
+uint8_t oled_pet_frame_lines(void);
+
+/* Returns whether or not the OLED pet should "jump" when the spacebar is
+ * pressed. (The render_oled_pet implementation shifts the animation frame up
+ * one line when this happens.)
+ */
+bool oled_pet_can_jump(void);
+
+/* Returns the delay before the next animation frame should be displayed. */
+uint16_t oled_pet_update_millis(const oled_keyboard_state_t *keyboard_state);
+
+/* Returns the state of the pet to be animated on the next animation tick. */
+oled_pet_state_t oled_pet_next_state(oled_pet_state_t state, const oled_keyboard_state_t *keyboard_state);
+
+/* Called after the OLED pet is rendered during each OLED task invocation.
+ * Receives the same keyboard state as render_oled_pet. The redraw param
+ * indicates whether or not an OLED frame was just redrawn, allowing a specific
+ * pet implementation to draw custom things atop its animation frames.
+ *
+ * When this function is called, the cursor will be in an unspecified location,
+ * not necessarily the top-left corner of the OLED pet.
+ */
+void oled_pet_post_render(uint8_t col, uint8_t line, const oled_keyboard_state_t *keyboard_state, bool redraw);
+
+/* Returns a PROGMEM pointer to the specified frame buffer for the specified
+ * state. The animation frame has length given by oled_pet_frame_bytes and is
+ * formatted as expected by oled_write_raw_P.
+ */
+const char *oled_pet_frame(oled_pet_state_t state);
diff --git a/users/bcat/bcat_oled_pet_isda.c b/users/bcat/bcat_oled_pet_isda.c
new file mode 100644
index 0000000000..98abddb13b
--- /dev/null
+++ b/users/bcat/bcat_oled_pet_isda.c
@@ -0,0 +1,134 @@
+/* Copyright 2018 sparrow666
+ * Copyright 2021 Jonathan Rascher
+ *
+ * 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/>.
+ */
+
+/* OLED pet "Isda" (animated unicorn) featuring artwork by OpenGameArt user
+ * sparrow666, licensed under GPL v2.0.
+ *
+ * The animation is 32x72 pixels (9 lines tall).
+ *
+ * Runs faster the quicker you type. Shows LED indicator (Num/Caps/Scroll Lock)
+ * status in the bottom-right corner.
+ *
+ * Named after the goddess Ehlonna's personal unicorn in the first D&D campaign
+ * I ever played. :)
+ *
+ * Artwork source: https://opengameart.org/content/unicorn-2
+ */
+
+#include "bcat_oled_pet.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bcat_oled.h"
+#include "led.h"
+#include "oled_driver.h"
+#include "progmem.h"
+
+#define NUM_FRAMES 4
+#define FRAME_BYTES 288 /* (32 pixel) * (72 pixel) / (8 pixel/byte) */
+
+uint16_t oled_pet_frame_bytes(void) { return FRAME_BYTES; }
+uint8_t oled_pet_frame_lines(void) { return 9 /* (72 pixel) / (8 pixel/line) */; }
+bool oled_pet_can_jump(void) { return false; }
+
+uint16_t oled_pet_update_millis(const oled_keyboard_state_t *keyboard_state) {
+ static const uint16_t MIN_MILLIS = 75;
+ static const uint16_t MAX_MILLIS = 300;
+ static const uint8_t MAX_WPM = 150;
+ uint8_t wpm = keyboard_state->wpm;
+ if (wpm > MAX_WPM) {
+ wpm = MAX_WPM;
+ }
+ return MAX_MILLIS - (MAX_MILLIS - MIN_MILLIS) * wpm / MAX_WPM;
+}
+
+oled_pet_state_t oled_pet_next_state(oled_pet_state_t state, const oled_keyboard_state_t *keyboard_state) {
+ /* When the user stops typing, cycle the animation to frame 0 and stop. */
+ return state != 0 || keyboard_state->wpm > 0 ? (state + 1) % NUM_FRAMES : 0;
+}
+
+void oled_pet_post_render(uint8_t col, uint8_t line, const oled_keyboard_state_t *keyboard_state, bool redraw) {
+ /* Draws LED indicator status in the bottom-right corner of the OLED pet,
+ * atop the animation frame. Redrawn only when necessary, e.g., when LED
+ * status changes or the animation itself updated (which overwrites any
+ * previously drawn indicators).
+ */
+ static led_t prev_leds = {.raw = 0};
+ led_t leds = keyboard_state->leds;
+ if (redraw || leds.raw != prev_leds.raw) {
+ oled_set_cursor(col + 4, line + 4);
+ oled_write_char(leds.num_lock ? 'N' : ' ', /*invert=*/false);
+ oled_set_cursor(col + 4, line + 6);
+ oled_write_char(leds.caps_lock ? 'C' : ' ', /*invert=*/false);
+ oled_set_cursor(col + 4, line + 8);
+ oled_write_char(leds.scroll_lock ? 'S' : ' ', /*invert=*/false);
+ prev_leds = leds;
+ }
+}
+
+const char *oled_pet_frame(oled_pet_state_t state) {
+ static const char PROGMEM FRAMES[NUM_FRAMES][FRAME_BYTES] = {
+ // clang-format off
+ {
+ 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, 0x80, 0x40, 0xa0, 0x60, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x88, 0xd0, 0x78, 0x04, 0x28, 0x70, 0x60, 0x90, 0x88, 0xc4, 0x22, 0x19, 0x04, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x84, 0x8c, 0x08, 0x01, 0x01, 0x02, 0x02, 0x04, 0x88, 0xf0, 0x00,
+ 0xc0, 0xe0, 0xe0, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0xff, 0xff, 0xff, 0x7f, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xe0, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfc, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x3c, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x03, 0xc6, 0x3c, 0x00, 0x80, 0x70, 0x1c, 0x0f, 0x03, 0x0f, 0x3f, 0xff, 0xff, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0xe0, 0xf8, 0xfe, 0x7f, 0x1f, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x0e, 0x30, 0x40, 0x47, 0x4f, 0x77, 0x03, 0x01, 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, 0x80, 0x40, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0xa0, 0xf0, 0x08, 0x50, 0xe0, 0xc0, 0x20, 0x10, 0x88, 0x44, 0x32, 0x09, 0x06, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x11, 0x03, 0x02, 0x04, 0x04, 0x08, 0x10, 0xe0, 0x00,
+ 0xc0, 0xe0, 0xe0, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00,
+ 0x00, 0x1f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x03, 0x00, 0x00, 0x80, 0xc0, 0x20, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0x3c, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x03, 0xc6, 0x3c, 0x00, 0x80, 0x70, 0x18, 0x0f, 0x03, 0x0f, 0x3f, 0xff, 0xff, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x38, 0x07, 0xc0, 0x38, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x7f, 0xff, 0xff, 0xe0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x20, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x0f, 0x0f, 0x0e, 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, 0x80, 0x40, 0xc0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0xa0, 0xf0, 0x08, 0x50, 0xe0, 0xc0, 0x20, 0x10, 0x88, 0x44, 0x32, 0x09, 0x06, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf8, 0xfe, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x11, 0x03, 0x02, 0x04, 0x04, 0x08, 0x10, 0xe0, 0x00,
+ 0xc0, 0xc0, 0xc0, 0x20, 0x20, 0x10, 0x08, 0x04, 0x03, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x3f, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00,
+ 0x00, 0x1f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x03, 0x00, 0x00, 0x80, 0xc0, 0x20, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x03, 0xc3, 0xfe, 0xfe, 0xfc, 0x7c, 0x1c, 0x0c, 0x0c, 0x08, 0x10, 0x60, 0x83, 0x07, 0x18, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x71, 0x0e, 0x80, 0x70, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x01, 0x0f, 0x3f, 0x7f, 0x7f, 0x78, 0xe0, 0x90, 0x88, 0x66, 0x11, 0x08, 0x06, 0x01, 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, 0x80, 0x40, 0xa0, 0x60, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x88, 0xd0, 0x78, 0x04, 0x28, 0x70, 0x60, 0x90, 0x88, 0xc4, 0x22, 0x19, 0x04, 0x03, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x84, 0x8c, 0x08, 0x01, 0x01, 0x02, 0x02, 0x04, 0x88, 0xf0, 0x00,
+ 0xc0, 0xe0, 0xe0, 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0xff, 0xff, 0xff, 0x7f, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0xe0, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xe0, 0xfc, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x03, 0xc6, 0xfc, 0xfc, 0xfc, 0x7c, 0x18, 0x08, 0x08, 0x08, 0x30, 0xc0, 0x03, 0x0c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xc0, 0xf8, 0xff, 0xff, 0x3f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x70, 0x80, 0x1f, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x18, 0x3e, 0x3f, 0x3f, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ // clang-format on
+ };
+ return FRAMES[state];
+}
diff --git a/users/bcat/bcat_oled_pet_luna.c b/users/bcat/bcat_oled_pet_luna.c
new file mode 100644
index 0000000000..f0397c9c05
--- /dev/null
+++ b/users/bcat/bcat_oled_pet_luna.c
@@ -0,0 +1,168 @@
+/* Copyright 2021 HellSingCoder
+ * Copyright 2021 Jonathan Rascher
+ *
+ * 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/>.
+ */
+
+/* OLED pet "Luna" (animated doggo) originally by HellSingCoder
+ * (https://www.simonepellegrino.com/) and licensed under GPL v2.0, adapted to
+ * fit the OLED pet framework in bcat's userspace.
+ *
+ * The animation is 32x24 pixels (3 lines tall).
+ *
+ * Walks or runs in response to typing speed. Sneaks when Ctrl is pressed and
+ * barks when Caps Lock is on. Jumps when space is pressed.
+ *
+ * Original source:
+ * https://github.com/qmk/qmk_firmware/blob/6dfe915e26d7147e6c2bed495d3b01cf5b21e6ec/keyboards/sofle/keymaps/helltm/keymap.c
+ */
+
+#include "bcat_oled_pet.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "bcat_oled.h"
+#include "keycode.h"
+#include "progmem.h"
+
+enum image {
+ IMAGE_IDLE,
+ IMAGE_WALK,
+ IMAGE_RUN,
+ IMAGE_SNEAK,
+ IMAGE_BARK,
+};
+
+typedef union {
+ oled_pet_state_t raw;
+ struct {
+ uint8_t image;
+ uint8_t frame;
+ };
+} luna_state_t;
+
+#define NUM_FRAMES 2
+#define FRAME_BYTES 96 /* (32 pixel) * (24 pixel) / (8 pixel/byte) */
+
+uint16_t oled_pet_frame_bytes(void) { return FRAME_BYTES; }
+uint8_t oled_pet_frame_lines(void) { return 3 /* (24 pixel) / (8 pixel/line) */; }
+bool oled_pet_can_jump(void) { return true; }
+
+uint16_t oled_pet_update_millis(const oled_keyboard_state_t *keyboard_state) { return 200; }
+
+oled_pet_state_t oled_pet_next_state(oled_pet_state_t state, const oled_keyboard_state_t *keyboard_state) {
+ luna_state_t luna_state = {.raw = state};
+ if (keyboard_state->leds.caps_lock) {
+ luna_state.image = IMAGE_BARK;
+ } else if (keyboard_state->mods & MOD_MASK_CTRL) {
+ luna_state.image = IMAGE_SNEAK;
+ } else if (keyboard_state->wpm >= 100) {
+ luna_state.image = IMAGE_RUN;
+ } else if (keyboard_state->wpm >= 25) {
+ luna_state.image = IMAGE_WALK;
+ } else {
+ luna_state.image = IMAGE_IDLE;
+ }
+ luna_state.frame = (luna_state.frame + 1) % NUM_FRAMES;
+ return luna_state.raw;
+}
+
+void oled_pet_post_render(uint8_t col, uint8_t line, const oled_keyboard_state_t *keyboard_state, bool redraw) {}
+
+const char *oled_pet_frame(oled_pet_state_t state) {
+ static const char PROGMEM IDLE_FRAMES[NUM_FRAMES][FRAME_BYTES] = {
+ // clang-format off
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1c, 0x02, 0x05, 0x02, 0x24, 0x04, 0x04, 0x02, 0xa9, 0x1e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x08, 0x68, 0x10, 0x08, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x82, 0x7c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0c, 0x10, 0x10, 0x20, 0x20, 0x20, 0x28, 0x3e, 0x1c, 0x20, 0x20, 0x3e, 0x0f, 0x11, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1c, 0x02, 0x05, 0x02, 0x24, 0x04, 0x04, 0x02, 0xa9, 0x1e, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x90, 0x08, 0x18, 0x60, 0x10, 0x08, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x82, 0x7c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x0c, 0x10, 0x10, 0x20, 0x20, 0x20, 0x28, 0x3e, 0x1c, 0x20, 0x20, 0x3e, 0x0f, 0x11, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ // clang-format on
+ };
+ static const char PROGMEM WALK_FRAMES[NUM_FRAMES][FRAME_BYTES] = {
+ // clang-format off
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x90, 0x90, 0x90, 0xa0, 0xc0, 0x80, 0x80, 0x80, 0x70, 0x08, 0x14, 0x08, 0x90, 0x10, 0x10, 0x08, 0xa4, 0x78, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x18, 0xea, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1c, 0x20, 0x20, 0x3c, 0x0f, 0x11, 0x1f, 0x03, 0x06, 0x18, 0x20, 0x20, 0x3c, 0x0c, 0x12, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x20, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x28, 0x10, 0x20, 0x20, 0x20, 0x10, 0x48, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x20, 0xf8, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x30, 0xd5, 0x20, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x30, 0x0c, 0x02, 0x05, 0x09, 0x12, 0x1e, 0x02, 0x1c, 0x14, 0x08, 0x10, 0x20, 0x2c, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ // clang-format on
+ };
+ static const char PROGMEM RUN_FRAMES[NUM_FRAMES][FRAME_BYTES] = {
+ // clang-format off
+ {
+ 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x08, 0x08, 0xc8, 0xb0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x40, 0x3c, 0x14, 0x04, 0x08, 0x90, 0x18, 0x04, 0x08, 0xb0, 0x40, 0x80, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xc4, 0xa4, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc8, 0x58, 0x28, 0x2a, 0x10, 0x0f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x09, 0x04, 0x04, 0x04, 0x04, 0x02, 0x03, 0x02, 0x01, 0x01, 0x02, 0x02, 0x04, 0x08, 0x10, 0x26, 0x2b, 0x32, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ {
+ 0x00, 0x00, 0x00, 0xe0, 0x10, 0x10, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x78, 0x28, 0x08, 0x10, 0x20, 0x30, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x04, 0x08, 0x10, 0x11, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0xb0, 0x50, 0x55, 0x20, 0x1f, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x10, 0x20, 0x28, 0x37, 0x02, 0x1e, 0x20, 0x20, 0x18, 0x0c, 0x14, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ // clang-format on
+ };
+ static const char PROGMEM SNEAK_FRAMES[NUM_FRAMES][FRAME_BYTES] = {
+ // clang-format off
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x40, 0x40, 0x80, 0x00, 0x80, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x1e, 0x21, 0xf0, 0x04, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x04, 0x04, 0x04, 0x03, 0x01, 0x00, 0x00, 0x09, 0x01, 0x80, 0x80, 0xab, 0x04, 0xf8, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1c, 0x20, 0x20, 0x3c, 0x0f, 0x11, 0x1f, 0x02, 0x06, 0x18, 0x20, 0x20, 0x38, 0x08, 0x10, 0x18, 0x04, 0x04, 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
+ },
+ {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xa0, 0x20, 0x40, 0x80, 0xc0, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3e, 0x41, 0xf0, 0x04, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, 0x40, 0x55, 0x82, 0x7c, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x30, 0x0c, 0x02, 0x05, 0x09, 0x12, 0x1e, 0x04, 0x18, 0x10, 0x08, 0x10, 0x20, 0x28, 0x34, 0x06, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ // clang-format on
+ };
+ static const char PROGMEM BARK_FRAMES[NUM_FRAMES][FRAME_BYTES] = {
+ // clang-format off
+ {
+ 0x00, 0xc0, 0x20, 0x10, 0xd0, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x3c, 0x14, 0x04, 0x08, 0x90, 0x18, 0x04, 0x08, 0xb0, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x04, 0x08, 0x10, 0x11, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc8, 0x48, 0x28, 0x2a, 0x10, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x10, 0x20, 0x28, 0x37, 0x02, 0x02, 0x04, 0x08, 0x10, 0x26, 0x2b, 0x32, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ {
+ 0x00, 0xe0, 0x10, 0x10, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x40, 0x40, 0x2c, 0x14, 0x04, 0x08, 0x90, 0x18, 0x04, 0x08, 0xb0, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x04, 0x08, 0x10, 0x11, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0x48, 0x28, 0x2a, 0x10, 0x0f, 0x20, 0x4a, 0x09, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x0c, 0x10, 0x20, 0x28, 0x37, 0x02, 0x02, 0x04, 0x08, 0x10, 0x26, 0x2b, 0x32, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ // clang-format on
+ };
+ luna_state_t luna_state = {.raw = state};
+ switch (luna_state.image) {
+ case IMAGE_WALK:
+ return WALK_FRAMES[luna_state.frame];
+ case IMAGE_RUN:
+ return RUN_FRAMES[luna_state.frame];
+ case IMAGE_SNEAK:
+ return SNEAK_FRAMES[luna_state.frame];
+ case IMAGE_BARK:
+ return BARK_FRAMES[luna_state.frame];
+ default:
+ return IDLE_FRAMES[luna_state.frame];
+ }
+}
diff --git a/users/drashna/rgb_matrix_stuff.h b/users/bcat/bcat_rgblight.c
index b86f2f6514..cd6222262b 100644
--- a/users/drashna/rgb_matrix_stuff.h
+++ b/users/bcat/bcat_rgblight.c
@@ -1,4 +1,4 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+/* Copyright 2021 Jonathan Rascher
*
* 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
@@ -14,12 +14,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-#include "quantum.h"
+#include <stdint.h>
-bool process_record_user_rgb_matrix(uint16_t keycode, keyrecord_t *record);
-void keyboard_post_init_rgb_matrix(void);
-void matrix_scan_rgb_matrix(void);
+#include "progmem.h"
-void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
-void rgb_matrix_layer_helper(uint8_t hue, uint8_t sat, uint8_t val, uint8_t mode, uint8_t speed, uint8_t led_type, uint8_t led_min, uint8_t led_max);
+/* Adjust RGB static hue ranges for shorter gradients than default. */
+const uint8_t RGBLED_GRADIENT_RANGES[] PROGMEM = {255, 127, 63, 31, 15};
diff --git a/users/bcat/compile.sh b/users/bcat/compile.sh
new file mode 100755
index 0000000000..9d5e58b1a1
--- /dev/null
+++ b/users/bcat/compile.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+set -o errexit -o nounset
+
+usage () {
+ printf "\
+usage: ./users/bcat/compile.sh [-c] [-j N]
+
+Compiles all keyboards for which bcat maintains keymaps.
+
+optional arguments:
+ -c performs a clean build
+ -j N runs N make tasks in parallel
+ -v shows verbose output
+"
+}
+
+compile () {
+ local keyboard=$1 layout=${2:-}
+ FORCE_LAYOUT="$layout" SILENT="$opt_silent" make -j "$opt_parallel" "$keyboard":bcat
+}
+
+opt_parallel=1
+opt_silent=true
+
+while getopts :chj:v opt; do
+ case $opt in
+ c) opt_clean=1 ;;
+ j) opt_parallel=$OPTARG ;;
+ v) opt_silent=false ;;
+ h) usage; exit 0 ;;
+ \?) usage >&2; exit 2 ;;
+ esac
+done
+
+if [[ -n ${opt_clean:-} ]]; then
+ SILENT="$opt_silent" make clean
+fi
+
+compile 9key
+compile ai03/polaris 60_tsangan_hhkb
+compile cannonkeys/an_c 60_tsangan_hhkb
+compile cannonkeys/instant60 60_tsangan_hhkb
+compile crkbd/rev1 split_3x6_3
+compile dz60 60_ansi_split_bs_rshift
+compile dz60 60_tsangan_hhkb
+compile eco/rev2
+compile kbdfans/kbd67/hotswap 65_ansi_blocker_split_bs
+compile keebio/bdn9/rev1
+compile keebio/quefrency/rev1
+compile lily58/rev1
+compile yanghu/unicorne/f411
diff --git a/users/bcat/config.h b/users/bcat/config.h
index 5bb93f3833..7bb5d71bae 100644
--- a/users/bcat/config.h
+++ b/users/bcat/config.h
@@ -14,6 +14,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+/* Enable NKRO by default. All my devices support this, and it enables me to
+ * dispense with the NK_TOGG key, thus saving firmware space by not compiling
+ * magic keycode support.
+ */
+#define FORCE_NKRO
+
/* Wait between tap_code register and unregister to fix flaky media keys. */
#undef TAP_CODE_DELAY
@@ -31,6 +37,22 @@
*/
#define TAPPING_FORCE_HOLD
+#if defined(OLED_ENABLE)
+/* The built-in OLED timeout wakes the OLED screen every time the buffer is
+ * updated, even if no user activity has occurred recently. This prevents the
+ * OLED from ever turning off during a continuously running animation. To avoid
+ * this, we disable the default timeout and implement our own in
+ * oled_task_user.
+ */
+# undef OLED_TIMEOUT
+# define OLED_DISABLE_TIMEOUT
+
+# if defined(SPLIT_KEYBOARD)
+/* Sync OLED on/off state between halves of split keyboards. */
+# define SPLIT_OLED_ENABLE
+# endif
+#endif
+
#if defined(RGB_MATRIX_ENABLE)
/* Turn off per-key RGB when the host goes to sleep. */
# define RGB_DISABLE_WHEN_USB_SUSPENDED
@@ -46,9 +68,42 @@
# define RGB_MATRIX_VAL_STEP 17
# define RGB_MATRIX_SPD_STEP 17
-/* Turn on additional RGB animations. */
+/* Enable specific per-key animation modes. */
+# define ENABLE_RGB_MATRIX_ALPHAS_MODS
+# define ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
+# define ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
+# define ENABLE_RGB_MATRIX_BAND_SAT
+# define ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
+# define ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
+# define ENABLE_RGB_MATRIX_BAND_VAL
+# define ENABLE_RGB_MATRIX_BREATHING
+# define ENABLE_RGB_MATRIX_CYCLE_ALL
+# define ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
+# define ENABLE_RGB_MATRIX_CYCLE_OUT_IN
+# define ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
+# define ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
+# define ENABLE_RGB_MATRIX_CYCLE_SPIRAL
+# define ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
+# define ENABLE_RGB_MATRIX_DUAL_BEACON
+# define ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
+# define ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
+# define ENABLE_RGB_MATRIX_HUE_BREATHING
+# define ENABLE_RGB_MATRIX_HUE_PENDULUM
+# define ENABLE_RGB_MATRIX_HUE_WAVE
+# define ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
+# define ENABLE_RGB_MATRIX_PIXEL_FRACTAL
+# define ENABLE_RGB_MATRIX_PIXEL_RAIN
+# define ENABLE_RGB_MATRIX_RAINBOW_BEACON
+# define ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
+# define ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
+# define ENABLE_RGB_MATRIX_RAINDROPS
+
+/* Enable additional per-key animation modes that require a copy of the
+ * framebuffer (with accompanying storage cost).
+ */
# define RGB_MATRIX_FRAMEBUFFER_EFFECTS
-# define RGB_MATRIX_KEYPRESSES
+# define ENABLE_RGB_MATRIX_DIGITAL_RAIN
+# define ENABLE_RGB_MATRIX_TYPING_HEATMAP
#endif
#if defined(RGBLIGHT_ENABLE)
@@ -64,8 +119,18 @@
# define RGBLIGHT_SAT_STEP 17
# define RGBLIGHT_VAL_STEP 17
-/* Turn on additional RGB animations. */
-# define RGBLIGHT_ANIMATIONS
+/* Enable specific underglow animation modes. (Skip TWINKLE because it seems to
+ * be broken on ARM: https://github.com/qmk/qmk_firmware/issues/15345.)
+ */
+# define RGBLIGHT_EFFECT_ALTERNATING
+# define RGBLIGHT_EFFECT_BREATHING
+# define RGBLIGHT_EFFECT_CHRISTMAS
+# define RGBLIGHT_EFFECT_KNIGHT
+# define RGBLIGHT_EFFECT_RAINBOW_MOOD
+# define RGBLIGHT_EFFECT_RAINBOW_SWIRL
+# define RGBLIGHT_EFFECT_RGB_TEST
+# define RGBLIGHT_EFFECT_SNAKE
+# define RGBLIGHT_EFFECT_STATIC_GRADIENT
#endif
#if defined(BACKLIGHT_ENABLE)
@@ -77,3 +142,9 @@
# define BACKLIGHT_LEVELS 7
#endif
+
+/* Turn off unused config options to reduce firmware size. */
+#define LAYER_STATE_8BIT
+#define NO_ACTION_ONESHOT
+#undef LOCKING_RESYNC_ENABLE
+#undef LOCKING_SUPPORT_ENABLE
diff --git a/users/bcat/readme.md b/users/bcat/readme.md
index 1922f95f4a..3650e8ee42 100644
--- a/users/bcat/readme.md
+++ b/users/bcat/readme.md
@@ -6,6 +6,8 @@ keyboard-specific keymaps for boards without standard layout support. I derive
my keymaps from two canonical ones (preferred for typing and gaming,
respectively).
+You can build all keymaps I maintain at once using `./users/bcat/compile.sh`.
+
## Canonical keymaps
* [Split 3x6 + 3 thumb
@@ -22,6 +24,7 @@ AN-C, CannonKeys Instant60, DZ60.
### Ergo
* [Lily58](https://github.com/qmk/qmk_firmware/tree/master/keyboards/lily58/keymaps/bcat)
+* [Unicorne](https://github.com/qmk/qmk_firmware/tree/master/keyboards/yanghu/unicorne/keymaps/bcat)
### Ortho
diff --git a/users/bcat/rules.mk b/users/bcat/rules.mk
index 12c9a89bf4..1ad2ee0aa8 100644
--- a/users/bcat/rules.mk
+++ b/users/bcat/rules.mk
@@ -1,7 +1,10 @@
-SRC += bcat.c
-
-# Enable Bootmagic Lite to consistently reset to bootloader and clear EEPROM.
-BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
+# Enable Bootmagic Lite for keyboards that don't have an easily accessible
+# reset button, but keep it disabled for all others to reduce firmware size.
+ifneq ($(filter $(strip $(KEYBOARD)),ai03/polaris dz60 kbdfans/kbd67/hotswap yanghu/unicorne/f411),)
+ BOOTMAGIC_ENABLE = yes
+else
+ BOOTMAGIC_ENABLE = no
+endif
# Enable media keys on all keyboards.
EXTRAKEY_ENABLE = yes
@@ -16,21 +19,49 @@ NKRO_ENABLE = yes
# Enable link-time optimization to reduce binary size.
LTO_ENABLE = yes
-# Disable unused build options on all keyboards.
+# Include common utilities shared across all our keymaps.
+SRC += bcat.c
+
+# Include additional utilities that extend optional QMK features only enabled
+# on some keyboards.
+ifeq ($(strip $(OLED_ENABLE)), yes)
+ SRC += bcat_oled.c
+ WPM_ENABLE = yes # for WPM and animated "keyboard pet" widgets
+
+ # OLED pets (animated critters that react to typing) take up a lot of
+ # firmware space, so only compile one, and only if requested.
+ BCAT_OLED_PET ?= no
+ ifneq ($(strip $(BCAT_OLED_PET)), no)
+ SRC += bcat_oled_pet_$(strip $(BCAT_OLED_PET)).c
+ OPT_DEFS += -DBCAT_OLED_PET
+ endif
+endif
+
+ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
+ SRC += bcat_rgblight.c
+endif
+
+# Disable unwanted build options on all keyboards. (Mouse keys are turned off
+# due to https://github.com/qmk/qmk_firmware/issues/8323, and the rest are
+# turned off to reduce firmware size.)
COMMAND_ENABLE = no
CONSOLE_ENABLE = no
MOUSEKEY_ENABLE = no
TERMINAL_ENABLE = no
-# Disable unused hardware options on all keyboards.
+# Disable unwanted hardware options on all keyboards. (Some keyboards turn
+# these features on by default even though they aren't actually required.)
MIDI_ENABLE = no
SLEEP_LED_ENABLE = no
# Disable other unused options on all keyboards.
AUTO_SHIFT_ENABLE = no
COMBO_ENABLE = no
+GRAVE_ESC_ENABLE = no
KEY_LOCK_ENABLE = no
LEADER_ENABLE = no
+MAGIC_ENABLE = no
+SPACE_CADET_ENABLE = no
SWAP_HANDS_ENABLE = no
TAP_DANCE_ENABLE = no
UCIS_ENABLE = no
diff --git a/users/byungyoonc/byungyoonc.c b/users/byungyoonc/byungyoonc.c
new file mode 100644
index 0000000000..5059de0d97
--- /dev/null
+++ b/users/byungyoonc/byungyoonc.c
@@ -0,0 +1,48 @@
+/* Copyright 2021 Choi Byungyoon <byungyoonc@gmail.com>
+ *
+ * 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 "byungyoonc.h"
+
+#if (__has_include("secrets.h") && !defined(NO_SECRETS))
+# include "secrets.h"
+#else
+static const char *const secrets[] = {"test1", "test2"};
+#endif
+
+#if !defined(MACRO_TIMER)
+# define MACRO_TIMER 20
+#endif
+
+/* replicaJunction's process_record_user_kb */
+__attribute__ ((weak))
+bool process_record_user_kb(uint16_t keycode, keyrecord_t *record) {
+ return true;
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case KC_SEC1 ... KC_SEC2: /* Secrets! Externally defined strings, not stored in repo */
+ if (!record->event.pressed) {
+ clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+ send_string_with_delay(secrets[keycode - KC_SEC1], MACRO_TIMER);
+ }
+ return false;
+ break;
+ }
+ return process_record_user_kb(keycode, record);
+};
+
diff --git a/users/drashna/rgb_stuff.h b/users/byungyoonc/byungyoonc.h
index af1acdde71..6d82370a01 100644
--- a/users/drashna/rgb_stuff.h
+++ b/users/byungyoonc/byungyoonc.h
@@ -1,4 +1,4 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+/* Copyright 2021 Choi Byungyoon <byungyoonc@gmail.com>
*
* 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
@@ -15,11 +15,13 @@
*/
#pragma once
-#include "quantum.h"
-bool process_record_user_rgb_light(uint16_t keycode, keyrecord_t *record);
-void keyboard_post_init_rgb_light(void);
-void matrix_scan_rgb_light(void);
-layer_state_t layer_state_set_rgb_light(layer_state_t state);
-layer_state_t default_layer_state_set_rgb_light(layer_state_t state);
-void rgblight_sethsv_default_helper(uint8_t index);
+enum custom_keycodes {
+ KC_SEC1 = SAFE_RANGE,
+ KC_SEC2
+};
+
+#define KC_TASK LCTL(LSFT(KC_ESC))
+#define KC_MMUT LSG(KC_A)
+
+bool process_record_user_kb(uint16_t keycode, keyrecord_t *record);
diff --git a/users/byungyoonc/readme.md b/users/byungyoonc/readme.md
new file mode 100644
index 0000000000..d0bc8d14d4
--- /dev/null
+++ b/users/byungyoonc/readme.md
@@ -0,0 +1,14 @@
+byungyoonc QMK Userspace
+========================
+
+# Overview
+Defines some custom keycodes, alongside with the Secrets feature. Also incorporates `process_record_user_kb()` for further controls.
+
+Heavily influenced by the [Userspace code by replicaJunction](../replicaJunction/readme.md).
+
+# Features
+
+## Custom Keycodes
+- `KC_SEC#` for the Secrets input
+- `KC_TASK` for the Windows Task Manager shortcut `LCTL(LSFT(KC_ESC))`
+- `KC_MMUT` for the Windows PowerToys Conference Mute microphone `LSG(KC_A)`
diff --git a/users/byungyoonc/rules.mk b/users/byungyoonc/rules.mk
new file mode 100644
index 0000000000..39c65e2238
--- /dev/null
+++ b/users/byungyoonc/rules.mk
@@ -0,0 +1 @@
+SRC += byungyoonc.c
diff --git a/users/byungyoonc/saturated_solid_multisplash.h b/users/byungyoonc/saturated_solid_multisplash.h
new file mode 100644
index 0000000000..f302348524
--- /dev/null
+++ b/users/byungyoonc/saturated_solid_multisplash.h
@@ -0,0 +1,50 @@
+/* Copyright 2021 Choi Byungyoon <byungyoonc@gmail.com>
+ *
+ * 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/>.
+ */
+
+#if defined(RGB_MATRIX_KEYPRESSES)
+RGB_MATRIX_EFFECT(saturated_solid_multisplash)
+
+# if defined(RGB_MATRIX_CUSTOM_EFFECT_IMPLS)
+
+static bool saturated_solid_multisplash(effect_params_t* params) {
+ RGB_MATRIX_USE_LIMITS(led_min, led_max);
+
+ uint8_t count = g_last_hit_tracker.count;
+ for (uint8_t i = led_min; i < led_max; i++) {
+ RGB_MATRIX_TEST_LED_FLAGS();
+ HSV hsv = rgb_matrix_config.hsv;
+ hsv.v = 0;
+ for (uint8_t j = 0; j < count; j++) {
+ int16_t dx = g_led_config.point[i].x - g_last_hit_tracker.x[j];
+ int16_t dy = g_led_config.point[i].y - g_last_hit_tracker.y[j];
+ uint8_t dist = sqrt16(dx * dx + dy * dy);
+ uint16_t tick = scale16by8(g_last_hit_tracker.tick[j], qadd8(rgb_matrix_config.speed, 1));
+
+ uint16_t effect = tick - dist;
+ if (effect > 255) effect = 255;
+ uint16_t vdiff = scale16by8(255 - effect, 255 - dist);
+ hsv.v = qadd8(hsv.v, vdiff);
+ hsv.s = qsub8(hsv.s, qsub8(127, effect));
+ }
+ hsv.v = scale8(hsv.v, rgb_matrix_config.hsv.v);
+ RGB rgb = rgb_matrix_hsv_to_rgb(hsv);
+ rgb_matrix_set_color(i, rgb.r, rgb.g, rgb.b);
+ }
+ return led_max < DRIVER_LED_TOTAL;
+}
+
+# endif // RGB_MATRIX_CUSTOM_EFFECT_IMPLS
+#endif // RGB_MATRIX_KEYPRESSES
diff --git a/users/drashna/callbacks.c b/users/drashna/callbacks.c
new file mode 100644
index 0000000000..f01aab433e
--- /dev/null
+++ b/users/drashna/callbacks.c
@@ -0,0 +1,211 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "drashna.h"
+
+__attribute__((weak)) void keyboard_pre_init_keymap(void) {}
+void keyboard_pre_init_user(void) {
+ userspace_config.raw = eeconfig_read_user();
+ keyboard_pre_init_keymap();
+}
+// Add reconfigurable functions here, for keymap customization
+// This allows for a global, userspace functions, and continued
+// customization of the keymap. Use _keymap instead of _user
+// functions in the keymaps
+// Call user matrix init, set default RGB colors and then
+// call the keymap's init function
+__attribute__((weak)) void matrix_init_keymap(void) {}
+__attribute__((weak)) void matrix_init_secret(void) {}
+void matrix_init_user(void) {
+#if defined(BOOTLOADER_CATERINA) && defined(__AVR__) && defined(__AVR_ATmega32U4__)
+ DDRD &= ~(1 << 5);
+ PORTD &= ~(1 << 5);
+
+ DDRB &= ~(1 << 0);
+ PORTB &= ~(1 << 0);
+#endif
+#ifdef CUSTOM_UNICODE_ENABLE
+ matrix_init_unicode();
+#endif
+ matrix_init_secret();
+ matrix_init_keymap();
+}
+
+__attribute__((weak)) void keyboard_post_init_keymap(void) {}
+void keyboard_post_init_user(void) {
+#if defined(RGBLIGHT_ENABLE)
+ keyboard_post_init_rgb_light();
+#endif
+#if defined(RGB_MATRIX_ENABLE)
+ keyboard_post_init_rgb_matrix();
+#endif
+#if defined(SPLIT_KEYBOARD) && defined(SPLIT_TRANSACTION_IDS_USER)
+ keyboard_post_init_transport_sync();
+#endif
+ keyboard_post_init_keymap();
+}
+
+#ifdef RGB_MATRIX_ENABLE
+void rgb_matrix_update_pwm_buffers(void);
+#endif
+
+__attribute__((weak)) void shutdown_keymap(void) {}
+void shutdown_user(void) {
+#ifdef RGBLIGHT_ENABLE
+ rgblight_enable_noeeprom();
+ rgblight_mode_noeeprom(1);
+ rgblight_setrgb_red();
+#endif // RGBLIGHT_ENABLE
+#ifdef RGB_MATRIX_ENABLE
+ rgb_matrix_set_color_all(0xFF, 0x00, 0x00);
+ rgb_matrix_update_pwm_buffers();
+#endif // RGB_MATRIX_ENABLE
+#ifdef OLED_ENABLE
+ oled_off();
+#endif
+
+ shutdown_keymap();
+}
+
+__attribute__((weak)) void suspend_power_down_keymap(void) {}
+
+void suspend_power_down_user(void) {
+ if (layer_state_is(_GAMEPAD)) {
+ layer_off(_GAMEPAD);
+ }
+ if (layer_state_is(_DIABLO)) {
+ layer_off(_DIABLO);
+ }
+ if (layer_state_is(_DIABLOII)) {
+ layer_off(_DIABLOII);
+ }
+#ifdef OLED_ENABLE
+ oled_off();
+#endif
+ suspend_power_down_keymap();
+}
+
+__attribute__((weak)) void suspend_wakeup_init_keymap(void) {}
+void suspend_wakeup_init_user(void) {
+ suspend_wakeup_init_keymap();
+}
+
+// No global matrix scan code, so just run keymap's matrix
+// scan function
+__attribute__((weak)) void matrix_scan_keymap(void) {}
+__attribute__((weak)) void matrix_scan_secret(void) {}
+void matrix_scan_user(void) {
+ static bool has_ran_yet;
+ if (!has_ran_yet) {
+ has_ran_yet = true;
+ startup_user();
+ }
+
+#ifdef TAP_DANCE_ENABLE // Run Diablo 3 macro checking code.
+ run_diablo_macro_check();
+#endif // TAP_DANCE_ENABLE
+
+#if defined(RGB_MATRIX_ENABLE)
+ matrix_scan_rgb_matrix();
+#endif
+ matrix_scan_secret();
+
+ matrix_scan_keymap();
+}
+
+#ifdef AUDIO_ENABLE
+float doom_song[][2] = SONG(E1M1_DOOM);
+#endif
+
+// on layer change, no matter where the change was initiated
+// Then runs keymap's layer change check
+__attribute__((weak)) layer_state_t layer_state_set_keymap(layer_state_t state) { return state; }
+layer_state_t layer_state_set_user(layer_state_t state) {
+ if (!is_keyboard_master()) {
+ return state;
+ }
+
+ state = update_tri_layer_state(state, _RAISE, _LOWER, _ADJUST);
+#if defined(POINTING_DEVICE_ENABLE)
+ state = layer_state_set_pointing(state);
+#endif
+#if defined(RGBLIGHT_ENABLE)
+ state = layer_state_set_rgb_light(state);
+#endif // RGBLIGHT_ENABLE
+#if defined(AUDIO_ENABLE) && !defined(__arm__)
+ static bool is_gamepad_on = false;
+ if (layer_state_cmp(state, _GAMEPAD) != is_gamepad_on) {
+ is_gamepad_on = layer_state_cmp(state, _GAMEPAD);
+ if (is_gamepad_on) {
+ PLAY_LOOP(doom_song);
+ } else {
+ stop_all_notes();
+ }
+ }
+#endif
+ state = layer_state_set_keymap(state);
+ return state;
+}
+
+// Runs state check and changes underglow color and animation
+__attribute__((weak)) layer_state_t default_layer_state_set_keymap(layer_state_t state) { return state; }
+layer_state_t default_layer_state_set_user(layer_state_t state) {
+ if (!is_keyboard_master()) {
+ return state;
+ }
+
+ state = default_layer_state_set_keymap(state);
+#if 0
+# if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
+ state = default_layer_state_set_rgb(state);
+# endif // RGBLIGHT_ENABLE
+#endif
+ return state;
+}
+
+__attribute__((weak)) void led_set_keymap(uint8_t usb_led) {}
+void led_set_user(uint8_t usb_led) { led_set_keymap(usb_led); }
+
+__attribute__((weak)) void eeconfig_init_keymap(void) {}
+void eeconfig_init_user(void) {
+ userspace_config.raw = 0;
+ userspace_config.rgb_layer_change = true;
+ eeconfig_update_user(userspace_config.raw);
+ eeconfig_init_keymap();
+}
+
+#ifdef SPLIT_KEYBOARD
+__attribute__((weak)) void matrix_slave_scan_keymap(void) {}
+void matrix_slave_scan_user(void) {
+# if defined(AUDIO_ENABLE)
+# if !defined(NO_MUSIC_MODE)
+ music_task();
+# endif
+# ifdef AUDIO_INIT_DELAY
+ if (!is_keyboard_master()) {
+ static bool delayed_tasks_run = false;
+ static uint16_t delayed_task_timer = 0;
+ if (!delayed_tasks_run) {
+ if (!delayed_task_timer) {
+ delayed_task_timer = timer_read();
+ } else if (timer_elapsed(delayed_task_timer) > 300) {
+ audio_startup();
+ delayed_tasks_run = true;
+ }
+ }
+ }
+# endif
+# endif
+# ifdef SEQUENCER_ENABLE
+ sequencer_task();
+# endif
+# ifdef LED_MATRIX_ENABLE
+ led_matrix_task();
+# endif
+# ifdef HAPTIC_ENABLE
+ haptic_task();
+# endif
+
+ matrix_slave_scan_keymap();
+}
+#endif
diff --git a/users/drashna/callbacks.h b/users/drashna/callbacks.h
new file mode 100644
index 0000000000..f6ac6b88de
--- /dev/null
+++ b/users/drashna/callbacks.h
@@ -0,0 +1,25 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "quantum.h"
+
+void matrix_init_keymap(void);
+void matrix_init_secret(void);
+void shutdown_keymap(void);
+void suspend_power_down_keymap(void);
+void suspend_wakeup_init_keymap(void);
+void matrix_scan_keymap(void);
+void matrix_scan_secret(void);
+layer_state_t layer_state_set_keymap(layer_state_t state);
+layer_state_t default_layer_state_set_keymap(layer_state_t state);
+void led_set_keymap(uint8_t usb_led);
+void eeconfig_init_keymap(void);
+
+#ifdef CUSTOM_UNICODE_ENABLE
+void matrix_init_unicode(void);
+#endif
+#ifdef SPLIT_KEYBOARD
+void matrix_slave_scan_keymap(void);
+#endif
diff --git a/users/drashna/callbacks.md b/users/drashna/callbacks.md
new file mode 100644
index 0000000000..a0f0d9fdae
--- /dev/null
+++ b/users/drashna/callbacks.md
@@ -0,0 +1,71 @@
+# Custom Userspace Callback Functions
+
+Specifically QMK works by using customized callback functions for everything. This allows for multiple levels of customization.
+
+`matrix_scan` calls `matrix_scan_quantum`, which calls `matrix_scan_kb`, which calls `matrix_scan_user`.
+`process_record` calls a bunch of stuff, but eventually calls `process_record_kb` which calls `process_record_user`
+The same goes for `matrix_init`, `layer_state_set`, `led_set`, and a few other functions.
+
+All (most) `_user` functions are handled here, in the userspace instead. To allow keyboard specific configuration, I've created `_keymap` functions that can be called by the keymap.c files instead.
+
+This allows for keyboard specific configuration while maintaining the ability to customize the board.
+
+My [Ergodox EZ Keymap](https://github.com/qmk/qmk_firmware/blob/master/layouts/community/ergodox/drashna/keymap.c) is a good example of this, as it uses the LEDs as modifier indicators.
+
+You can see a list of these files in [callbacks.c](callbacks.c), or a shortend list here
+
+```c
+__attribute__((weak)) void matrix_init_keymap(void) {}
+void matrix_init_user(void) {
+ matrix_init_keymap();
+}
+
+__attribute__((weak)) void keyboard_post_init_keymap(void) {}
+void keyboard_post_init_user(void) {
+ keyboard_post_init_keymap();
+}
+
+__attribute__((weak)) void matrix_scan_keymap(void) {}
+void matrix_scan_user(void) {
+ matrix_scan_keymap();
+}
+
+__attribute__ ((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; }
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ if (!process_record_keymap(keycode, record)) { return false; }
+ return true;
+}
+
+__attribute__((weak)) layer_state_t layer_state_set_keymap(layer_state_t state) { return state; }
+layer_state_t layer_state_set_user(layer_state_t state) {
+ state = layer_state_set_keymap(state);
+ return state;
+}
+
+__attribute__ ((weak)) void led_set_keymap(uint8_t usb_led) {}
+void led_set_user(uint8_t usb_led) {
+ led_set_keymap(usb_led);
+}
+
+__attribute__ ((weak)) void suspend_power_down_keymap(void) {}
+void suspend_power_down_user(void) {
+ suspend_power_down_keymap();
+}
+
+__attribute__ ((weak)) void suspend_wakeup_init_keymap(void) {}
+void suspend_wakeup_init_user(void) {
+ suspend_wakeup_init_keymap();
+}
+
+
+__attribute__ ((weak)) void shutdown_keymap(void) {}
+void shutdown_user (void) {
+ shutdown_keymap();
+}
+
+__attribute__ ((weak)) void eeconfig_init_keymap(void) {}
+void eeconfig_init_user(void) {
+ eeconfig_update_user(0);
+ eeconfig_init_keymap();
+}
+```
diff --git a/users/drashna/config.h b/users/drashna/config.h
index ebb8d7b7ac..f55ed36bc2 100644
--- a/users/drashna/config.h
+++ b/users/drashna/config.h
@@ -1,24 +1,16 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// Use custom magic number so that when switching branches, EEPROM always gets reset
#define EECONFIG_MAGIC_NUMBER (uint16_t)0x1339
+#ifdef IS_COMMAND
+#undef IS_COMMAND
+#endif
+#define IS_COMMAND() (((get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT) == MOD_MASK_SHIFT)
+
/* Set Polling rate to 1000Hz */
#define USB_POLLING_INTERVAL_MS 1
@@ -37,10 +29,19 @@
# define SELECT_SOFT_SERIAL_SPEED 1
# endif
# ifdef CUSTOM_SPLIT_TRANSPORT_SYNC
-# define SPLIT_TRANSACTION_IDS_USER RPC_ID_USER_STATE_SYNC, RPC_ID_USER_KEYMAP_SYNC, RPC_ID_USER_CONFIG_SYNC
+# define SPLIT_TRANSACTION_IDS_USER RPC_ID_USER_STATE_SYNC, RPC_ID_USER_KEYMAP_SYNC, RPC_ID_USER_CONFIG_SYNC, RPC_ID_USER_WATCHDOG_SYNC, RPC_ID_USER_KEYLOG_STR
# endif
#endif
+#if defined(WPM_ENABLE)
+// # define WPM_LAUNCH_CONTROL
+// # define WPM_ALLOW_COUNT_REGRESSOIN
+// # define WPM_UNFILTERED
+# define WPM_SAMPLE_SECONDS 6
+# define WPM_SAMPLE_PERIODS 50
+# define WPM_ESTIMATED_WORD_SIZE 6
+#endif
+
#ifdef AUDIO_ENABLE
# define AUDIO_CLICKY
# define AUDIO_CLICKY_FREQ_RANDOMNESS 1.5f
@@ -68,7 +69,7 @@
# endif
#endif // !AUDIO_ENABLE
-#define UNICODE_SELECTED_MODES UC_WIN, UC_MAC
+#define UNICODE_SELECTED_MODES UC_WINC, UC_MAC
#ifdef RGBLIGHT_ENABLE
# define RGBLIGHT_SLEEP
@@ -191,7 +192,7 @@
# ifdef OLED_FONT_H
# undef OLED_FONT_H
# endif
-# define OLED_FONT_H "drashna_font.h"
+# define OLED_FONT_H "oled/drashna_font.h"
# define OLED_FONT_END 255
// # define OLED_FONT_5X5
// # define OLED_FONT_AZTECH
@@ -242,17 +243,6 @@
# define TAPPING_TOGGLE 1
#endif
-#ifdef TAPPING_TERM
-# undef TAPPING_TERM
-#endif // TAPPING_TERM
-#if defined(KEYBOARD_ergodox_ez)
-# define TAPPING_TERM 185
-#elif defined(KEYBOARD_crkbd)
-# define TAPPING_TERM 200
-#else
-# define TAPPING_TERM 175
-#endif
-
#define TAP_CODE_DELAY 5
/* Disable unused and unneeded features to reduce on firmware size */
@@ -281,3 +271,24 @@
# define C14 PAL_LINE(GPIOC, 14)
# define C15 PAL_LINE(GPIOC, 15)
#endif
+
+#ifdef OLED_DRIVER_SH1107
+# define OLED_DISPLAY_CUSTOM
+# define OLED_IC_SH1107 2
+# define OLED_DISPLAY_128X128
+# define OLED_DISPLAY_WIDTH 128
+# define OLED_DISPLAY_HEIGHT 128
+# define OLED_MATRIX_SIZE (OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)
+# define OLED_BLOCK_TYPE uint32_t
+# define OLED_SOURCE_MAP \
+ { 0, 8, 16, 24, 32, 40, 48, 56 }
+# define OLED_TARGET_MAP \
+ { 56, 48, 40, 32, 24, 16, 8, 0 }
+# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)
+# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
+# define OLED_COM_PINS COM_PINS_ALT
+# define OLED_IC OLED_IC_SH1107
+# ifndef OLED_BRIGHTNESS
+# define OLED_BRIGHTNESS 50
+# endif
+#endif
diff --git a/users/drashna/drashna.c b/users/drashna/drashna.c
index 7e07a2c7c5..6e8d4ac9bd 100644
--- a/users/drashna/drashna.c
+++ b/users/drashna/drashna.c
@@ -1,39 +1,38 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#include "drashna.h"
+#ifdef __AVR__
+# include <avr/wdt.h>
+#endif
userspace_config_t userspace_config;
+/**
+ * @brief Handle registering a keycode, with optional modifer based on timed event
+ *
+ * @param code keycode to send to host
+ * @param mod_code modifier to send with code, if held for tapping term or longer
+ * @param pressed the press/release event (can use "record->event.pressed" for this)
+ * @return true exits function
+ * @return false exits function
+ */
bool mod_key_press_timer(uint16_t code, uint16_t mod_code, bool pressed) {
static uint16_t this_timer;
- if (pressed) {
- this_timer = timer_read();
- } else {
- if (timer_elapsed(this_timer) < TAPPING_TERM) {
- tap_code(code);
- } else {
- register_code(mod_code);
- tap_code(code);
- unregister_code(mod_code);
- }
- }
+ mod_key_press(code, mod_code, pressed, this_timer);
return false;
}
+/**
+ * @brief Handle registation of keycode, with optional modifier based on custom timer
+ *
+ * @param code keycode to send to host
+ * @param mod_code modifier keycode to send with code, if held for tapping term or longer
+ * @param pressed the press/release event
+ * @param this_timer custom timer to use
+ * @return true
+ * @return false
+ */
bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this_timer) {
if (pressed) {
this_timer = timer_read();
@@ -49,271 +48,77 @@ bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this
return false;
}
-__attribute__((weak)) void keyboard_pre_init_keymap(void) {}
-void keyboard_pre_init_user(void) {
- userspace_config.raw = eeconfig_read_user();
- keyboard_pre_init_keymap();
-}
-// Add reconfigurable functions here, for keymap customization
-// This allows for a global, userspace functions, and continued
-// customization of the keymap. Use _keymap instead of _user
-// functions in the keymaps
-// Call user matrix init, set default RGB colors and then
-// call the keymap's init function
-__attribute__((weak)) void matrix_init_keymap(void) {}
-__attribute__((weak)) void matrix_init_secret(void) {}
-void matrix_init_user(void) {
-#if defined(BOOTLOADER_CATERINA) && defined(__AVR__)
- DDRD &= ~(1 << 5);
- PORTD &= ~(1 << 5);
-
- DDRB &= ~(1 << 0);
- PORTB &= ~(1 << 0);
-#endif
+/**
+ * @brief Performs exact match for modifier values
+ *
+ * @param value the modifer varible (get_mods/get_oneshot_mods/get_weak_mods)
+ * @param mask the modifier mask to check for
+ * @return true Has the exact modifiers specifed
+ * @return false Does not have the exact modifiers specified
+ */
+bool hasAllBitsInMask(uint8_t value, uint8_t mask) {
+ value &= 0xF;
+ mask &= 0xF;
- matrix_init_secret();
- matrix_init_keymap();
+ return (value & mask) == mask;
}
-__attribute__((weak)) void keyboard_post_init_keymap(void) {}
-void keyboard_post_init_user(void) {
-#if defined(RGBLIGHT_ENABLE)
- keyboard_post_init_rgb_light();
-#endif
-#if defined(RGB_MATRIX_ENABLE)
- keyboard_post_init_rgb_matrix();
-#endif
-#if defined(SPLIT_KEYBOARD) && defined(SPLIT_TRANSACTION_IDS_USER)
- keyboard_post_init_transport_sync();
-#endif
- keyboard_post_init_keymap();
+/**
+ * @brief Tap keycode, with no mods
+ *
+ * @param kc keycode to use
+ */
+void tap_code16_nomods(uint16_t kc) {
+ uint8_t temp_mod = get_mods();
+ clear_mods();
+ clear_oneshot_mods();
+ tap_code16(kc);
+ set_mods(temp_mod);
}
-#ifdef RGB_MATRIX_ENABLE
-void rgb_matrix_update_pwm_buffers(void);
-#endif
+/**
+ * @brief Run shutdown routine and soft reboot firmware.
+ *
+ */
-__attribute__((weak)) void shutdown_keymap(void) {}
-void shutdown_user(void) {
-#ifdef RGBLIGHT_ENABLE
- rgblight_enable_noeeprom();
- rgblight_mode_noeeprom(1);
- rgblight_setrgb_red();
-#endif // RGBLIGHT_ENABLE
-#ifdef RGB_MATRIX_ENABLE
- rgb_matrix_set_color_all(0xFF, 0x00, 0x00);
- rgb_matrix_update_pwm_buffers();
-#endif // RGB_MATRIX_ENABLE
-#ifdef OLED_ENABLE
- oled_off();
+#ifdef HAPTIC_ENABLE
+# include "haptic.h"
#endif
- shutdown_keymap();
-}
-
-__attribute__((weak)) void suspend_power_down_keymap(void) {}
-
-void suspend_power_down_user(void) {
-#ifdef OLED_ENABLE
- oled_off();
+#ifdef AUDIO_ENABLE
+# ifndef GOODBYE_SONG
+# define GOODBYE_SONG SONG(GOODBYE_SOUND)
+# endif
+float reset_song[][2] = GOODBYE_SONG;
#endif
- suspend_power_down_keymap();
-}
-
-__attribute__((weak)) void suspend_wakeup_init_keymap(void) {}
-void suspend_wakeup_init_user(void) {
- if (layer_state_is(_GAMEPAD)) {
- layer_off(_GAMEPAD);
- }
- if (layer_state_is(_DIABLO)) {
- layer_off(_DIABLO);
- }
- suspend_wakeup_init_keymap();
-}
-
-// No global matrix scan code, so just run keymap's matrix
-// scan function
-__attribute__((weak)) void matrix_scan_keymap(void) {}
-__attribute__((weak)) void matrix_scan_secret(void) {}
-void matrix_scan_user(void) {
- static bool has_ran_yet;
- if (!has_ran_yet) {
- has_ran_yet = true;
- startup_user();
- }
-
-#ifdef TAP_DANCE_ENABLE // Run Diablo 3 macro checking code.
- run_diablo_macro_check();
-#endif // TAP_DANCE_ENABLE
-#if defined(RGBLIGHT_ENABLE)
- matrix_scan_rgb_light();
-#endif // RGBLIGHT_ENABLE
-#if defined(RGB_MATRIX_ENABLE)
- matrix_scan_rgb_matrix();
+void software_reset(void) {
+ clear_keyboard();
+#if defined(MIDI_ENABLE) && defined(MIDI_BASIC)
+ process_midi_all_notes_off();
#endif
-
- matrix_scan_secret();
-
- matrix_scan_keymap();
-}
-
#ifdef AUDIO_ENABLE
-float doom_song[][2] = SONG(E1M1_DOOM);
+# ifndef NO_MUSIC_MODE
+ music_all_notes_off();
+# endif
+ uint16_t timer_start = timer_read();
+ PLAY_SONG(reset_song);
+ shutdown_user();
+ while (timer_elapsed(timer_start) < 250) wait_ms(1);
+ stop_all_notes();
+#else
+ shutdown_user();
+ wait_ms(250);
#endif
-
-// on layer change, no matter where the change was initiated
-// Then runs keymap's layer change check
-__attribute__((weak)) layer_state_t layer_state_set_keymap(layer_state_t state) { return state; }
-layer_state_t layer_state_set_user(layer_state_t state) {
- if (!is_keyboard_master()) {
- return state;
- }
-
- state = update_tri_layer_state(state, _RAISE, _LOWER, _ADJUST);
-#if defined(RGBLIGHT_ENABLE)
- state = layer_state_set_rgb_light(state);
-#endif // RGBLIGHT_ENABLE
-#if defined(AUDIO_ENABLE) && !defined(__arm__)
- static bool is_gamepad_on = false;
- if (layer_state_cmp(state, _GAMEPAD) != is_gamepad_on) {
- is_gamepad_on = layer_state_cmp(state, _GAMEPAD);
- if (is_gamepad_on) {
- PLAY_LOOP(doom_song);
- } else {
- stop_all_notes();
- }
- }
+#ifdef HAPTIC_ENABLE
+ haptic_shutdown();
#endif
- state = layer_state_set_keymap(state);
- return state;
-}
-
-// Runs state check and changes underglow color and animation
-__attribute__((weak)) layer_state_t default_layer_state_set_keymap(layer_state_t state) { return state; }
-layer_state_t default_layer_state_set_user(layer_state_t state) {
- if (!is_keyboard_master()) {
- return state;
- }
-
- state = default_layer_state_set_keymap(state);
-#if 0
-# if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
- state = default_layer_state_set_rgb(state);
-# endif // RGBLIGHT_ENABLE
-#endif
- return state;
-}
-
-__attribute__((weak)) void led_set_keymap(uint8_t usb_led) {}
-void led_set_user(uint8_t usb_led) { led_set_keymap(usb_led); }
-
-__attribute__((weak)) void eeconfig_init_keymap(void) {}
-void eeconfig_init_user(void) {
- userspace_config.raw = 0;
- userspace_config.rgb_layer_change = true;
- eeconfig_update_user(userspace_config.raw);
- eeconfig_init_keymap();
- keyboard_init();
-}
-
-bool hasAllBitsInMask(uint8_t value, uint8_t mask) {
- value &= 0xF;
- mask &= 0xF;
-
- return (value & mask) == mask;
-}
-#ifdef SPLIT_KEYBOARD
-__attribute__((weak)) void matrix_slave_scan_keymap(void) {}
-void matrix_slave_scan_user(void) {
-# if defined(AUDIO_ENABLE)
-# if !defined(NO_MUSIC_MODE)
- music_task();
-# endif
-# ifdef AUDIO_INIT_DELAY
- if (!is_keyboard_master()) {
- static bool delayed_tasks_run = false;
- static uint16_t delayed_task_timer = 0;
- if (!delayed_tasks_run) {
- if (!delayed_task_timer) {
- delayed_task_timer = timer_read();
- } else if (timer_elapsed(delayed_task_timer) > 300) {
- audio_startup();
- delayed_tasks_run = true;
- }
- }
- }
-# endif
-# endif
-# ifdef SEQUENCER_ENABLE
- sequencer_task();
+#if defined(PROTOCOL_LUFA)
+ wdt_enable(WDTO_250MS);
+#elif defined(PROTOCOL_CHIBIOS)
+# if defined(MCU_STM32) || defined(MCU_KINETIS)
+ NVIC_SystemReset();
# endif
-# ifdef LED_MATRIX_ENABLE
- led_matrix_task();
-# endif
-# ifdef HAPTIC_ENABLE
- haptic_task();
-# endif
-
- matrix_slave_scan_keymap();
-}
#endif
-
-__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
- switch (keycode) {
- default:
- return TAPPING_TERM;
- }
-}
-
-__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
- // Immediately select the hold action when another key is tapped:
- // return true;
- // Do not select the hold action when another key is tapped.
- // return false;
- switch (keycode) {
- default:
- return false;
- }
-}
-
-__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
- // Immediately select the hold action when another key is pressed.
- // return true;
- // Do not select the hold action when another key is pressed.
- // return false;
- switch (keycode) {
- case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
- return true;
- default:
- return false;
- }
-}
-
-__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) {
- // Do not force the mod-tap key press to be handled as a modifier
- // if any other key was pressed while the mod-tap key is held down.
- // return true;
- // Force the mod-tap key press to be handled as a modifier if any
- // other key was pressed while the mod-tap key is held down.
- // return false;
- switch (keycode) {
- default:
- return true;
- }
-}
-
-__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) {
- switch (keycode) {
- default:
- return false;
- }
-}
-
-__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) {
- switch (keycode) {
- default:
- return false;
- }
}
diff --git a/users/drashna/drashna.h b/users/drashna/drashna.h
index 6a45141d9a..0bf1de84cf 100644
--- a/users/drashna/drashna.h
+++ b/users/drashna/drashna.h
@@ -1,42 +1,31 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include QMK_KEYBOARD_H
#include "eeprom.h"
-#include "wrappers.h"
-#include "process_records.h"
+#include "keyrecords/wrappers.h"
+#include "keyrecords/process_records.h"
+#include "callbacks.h"
+
#ifdef TAP_DANCE_ENABLE
-# include "tap_dances.h"
+# include "keyrecords/tap_dances.h"
#endif // TAP_DANCE_ENABLE
#if defined(RGBLIGHT_ENABLE)
-# include "rgb_stuff.h"
+# include "rgb/rgb_stuff.h"
#endif
#if defined(RGB_MATRIX_ENABLE)
-# include "rgb_matrix_stuff.h"
+# include "rgb/rgb_matrix_stuff.h"
#endif
#if defined(OLED_ENABLE)
-# include "oled_stuff.h"
-#endif
-#if defined(PIMORONI_TRACKBALL_ENABLE)
-# include "drivers/sensors/pimoroni_trackball.h"
+# include "oled/oled_stuff.h"
#endif
#ifdef SPLIT_KEYBOARD
-# include "transport_sync.h"
+# include "split/transport_sync.h"
+#endif
+#ifdef POINTING_DEVICE_ENABLE
+# include "pointing/pointing.h"
#endif
/* Define layer names */
@@ -58,7 +47,7 @@ enum userspace_layers {
_ADJUST,
};
-#define _MACROS _MOUSE
+#define _MACROS _MOUSE
#define _DEFAULT_LAYER_1 FIRST_DEFAULT_LAYER
#define _DEFAULT_LAYER_2 (FIRST_DEFAULT_LAYER + 1)
#define _DEFAULT_LAYER_3 (FIRST_DEFAULT_LAYER + 2)
@@ -86,23 +75,11 @@ enum userspace_layers {
#define DEFAULT_LAYER_3_RGB RGB_MAGENTA
#define DEFAULT_LAYER_4_RGB RGB_GOLDENROD
-bool mod_key_press_timer(uint16_t code, uint16_t mod_code, bool pressed);
-bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this_timer);
-void matrix_init_keymap(void);
-void matrix_init_secret(void);
-void shutdown_keymap(void);
-void suspend_power_down_keymap(void);
-void suspend_wakeup_init_keymap(void);
-void matrix_scan_keymap(void);
-void matrix_scan_secret(void);
-layer_state_t layer_state_set_keymap(layer_state_t state);
-layer_state_t default_layer_state_set_keymap(layer_state_t state);
-void led_set_keymap(uint8_t usb_led);
-void eeconfig_init_keymap(void);
-bool hasAllBitsInMask(uint8_t value, uint8_t mask);
-#ifdef SPLIT_KEYBOARD
-void matrix_slave_scan_keymap(void);
-#endif
+bool mod_key_press_timer(uint16_t code, uint16_t mod_code, bool pressed);
+bool mod_key_press(uint16_t code, uint16_t mod_code, bool pressed, uint16_t this_timer);
+bool hasAllBitsInMask(uint8_t value, uint8_t mask);
+void tap_code16_nomods(uint16_t kc);
+void software_reset(void);
// clang-format off
typedef union {
@@ -113,25 +90,9 @@ typedef union {
bool nuke_switch :1;
bool swapped_numbers :1;
bool rgb_matrix_idle_anim :1;
+ bool autocorrection :1;
};
} userspace_config_t;
// clang-format on
extern userspace_config_t userspace_config;
-
-/*
-Custom Keycodes for Diablo 3 layer
-But since TD() doesn't work when tap dance is disabled
-We use custom codes here, so we can substitute the right stuff
-*/
-#ifdef TAP_DANCE_ENABLE
-# define KC_D3_1 TD(TD_D3_1)
-# define KC_D3_2 TD(TD_D3_2)
-# define KC_D3_3 TD(TD_D3_3)
-# define KC_D3_4 TD(TD_D3_4)
-#else // TAP_DANCE_ENABLE
-# define KC_D3_1 KC_1
-# define KC_D3_2 KC_2
-# define KC_D3_3 KC_3
-# define KC_D3_4 KC_4
-#endif // TAP_DANCE_ENABLE
diff --git a/users/drashna/keyrecords/autocorrection/autocorrection.c b/users/drashna/keyrecords/autocorrection/autocorrection.c
new file mode 100644
index 0000000000..c7e938a341
--- /dev/null
+++ b/users/drashna/keyrecords/autocorrection/autocorrection.c
@@ -0,0 +1,170 @@
+// Copyright 2021 Google LLC
+// Copyright 2021 @filterpaper
+// SPDX-License-Identifier: Apache-2.0
+// Original source: https://getreuer.info/posts/keyboards/autocorrection
+
+#include "autocorrection.h"
+#include <string.h>
+
+#if __has_include("autocorrection_data.h")
+# pragma GCC push_options
+# pragma GCC optimize("O0")
+# include "autocorrection_data.h"
+# if AUTOCORRECTION_MIN_LENGTH < 4
+# error Minimum Length is too short and may cause overflows
+# endif
+# if DICTIONARY_SIZE > SIZE_MAX
+# error Dictionary size excees maximum size permitted
+# endif
+
+/**
+ * @brief Process handler for autocorrect feature
+ *
+ * @param keycode Keycode registered by matrix press, per keymap
+ * @param record keyrecord_t structure
+ * @return true Continue processing keycodes, and send to host
+ * @return false Stop processing keycodes, and don't send to host
+ */
+bool process_autocorrection(uint16_t keycode, keyrecord_t* record) {
+ static uint8_t typo_buffer[AUTOCORRECTION_MAX_LENGTH] = {KC_SPC};
+ static uint8_t typo_buffer_size = 1;
+
+ if (keycode == AUTO_CTN) {
+ if (record->event.pressed) {
+ typo_buffer_size = 0;
+ userspace_config.autocorrection ^= 1;
+ eeconfig_update_user(userspace_config.raw);
+ }
+ return false;
+ }
+
+ if (!userspace_config.autocorrection) {
+ typo_buffer_size = 0;
+ return true;
+ }
+
+ switch (keycode) {
+ case KC_LSFT:
+ case KC_RSFT:
+ return true;
+# ifndef NO_ACTION_TAPPING
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ if (((keycode >> 8) & 0xF) == MOD_LSFT) {
+ return true;
+ }
+# ifndef NO_ACTION_LAYER
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+# endif
+ if (record->event.pressed || !record->tap.count) {
+ return true;
+ }
+ keycode &= 0xFF;
+ break;
+# endif
+# ifdef SWAP_HANDS_ENABLE
+ case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
+ if (keycode >= 0x56F0 || record->event.pressed || !record->tap.count) {
+ return true;
+ }
+ keycode &= 0xFF;
+ break;
+# endif
+# ifndef NO_ACTION_ONESHOT
+ case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:
+ if ((keycode & 0xF) == MOD_LSFT) {
+ return true;
+ }
+# endif
+ default:
+ // Disable autocorrection while a mod other than shift is active.
+ if (((get_mods() | get_oneshot_mods()) & ~MOD_MASK_SHIFT) != 0) {
+ typo_buffer_size = 0;
+ return true;
+ }
+ if (!record->event.pressed) {
+ return true;
+ }
+ }
+
+ // Subtract buffer for Backspace key, reset for other non-alpha.
+ if (!(KC_A <= keycode && keycode <= KC_Z)) {
+ if (keycode == KC_BSPC) {
+ // Remove last character from the buffer.
+ if (typo_buffer_size > 0) {
+ --typo_buffer_size;
+ }
+ return true;
+ } else if (KC_1 <= keycode && keycode <= KC_SLSH && keycode != KC_ESC) {
+ // Set a word boundary if space, period, digit, etc. is pressed.
+ // Behave more conservatively for the enter key. Reset, so that enter
+ // can't be used on a word ending.
+ if (keycode == KC_ENT || (keycode == KC_MINUS && (get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT)) {
+ typo_buffer_size = 0;
+ }
+ keycode = KC_SPC;
+ } else {
+ // Clear state if some other non-alpha key is pressed.
+ typo_buffer_size = 0;
+ return true;
+ }
+ }
+
+ // Rotate oldest character if buffer is full.
+ if (typo_buffer_size >= AUTOCORRECTION_MAX_LENGTH) {
+ memmove(typo_buffer, typo_buffer + 1, AUTOCORRECTION_MAX_LENGTH - 1);
+ typo_buffer_size = AUTOCORRECTION_MAX_LENGTH - 1;
+ }
+
+ // Append `keycode` to buffer.
+ typo_buffer[typo_buffer_size++] = keycode;
+ // Return if buffer is smaller than the shortest word.
+ if (typo_buffer_size < AUTOCORRECTION_MIN_LENGTH) {
+ return true;
+ }
+
+ // Check for typo in buffer using a trie stored in `autocorrection_data`.
+ uint16_t state = 0;
+ uint8_t code = pgm_read_byte(autocorrection_data + state);
+ for (uint8_t i = typo_buffer_size - 1; i >= 0; --i) {
+ uint8_t const key_i = typo_buffer[i];
+
+ if (code & 64) { // Check for match in node with multiple children.
+ code &= 63;
+ for (; code != key_i; code = pgm_read_byte(autocorrection_data + (state += 3))) {
+ if (!code) return true;
+ }
+ // Follow link to child node.
+ state = (pgm_read_byte(autocorrection_data + state + 1) | pgm_read_byte(autocorrection_data + state + 2) << 8);
+ // Check for match in node with single child.
+ } else if (code != key_i) {
+ return true;
+ } else if (!(code = pgm_read_byte(autocorrection_data + (++state)))) {
+ ++state;
+ }
+
+ code = pgm_read_byte(autocorrection_data + state);
+
+ if (code & 128) { // A typo was found! Apply autocorrection.
+ const uint8_t backspaces = code & 63;
+ for (uint8_t i = 0; i < backspaces; ++i) {
+ tap_code(KC_BSPC);
+ }
+ send_string_P((char const*)(autocorrection_data + state + 1));
+
+ if (keycode == KC_SPC) {
+ typo_buffer[0] = KC_SPC;
+ typo_buffer_size = 1;
+ return true;
+ } else {
+ typo_buffer_size = 0;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+# pragma GCC pop_options
+#else
+# pragma message "Warning!!! Autocorrect is not corretly setup!"
+bool process_autocorrection(uint16_t keycode, keyrecord_t* record) { return true; }
+#endif
diff --git a/users/drashna/keyrecords/autocorrection/autocorrection.h b/users/drashna/keyrecords/autocorrection/autocorrection.h
new file mode 100644
index 0000000000..cea93159ae
--- /dev/null
+++ b/users/drashna/keyrecords/autocorrection/autocorrection.h
@@ -0,0 +1,10 @@
+// Copyright 2021 Google LLC
+// Copyright 2021 @filterpaper
+// SPDX-License-Identifier: Apache-2.0
+// Original source: https://getreuer.info/posts/keyboards/autocorrection
+
+#pragma once
+
+#include "drashna.h"
+
+bool process_autocorrection(uint16_t keycode, keyrecord_t* record);
diff --git a/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py b/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py
new file mode 100755
index 0000000000..54fd9ba594
--- /dev/null
+++ b/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py
@@ -0,0 +1,274 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Python program to make autocorrection_data.h.
+
+This program reads "autocorrection_dict.txt" and generates a C source file
+"autocorrection_data.h" with a serialized trie embedded as an array. Run this
+program without arguments like
+
+$ python3 make_autocorrection_data.py
+
+Or to read from a different typo dict file, pass it as the first argument like
+
+$ python3 make_autocorrection_data.py dict.txt
+
+Each line of the dict file defines one typo and its correction with the syntax
+"typo -> correction". Blank lines or lines starting with '#' are ignored.
+Example:
+
+ :thier -> their
+ fitler -> filter
+ lenght -> length
+ ouput -> output
+ widht -> width
+
+See autocorrection_dict_extra.txt for a larger example.
+
+For full documentation, see
+https://getreuer.info/posts/keyboards/autocorrection
+"""
+
+import sys
+import textwrap
+from typing import Any, Dict, List, Tuple
+
+try:
+ from english_words import english_words_lower_alpha_set as CORRECT_WORDS
+except ImportError:
+ print('Autocorrection will falsely trigger when a typo is a substring of a '
+ 'correctly spelled word. To check for this, install the english_words '
+ 'package and rerun this script:\n\n pip install english_words\n')
+ # Use a minimal word list as a fallback.
+ CORRECT_WORDS = ('information', 'available', 'international', 'language',
+ 'loosest', 'reference', 'wealthier', 'entertainment',
+ 'association', 'provides', 'technology', 'statehood')
+
+KC_A = 4
+KC_SPC = 0x2c
+
+def parse_file(file_name: str) -> List[Tuple[str, str]]:
+ """Parses autocorrections dictionary file.
+
+ Each line of the file defines one typo and its correction with the syntax
+ "typo -> correction". Blank lines or lines starting with '#' are ignored. The
+ function validates that typos only have characters a-z and that typos are not
+ substrings of other typos, otherwise the longer typo would never trigger.
+
+ Args:
+ file_name: String, path of the autocorrections dictionary.
+ Returns:
+ List of (typo, correction) tuples.
+ """
+
+ autocorrections = []
+ typos = set()
+ line_number = 0
+ for line in open(file_name, 'rt'):
+ line_number += 1
+ line = line.strip()
+ if line and line[0] != '#':
+ # Parse syntax "typo -> correction", using strip to ignore indenting.
+ tokens = [token.strip() for token in line.split('->', 1)]
+ if len(tokens) != 2 or not tokens[0]:
+ print(f'Error:{line_number}: Invalid syntax: "{line}"')
+ sys.exit(1)
+
+ typo, correction = tokens
+ typo = typo.lower() # Force typos to lowercase.
+ typo = typo.replace(' ', ':')
+
+ if typo in typos:
+ print(f'Warning:{line_number}: Ignoring duplicate typo: "{typo}"')
+ continue
+
+ # Check that `typo` is valid.
+ if not(all([ord('a') <= ord(c) <= ord('z') or c == ':' for c in typo])):
+ print(f'Error:{line_number}: Typo "{typo}" has '
+ 'characters other than a-z and :.')
+ sys.exit(1)
+ for other_typo in typos:
+ if typo in other_typo or other_typo in typo:
+ print(f'Error:{line_number}: Typos may not be substrings of one '
+ f'another, otherwise the longer typo would never trigger: '
+ f'"{typo}" vs. "{other_typo}".')
+ sys.exit(1)
+ if len(typo) < 5:
+ print(f'Warning:{line_number}: It is suggested that typos are at '
+ f'least 5 characters long to avoid false triggers: "{typo}"')
+
+ if typo.startswith(':') and typo.endswith(':'):
+ if typo[1:-1] in CORRECT_WORDS:
+ print(f'Warning:{line_number}: Typo "{typo}" is a correctly spelled '
+ 'dictionary word.')
+ elif typo.startswith(':') and not typo.endswith(':'):
+ for word in CORRECT_WORDS:
+ if word.startswith(typo[1:]):
+ print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger '
+ f'on correctly spelled word "{word}".')
+ elif not typo.startswith(':') and typo.endswith(':'):
+ for word in CORRECT_WORDS:
+ if word.endswith(typo[:-1]):
+ print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger '
+ f'on correctly spelled word "{word}".')
+ elif not typo.startswith(':') and not typo.endswith(':'):
+ for word in CORRECT_WORDS:
+ if typo in word:
+ print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger '
+ f'on correctly spelled word "{word}".')
+
+ autocorrections.append((typo, correction))
+ typos.add(typo)
+
+ return autocorrections
+
+
+def make_trie(autocorrections: List[Tuple[str, str]]) -> Dict[str, Any]:
+ """Makes a trie from the the typos, writing in reverse.
+
+ Args:
+ autocorrections: List of (typo, correction) tuples.
+ Returns:
+ Dict of dict, representing the trie.
+ """
+ trie = {}
+ for typo, correction in autocorrections:
+ node = trie
+ for letter in typo[::-1]:
+ node = node.setdefault(letter, {})
+ node['LEAF'] = (typo, correction)
+
+ return trie
+
+
+def serialize_trie(autocorrections: List[Tuple[str, str]],
+ trie: Dict[str, Any]) -> List[int]:
+ """Serializes trie and correction data in a form readable by the C code.
+
+ Args:
+ autocorrections: List of (typo, correction) tuples.
+ trie: Dict of dicts.
+ Returns:
+ List of ints in the range 0-255.
+ """
+ table = []
+
+ # Traverse trie in depth first order.
+ def traverse(trie_node):
+ if 'LEAF' in trie_node: # Handle a leaf trie node.
+ typo, correction = trie_node['LEAF']
+ word_boundary_ending = typo[-1] == ':'
+ typo = typo.strip(':')
+ i = 0 # Make the autocorrection data for this entry and serialize it.
+ while i < min(len(typo), len(correction)) and typo[i] == correction[i]:
+ i += 1
+ backspaces = len(typo) - i - 1 + word_boundary_ending
+ assert 0 <= backspaces <= 63
+ correction = correction[i:]
+ data = [backspaces + 128] + list(bytes(correction, 'ascii')) + [0]
+
+ entry = {'data': data, 'links': [], 'byte_offset': 0}
+ table.append(entry)
+ elif len(trie_node) == 1: # Handle trie node with a single child.
+ c, trie_node = next(iter(trie_node.items()))
+ entry = {'chars': c, 'byte_offset': 0}
+
+ # It's common for a trie to have long chains of single-child nodes. We
+ # find the whole chain so that we can serialize it more efficiently.
+ while len(trie_node) == 1 and 'LEAF' not in trie_node:
+ c, trie_node = next(iter(trie_node.items()))
+ entry['chars'] += c
+
+ table.append(entry)
+ entry['links'] = [traverse(trie_node)]
+ else: # Handle trie node with multiple children.
+ entry = {'chars': ''.join(sorted(trie_node.keys())), 'byte_offset': 0}
+ table.append(entry)
+ entry['links'] = [traverse(trie_node[c]) for c in entry['chars']]
+ return entry
+
+ traverse(trie)
+
+ def serialize(e):
+ def kc_code(c):
+ if ord('a') <= ord(c) <= ord('z'):
+ return ord(c) - ord('a') + KC_A
+ elif c == ':':
+ return KC_SPC
+ else:
+ raise ValueError(f'Invalid character: {c}')
+
+ encode_link = lambda link: [link['byte_offset'] & 255,
+ link['byte_offset'] >> 8]
+
+ if not e['links']: # Handle a leaf table entry.
+ return e['data']
+ elif len(e['links']) == 1: # Handle a chain table entry.
+ return list(map(kc_code, e['chars'])) + [0] #+ encode_link(e['links'][0]))
+ else: # Handle a branch table entry.
+ data = []
+ for c, link in zip(e['chars'], e['links']):
+ data += [kc_code(c) | (0 if data else 64)] + encode_link(link)
+ return data + [0]
+
+ byte_offset = 0
+ for e in table: # To encode links, first compute byte offset of each entry.
+ e['byte_offset'] = byte_offset
+ byte_offset += len(serialize(e))
+ assert 0 <= byte_offset <= 0xffff
+
+ return [b for e in table for b in serialize(e)] # Serialize final table.
+
+
+def write_generated_code(autocorrections: List[Tuple[str, str]],
+ data: List[int],
+ file_name: str) -> None:
+ """Writes autocorrection data as generated C code to `file_name`.
+
+ Args:
+ autocorrections: List of (typo, correction) tuples.
+ data: List of ints in 0-255, the serialized trie.
+ file_name: String, path of the output C file.
+ """
+ assert all(0 <= b <= 255 for b in data)
+ typo_len = lambda e: len(e[0])
+ min_typo = min(autocorrections, key=typo_len)[0]
+ max_typo = max(autocorrections, key=typo_len)[0]
+ generated_code = ''.join([
+ '// Generated code.\n\n',
+ f'// Autocorrection dictionary ({len(autocorrections)} entries):\n',
+ ''.join(sorted(f'// {typo:<{len(max_typo)}} -> {correction}\n'
+ for typo, correction in autocorrections)),
+ f'\n#define AUTOCORRECTION_MIN_LENGTH {len(min_typo)} // "{min_typo}"\n',
+ f'#define AUTOCORRECTION_MAX_LENGTH {len(max_typo)} // "{max_typo}"\n\n',
+ f'#define DICTIONARY_SIZE {len(data)}\n\n',
+ textwrap.fill('static const uint8_t autocorrection_data[DICTIONARY_SIZE] PROGMEM = {%s};' % (
+ ', '.join(map(str, data))), width=120, subsequent_indent=' '),
+ '\n\n'])
+
+ with open(file_name, 'wt') as f:
+ f.write(generated_code)
+
+
+def main(argv):
+ dict_file = argv[1] if len(argv) > 1 else 'autocorrection_dict.txt'
+ autocorrections = parse_file(dict_file)
+ trie = make_trie(autocorrections)
+ data = serialize_trie(autocorrections, trie)
+ print(f'Processed %d autocorrection entries to table with %d bytes.'
+ % (len(autocorrections), len(data)))
+ write_generated_code(autocorrections, data, 'autocorrection_data.h')
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/users/drashna/keyrecords/autocorrection/readme.md b/users/drashna/keyrecords/autocorrection/readme.md
new file mode 100644
index 0000000000..d920508793
--- /dev/null
+++ b/users/drashna/keyrecords/autocorrection/readme.md
@@ -0,0 +1,301 @@
+# Autocorrection
+
+This is taken from [Pascal Getreuer's implemenation](https://getreuer.info/posts/keyboards/autocorrection/index.html), with a number of modifications.
+
+To enabled Autocorrection, add `AUTOCORRECTION_ENABLE = yes` to your `rules.mk` file.
+
+This is mostly a reproduction of Pascal's docs:
+
+## Overview
+Some words are more prone to typos than others. I have a habit of typo-ing *ouput* and *fitler*. This post describes a rudimentary autocorrection implementation that runs on your keyboard with QMK.
+
+The animation below shows the effect as I type *aparent*. As I press the final t, the autocorrection feature detects the typo and automatically sends keys to correct it:
+
+Example: Autocorrecting *aparent* → apparent.
+
+**Features**:
+* It runs on your keyboard, so it is always active no matter what software.
+* Low resource cost: for an autocorrection dictionary of 70 entries, firmware size cost is 1620 bytes and average CPU cost per key press is about 20 µs.
+* It is case insensitive. It corrects Fitler to Filter and FITLER to FILTER.
+* It works within words. It corrects fitlered, fitlering, and useful for programming, within longer identifiers like DesignButterworthFitle*r.
+
+**Limitations**: Running autocorrection on the keyboard comes with some constraints. It is rudimentary like I said:
+* It is limited to alphabet characters a–z. No accented or Unicode letters; I’m sorry this probably isn’t useful for languages besides English.
+* It does not follow mouse or hotkey driven cursor movement.
+
+## Taking autocorrection for a test drive
+With the above flashed to your keyboard, try for instance typing the misspelled word ouput. The instant you type the final t, the word should be speedily autocorrected to output. As further tests, try becuase and invliad.
+
+Here is the full list of typos corrected using the provided autocorrection_data.h file. : is a special character denoting a word break. See below for how to change the autocorrection dictionary.
+
+```
+:guage -> gauge
+:the:the: -> the
+:thier -> their
+:ture -> true
+accomodate -> accommodate
+acommodate -> accommodate
+aparent -> apparent
+aparrent -> apparent
+apparant -> apparent
+apparrent -> apparent
+aquire -> acquire
+becuase -> because
+cauhgt -> caught
+cheif -> chief
+choosen -> chosen
+cieling -> ceiling
+collegue -> colleague
+concensus -> consensus
+contians -> contains
+cosnt -> const
+dervied -> derived
+fales -> false
+fasle -> false
+fitler -> filter
+flase -> false
+foward -> forward
+frequecy -> frequency
+gaurantee -> guarantee
+guaratee -> guarantee
+heigth -> height
+heirarchy -> hierarchy
+inclued -> include
+interator -> iterator
+intput -> input
+invliad -> invalid
+lenght -> length
+liasion -> liaison
+libary -> library
+listner -> listener
+looses: -> loses
+looup -> lookup
+manefist -> manifest
+namesapce -> namespace
+namespcae -> namespace
+occassion -> occasion
+occured -> occurred
+ouptut -> output
+ouput -> output
+overide -> override
+postion -> position
+priviledge -> privilege
+psuedo -> pseudo
+recieve -> receive
+refered -> referred
+relevent -> relevant
+repitition -> repetition
+reuslt -> result
+retrun -> return
+retun -> return
+reutrn -> return
+saftey -> safety
+seperate -> separate
+singed -> signed
+stirng -> string
+strign -> string
+swithc -> switch
+swtich -> switch
+thresold -> threshold
+udpate -> update
+widht -> width
+```
+
+## Firmware size and CPU costs
+I am anxiously aware that a keyboard microcontroller has limited resources. So I was sure to measure how much memory and CPU time autocorrection consumes during development. These measurements are for the example autocorrection dictionary as used above, which has 70 entries:
+* **Firmware size**: Autocorrection increases my firmware size by a total of 1620 bytes. Breaking that down, 1104 bytes are for the autocorrection_data array and 516 bytes for the autocorrection code.
+* **CPU time**: On my Elite-C microcontrollers, the average CPU time for process_autocorrection to process an alpha key press is around 20 µs. Consider this a rough order-of-magnitude cost. Processing cost increases (more trie nodes are visited) when recent input is close to a known typo, with the max being when a long typo is matched.
+
+The costs are not free but reasonable. For reference, the firmware size cost for mouse keys is 2124 bytes and the CPU time to process a layer switch is about 70 µs, so autocorrection is cheaper than those things. Of course, the cost scales with the size of the autocorrection dictionary, so keep that in mind if you add a lot more entries.
+
+## How does it work?
+The function process_autocorrection maintains a small buffer of recent key presses. On each key press, it checks whether the buffer ends in a recognized typo, and if so, automatically sends keystrokes to correct it.
+
+The tricky part is how to efficiently check the buffer for typos. We don’t want to spend too much memory or time on storing or searching the typos. A good solution is to represent the typos with a trie data structure. A trie is a tree data structure where each node is a letter, and words are formed by following a path to one of the leaves.
+
+
+An example trie.
+Since we search whether the buffer ends in a typo, we store the trie writing in reverse. The trie is queried starting from the last letter, then second to last letter, and so on, until either a letter doesn’t match or we reach a leaf, meaning a typo was found.
+
+## Changing the autocorrection dictionary
+The file autocorrection_data.h encodes the typos to correct. While you could simply use the version of this file provided above for a practical configuration, you can make your own to personalize the autocorrection to your most troublesome typos:
+
+1. First, create an autocorrection dictionary autocorrection_dict.txt, like
+
+ ```
+:thier -> their
+fitler -> filter
+lenght -> length
+ouput -> output
+widht -> width
+```
+ For a practical 70-entry example, see autocorrection_dict.txt. And for a yet larger 400-entry example, see autocorrection_dict_extra.txt.
+
+ The syntax is `typo -> correction`. Typos and corrections are case insensitive, and any whitespace before or after the typo and correction is ignored. The typo must be only the letters a–z, or the special character : representing a word break. The correction may have any characters.
+
+2. Use the make_autocorrection_data.py Python script to process the dictionary
+
+```
+$ python3 make_autocorrection_data.py
+Processed 70 autocorrection entries to table with 1104 bytes.
+```
+The script arranges the entries in autocorrection_dict.txt into a trie and generates autocorrection_data.h with the serialized trie embedded as an array.
+
+3. Finally, recompile and flash your keymap.
+
+The generated C header looks like this:
+
+autocorrection_data.h
+```c
+// Generated code.
+
+#define AUTOCORRECTION_MIN_LENGTH 5 // "cheif"
+#define AUTOCORRECTION_MAX_LENGTH 10 // "accomodate"
+
+static const uint8_t autocorrection_data[1104] PROGMEM = {108, 43, 0, 6,
+ 71, 0, 7, 81, 0, 8, 199, 0, 9, 240, 1, 10, 250, 1, 11, 26, 2, 17, 53, 2,
+ 18, 190, 2, 19, 202, 2, 21, 212, 2, 22, 20, 3, 23, 67, 3, 28, 16, 4, 0,
+ 72, 50, 0, 22, 60, 0, 0, 11, 23, 44, 8, 11, 23, 44, 0, 132, 0, 8, 22, 18,
+ 18, 15, 0, 132, 115, 101, 115, 0, 11, 23, 12, 26, 22, 0, 129, 99, 104, 0,
+ 68, 94, 0, 8, 106, 0, 15, 174, 0, 21, 187, 0, 0, 12, 15, 25, 17, 12, 0,
+ 131, 97, 108, 105, 100, 0, 74, 119, 0, 12, 129, 0, 21, 140, 0, 24, 165,
+ 0, 0, 17, 12, 22, 0, 131, 103, 110, 101, 100, 0, 25, 21, 8, 7, 0, 131,
+ 105, 118, 101, 100, 0, 72, 147, 0, 24, 156, 0, 0, 9, 8, 21, 0, 129, 114,
+ 101, 100, 0, 6, 6, 18, 0, 129, 114, 101, 100, 0, 15, 6, 17, 12, 0, 129,
+ 100, 101, 0, 18, 22, 8, 21, 11, 23, 0, 130, 104, 111, 108, 100, 0, 4, 26,
+ 18, 9, 0, 131, 114, 119, 97, 114, 100, 0, 68, 233, 0, 6, 246, 0, 7, 4, 1,
+ 8, 16, 1, 10, 52, 1, 15, 81, 1, 21, 90, 1, 22, 117, 1, 23, 144, 1, 24,
+ 215, 1, 25, 228, 1, 0, 6, 19, 22, 8, 16, 4, 17, 0, 130, 97, 99, 101, 0,
+ 19, 4, 22, 8, 16, 4, 17, 0, 131, 112, 97, 99, 101, 0, 12, 21, 8, 25, 18,
+ 0, 130, 114, 105, 100, 101, 0, 23, 0, 68, 25, 1, 17, 36, 1, 0, 21, 4, 24,
+ 10, 0, 130, 110, 116, 101, 101, 0, 4, 21, 24, 4, 10, 0, 135, 117, 97,
+ 114, 97, 110, 116, 101, 101, 0, 68, 59, 1, 7, 69, 1, 0, 24, 10, 44, 0,
+ 131, 97, 117, 103, 101, 0, 8, 15, 12, 25, 12, 21, 19, 0, 130, 103, 101,
+ 0, 22, 4, 9, 0, 130, 108, 115, 101, 0, 76, 97, 1, 24, 109, 1, 0, 24, 20,
+ 4, 0, 132, 99, 113, 117, 105, 114, 101, 0, 23, 44, 0, 130, 114, 117, 101,
+ 0, 4, 0, 79, 126, 1, 24, 134, 1, 0, 9, 0, 131, 97, 108, 115, 101, 0, 6,
+ 8, 5, 0, 131, 97, 117, 115, 101, 0, 4, 0, 71, 156, 1, 19, 193, 1, 21,
+ 203, 1, 0, 18, 16, 0, 80, 166, 1, 18, 181, 1, 0, 18, 6, 4, 0, 135, 99,
+ 111, 109, 109, 111, 100, 97, 116, 101, 0, 6, 6, 4, 0, 132, 109, 111, 100,
+ 97, 116, 101, 0, 7, 24, 0, 132, 112, 100, 97, 116, 101, 0, 8, 19, 8, 22,
+ 0, 132, 97, 114, 97, 116, 101, 0, 10, 8, 15, 15, 18, 6, 0, 130, 97, 103,
+ 117, 101, 0, 8, 12, 6, 8, 21, 0, 131, 101, 105, 118, 101, 0, 12, 8, 11,
+ 6, 0, 130, 105, 101, 102, 0, 17, 0, 76, 3, 2, 21, 16, 2, 0, 15, 8, 12, 6,
+ 0, 133, 101, 105, 108, 105, 110, 103, 0, 12, 23, 22, 0, 131, 114, 105,
+ 110, 103, 0, 70, 33, 2, 23, 44, 2, 0, 12, 23, 26, 22, 0, 131, 105, 116,
+ 99, 104, 0, 10, 12, 8, 11, 0, 129, 104, 116, 0, 72, 69, 2, 10, 80, 2, 18,
+ 89, 2, 21, 156, 2, 24, 167, 2, 0, 22, 18, 18, 11, 6, 0, 131, 115, 101,
+ 110, 0, 12, 21, 23, 22, 0, 129, 110, 103, 0, 12, 0, 86, 98, 2, 23, 124,
+ 2, 0, 68, 105, 2, 22, 114, 2, 0, 12, 15, 0, 131, 105, 115, 111, 110, 0,
+ 4, 6, 6, 18, 0, 131, 105, 111, 110, 0, 76, 131, 2, 22, 146, 2, 0, 23, 12,
+ 19, 8, 21, 0, 134, 101, 116, 105, 116, 105, 111, 110, 0, 18, 19, 0, 131,
+ 105, 116, 105, 111, 110, 0, 23, 24, 8, 21, 0, 131, 116, 117, 114, 110, 0,
+ 85, 174, 2, 23, 183, 2, 0, 23, 8, 21, 0, 130, 117, 114, 110, 0, 8, 21, 0,
+ 128, 114, 110, 0, 7, 8, 24, 22, 19, 0, 131, 101, 117, 100, 111, 0, 24,
+ 18, 18, 15, 0, 129, 107, 117, 112, 0, 72, 219, 2, 18, 3, 3, 0, 76, 229,
+ 2, 15, 238, 2, 17, 248, 2, 0, 11, 23, 44, 0, 130, 101, 105, 114, 0, 23,
+ 12, 9, 0, 131, 108, 116, 101, 114, 0, 23, 22, 12, 15, 0, 130, 101, 110,
+ 101, 114, 0, 23, 4, 21, 8, 23, 17, 12, 0, 135, 116, 101, 114, 97, 116,
+ 111, 114, 0, 72, 30, 3, 17, 38, 3, 24, 51, 3, 0, 15, 4, 9, 0, 129, 115,
+ 101, 0, 4, 12, 23, 17, 18, 6, 0, 131, 97, 105, 110, 115, 0, 22, 17, 8, 6,
+ 17, 18, 6, 0, 133, 115, 101, 110, 115, 117, 115, 0, 74, 86, 3, 11, 96, 3,
+ 15, 118, 3, 17, 129, 3, 22, 218, 3, 24, 232, 3, 0, 11, 24, 4, 6, 0, 130,
+ 103, 104, 116, 0, 71, 103, 3, 10, 110, 3, 0, 12, 26, 0, 129, 116, 104, 0,
+ 17, 8, 15, 0, 129, 116, 104, 0, 22, 24, 8, 21, 0, 131, 115, 117, 108,
+ 116, 0, 68, 139, 3, 8, 150, 3, 22, 210, 3, 0, 21, 4, 19, 19, 4, 0, 130,
+ 101, 110, 116, 0, 85, 157, 3, 25, 200, 3, 0, 68, 164, 3, 21, 175, 3, 0,
+ 19, 4, 0, 132, 112, 97, 114, 101, 110, 116, 0, 4, 19, 0, 68, 185, 3, 19,
+ 193, 3, 0, 133, 112, 97, 114, 101, 110, 116, 0, 4, 0, 131, 101, 110, 116,
+ 0, 8, 15, 8, 21, 0, 130, 97, 110, 116, 0, 18, 6, 0, 130, 110, 115, 116,
+ 0, 12, 9, 8, 17, 4, 16, 0, 132, 105, 102, 101, 115, 116, 0, 83, 239, 3,
+ 23, 6, 4, 0, 87, 246, 3, 24, 254, 3, 0, 17, 12, 0, 131, 112, 117, 116, 0,
+ 18, 0, 130, 116, 112, 117, 116, 0, 19, 24, 18, 0, 131, 116, 112, 117,
+ 116, 0, 70, 29, 4, 8, 41, 4, 11, 51, 4, 21, 69, 4, 0, 8, 24, 20, 8, 21,
+ 9, 0, 129, 110, 99, 121, 0, 23, 9, 4, 22, 0, 130, 101, 116, 121, 0, 6,
+ 21, 4, 21, 12, 8, 11, 0, 135, 105, 101, 114, 97, 114, 99, 104, 121, 0, 4,
+ 5, 12, 15, 0, 130, 114, 97, 114, 121, 0};
+```
+
+## Troubleshooting
+### Avoiding false triggers
+By default, typos are searched within words, to find typos within longer identifiers like maxFitlerOuput. While this is useful, a consequence is that autocorrection will falsely trigger when a typo happens to be a substring of a correctly-spelled word. For instance, if we had thier -> their as an entry, it would falsely trigger on (correct, though relatively uncommon) words like “wealthier” and “filthier.”
+
+The solution is to set a word break : before and/or after the typo to constrain matching. : matches space, period, comma, underscore, digits, and most other non-alpha characters.
+
+| Text | thier | :thier | thier: | :thier: |
+|------|-------|--------|--------|---------|
+|see thier typo|matches|matches|matches|matches|
+it’s thiers |matches|matches|no|no|
+wealthier words|matches|no|matches|no|
+
+:thier: is most restrictive, matching only when thier is a whole word.
+
+The make_autocorrection_data.py script makes an effort to check for entries that would false trigger as substrings of correct words. It searches each typo against a dictionary of 25K English words from the english_words Python package, provided it’s installed.
+
+### Overriding autocorrection
+Occasionally you might actually want to type a typo (for instance, while editing autocorrection_dict.txt) without being autocorrected. Here is a way to do that:
+
+1. Begin typing the typo.
+2. Before typing the last letter, press and release the Ctrl or Alt key.
+3. Type the remaining letters.
+
+This works because the autocorrection implementation doesn’t understand hotkeys, so it resets itself whenever a modifier other than shift is held.
+
+Alternatively, the `AUTO_CTN` keycode will toggle autocorrection on and off.
+
+## Closing thoughts
+Based on my own use, an autocorrection dictionary of a few dozen entries is enough to help in day-to-day writing. On the other hand, it is of course far from comprehensively checking that every word is spelled correctly. Keyboard microcontrollers might not have the resources check against a full English dictionary any time soon, but a lot of editors and other software have good integrated spell check features.
+
+I suggest to enable and use spell check in combination with autocorrection:
+* Sublime: Open the View menu and enable “Spell Check.”
+* Eclipse: Open the Window menu, click Preferences, and search for “Spelling.”
+* Vim: Type :set spell, and misspellings will be highlighted. Use ]s to jump to the next misspelled word and z= to get suggested corrections for the word under the cursor. See the :help spell documentation. Vim also has an abbreviations feature that can autocorrect misspellings (see :help abbreviations).
+* Emacs: Use M-x flyspell-mode to enable Flyspell mode in the current buffer. Or for programming, use M-x flyspell-prog-mode to check comments and strings only. See the spelling documentation. There is also an abbreviations feature that can do autocorrection.
+
+Some useful resources:
+
+* Wikipedia has a [large list of common typos](https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines).
+* EmacsWiki has another [list of typos](https://www.emacswiki.org/emacs/autocorrection_abbrev_defs).
+* You can find data on English word frequencies at https://www.wordfrequency.info/samples.asp.
+
+# Appendix: Trie binary data format
+This section details how the trie is serialized to byte data in autocorrection_data. You don’t need to care about this to use this autocorrection implementation. But I document it for the record in case anyone is interested in modifying the implementation, or just curious how it works.
+
+What I did here is fairly arbitrary, but it is simple to decode and gets the job done.
+
+## Encoding
+All autocorrection data is stored in a single flat array autocorrection_data. Each trie node is associated with a byte offset into this array, where data for that node is encoded, beginning with root at offset 0. There are three kinds of nodes. The highest two bits of the first byte of the node indicate what kind:
+
+* 00 ⇒ chain node: a trie node with a single child.
+* 01 ⇒ branching node: a trie node with multiple children.
+* 10 ⇒ leaf node: a leaf, corresponding to a typo and storing its correction.
+
+An example trie.
+Branching node. Each branch is encoded with one byte for the keycode (KC_A–KC_Z) followed by a link to the child node. Links between nodes are 16-bit byte offsets relative to the beginning of the array, serialized in little endian order.
+
+All branches are serialized this way, one after another, and terminated with a zero byte. As described above, the node is identified as a branch by setting the two high bits of the first byte to 01, done by bitwise ORing the first keycode with 64. keycode. The root node for the above figure would be serialized like:
+
+ +-------+-------+-------+-------+-------+-------+-------+
+ | R|64 | node 2 | T | node 3 | 0 |
+ +-------+-------+-------+-------+-------+-------+-------+
+
+Chain node. Tries tend to have long chains of single-child nodes, as seen in the example above with f-i-t-l in fitler. So to save space, we use a different format to encode chains than branching nodes. A chain is encoded as a string of keycodes, beginning with the node closest to the root, and terminated with a zero byte. The child of the last node in the chain is encoded immediately after. That child could be either a branching node or a leaf.
+
+In the figure above, the f-i-t-l chain is encoded as
+
+ +-------+-------+-------+-------+-------+
+ | L | T | I | F | 0 |
+ +-------+-------+-------+-------+-------+
+If we were to encode this chain using the same format used for branching nodes, we would encode a 16-bit node link with every node, costing 8 more bytes in this example. Across the whole trie, this adds up. Conveniently, we can point to intermediate points in the chain and interpret the bytes in the same way as before. E.g. starting at the i instead of the l, and the subchain has the same format.
+
+Leaf node. A leaf node corresponds to a particular typo and stores data to correct the typo. The leaf begins with a byte for the number of backspaces to type, and is followed by a null-terminated ASCII string of the replacement text. The idea is, after tapping backspace the indicated number of times, we can simply pass this string to QMK’s send_string_P function. For fitler, we need to tap backspace 3 times (not 4, because we catch the typo as the final ‘r’ is pressed) and replace it with lter. To identify the node as a leaf, the two high bits are set to 10 by ORing the backspace count with 128:
+
+ +-------+-------+-------+-------+-------+-------+
+ | 3|128 | 'l' | 't' | 'e' | 'r' | 0 |
+ +-------+-------+-------+-------+-------+-------+
+## Decoding
+This format is by design decodable with fairly simple logic. A 16-bit variable state represents our current position in the trie, initialized with 0 to start at the root node. Then, for each keycode, test the highest two bits in the byte at state to identify the kind of node.
+
+* 00 ⇒ chain node: If the node’s byte matches the keycode, increment state by one to go to the next byte. If the next byte is zero, increment again to go to the following node.
+* 01 ⇒ branching node: Search the branches for one that matches the keycode, and follow its node link.
+* 10 ⇒ leaf node: a typo has been found! We read its first byte for the number of backspaces to type, then pass its following bytes to send_string_P to type the correction.
diff --git a/users/drashna/keyrecords/caps_word.c b/users/drashna/keyrecords/caps_word.c
new file mode 100644
index 0000000000..0c7cd6cfe5
--- /dev/null
+++ b/users/drashna/keyrecords/caps_word.c
@@ -0,0 +1,83 @@
+// Copyright 2021 Google LLC.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "caps_word.h"
+
+#ifndef IS_COMMAND
+# define IS_COMMAND() (get_mods() == MOD_MASK_SHIFT)
+#endif
+
+bool caps_word_enabled = false;
+bool caps_word_shifted = false;
+
+/**
+ * @brief Handler for Caps Word feature.
+ *
+ * This checks the keycodes, and applies shift to the correct keys, if and when needid.
+ *
+ * @param keycode Keycode from matrix
+ * @param record keyrecord_t data structure
+ * @return true Continue processing keycode and sent to host
+ * @return false Stop processing keycode, and do not send to host
+ */
+bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
+ if (!caps_word_enabled) {
+ // Pressing both shift keys at the same time enables caps word.
+ if (IS_COMMAND()) {
+ clear_mods();
+ clear_oneshot_mods();
+ caps_word_shifted = false;
+ caps_word_enabled = true;
+ return false;
+ }
+ return true;
+ }
+
+ if (!record->event.pressed) {
+ return true;
+ }
+
+ if (!((get_mods() | get_oneshot_mods()) & ~MOD_MASK_SHIFT)) {
+ switch (keycode) {
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+ // Earlier return if this has not been considered tapped yet.
+ if (record->tap.count == 0) {
+ return true;
+ }
+ // Get the base tapping keycode of a mod- or layer-tap key.
+ keycode &= 0xff;
+ }
+
+ switch (keycode) {
+ // Letter keys should be shifted.
+ case KC_A ... KC_Z:
+ if (!caps_word_shifted) {
+ register_code(KC_LSFT);
+ }
+ caps_word_shifted = true;
+ return true;
+
+ // Keycodes that continue caps word but shouldn't get shifted.
+ case KC_1 ... KC_0:
+ case KC_BSPC:
+ case KC_MINS:
+ case KC_UNDS:
+ if (caps_word_shifted) {
+ unregister_code(KC_LSFT);
+ }
+ caps_word_shifted = false;
+ return true;
+
+ // Any other keycode disables caps word.
+ }
+ }
+
+ // Disable caps word.
+ caps_word_enabled = false;
+ if (caps_word_shifted) {
+ unregister_code(KC_LSFT);
+ }
+ caps_word_shifted = false;
+ return true;
+}
diff --git a/users/drashna/keyrecords/caps_word.h b/users/drashna/keyrecords/caps_word.h
new file mode 100644
index 0000000000..79e410ddda
--- /dev/null
+++ b/users/drashna/keyrecords/caps_word.h
@@ -0,0 +1,8 @@
+// Copyright 2021 Google LLC.
+// SPDX-License-Identifier: Apache-2.0
+
+#pragma once
+
+#include "drashna.h"
+
+bool process_caps_word(uint16_t keycode, keyrecord_t* record);
diff --git a/users/drashna/keyrecords/capwords.md b/users/drashna/keyrecords/capwords.md
new file mode 100644
index 0000000000..1ca01ed853
--- /dev/null
+++ b/users/drashna/keyrecords/capwords.md
@@ -0,0 +1,36 @@
+# Cap Words
+
+This is taken from [Pascal Getreuer's implemenation](https://getreuer.info/posts/keyboards/caps-word/index.html), with a number of modifications.
+
+To enable Caps Word, add `CAPS_WORD_ENABLE = yes` to your `rules.mk`.
+
+This is mostly a reproduction of Pascal's docs:
+
+## Overview
+
+All-caps identifiers like “MOD_MASK_ALT” are awkward to type.
+
+Caps Lock would be the standard solution to this problem, but it is awkward: it needs a dedicated key to toggle it (an imposition on smaller keyboards), and we need to remember to toggle it off after typing the word. Or with normal shifting, we either perform finger gymnastics or need to stop typing in the middle of the word to release shift with one hand to switch to holding shift with the other hand. In my experience, this is a nuisance especially if your shift keys are mod-taps, as in home row mods.
+
+Caps Word, implemented here, is a modern alternative to Caps Lock:
+
+* Caps Word is activated by pressing the left and right shift keys at the same time. This way you don’t need a dedicated key for using Caps Word.
+* Caps Word automatically disables itself at the end of the word.
+
+**Compatibility**: I’ve tested that this implementation works with one-shot mods and Space Cadet Shift, and it predictably handles key repeating.
+
+Unlike some other QMK Caps Word implementations, this library does not use the Caps Lock (KC_CAPS) keycode. It works even if the OS remaps Caps Lock to Ctrl or something else, as Emacs and Vim users often do.
+
+## Using Caps Word
+With the above flashed to your keyboard:
+
+1. **Activating**: Press and release both left and right shift keys at the same time. If your shift keys are mod-taps, activate Caps Word by holding both shift mod-tap keys until the tapping term, then release them.
+2. Then begin typing to get capitalized letters.
+3. **Disabling**: Caps Word disables itself when the next word breaking key is typed.
+
+If you want to explicitly stop Caps Word, press and release Ctrl or another non-shift modifier or layer key. This also disables Caps Word.
+
+## Explanation
+The code checks the mod bits on each key event, enabling Caps Word when both left and right shifts are active.
+
+While enabled, Caps Word automatically presses and releases left shift (KC_LSFT) as needed so that letters are shifted and other keys are not. The word continues while typing a–z, 0–9, -, _, and backspace. Any other key is considered “word breaking” and disables Caps Word. You can edit the switch statement at the end of the process_caps_word() function to adjust which keys count as word breaking.
diff --git a/users/drashna/keyrecords/keycodes.md b/users/drashna/keyrecords/keycodes.md
new file mode 100644
index 0000000000..348c68e46c
--- /dev/null
+++ b/users/drashna/keyrecords/keycodes.md
@@ -0,0 +1,18 @@
+
+# Custom Keycodes
+
+Keycodes are defined in the `process_record.h` file and need to be included in the keymap.c files, so that they can be used there.
+
+A bunch of macros are present and are only included on boards that are not the Ergodox EZ or Orthodox, as they are not needed for those boards.
+
+* `KC_MAKE` - outputs `qmk compile -kb (keyboard) -km (keymap)` and enter, to start compiling the currenct keyboard. This uses generated variables to always use the current keyboard and keymap. Will work with any keyboard and any keymap.
+ * If you are holding shift, it will use `qmk flash` instead of `qmk compile`.
+ * If `MAKE_BOOTLOADER` is defined, it will always use `qmk flash` instead of `qmk compile`.
+* `DEFAULT_LAYER_1` ... `DEFAULT_LAYER_4` - This sets layer 0-3 as the default layer, and writes that to eeprom, and plays a chime.
+* `VRSN`, outputs the keyboard, keymap, commit and date info. Eg:
+ * `handwired/tractyl_manuform/5x6_right/f411/drashna @ 0.15.9-162-g087d08, Built on: 2021-12-19-21:10:26`
+* `KC_DIABLO_CLEAR` - clears the diablo tapdance status.
+* `KC_CCCV` - Copy on hold, paste on tap.
+* `KEYLOCK` - This unloads the host driver, and prevents any data from being sent to the host. Hitting it again loads the driver, back.
+* `REBOOT` - Uses watchdog timer on AVR, and `NVIC_SystemReset()` on ChibiOS to reset the board, without jumping to the bootloader.
+* `EEP_RST` - Overrides the default behavior, disables EEPROM (which will trigger a reset on init), and reboots the keyboard as per `REBOOT` keycode.
diff --git a/users/drashna/process_records.c b/users/drashna/keyrecords/process_records.c
index c16c70c050..160a880215 100644
--- a/users/drashna/process_records.c
+++ b/users/drashna/keyrecords/process_records.c
@@ -1,30 +1,42 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#include "drashna.h"
#include "version.h"
+#ifdef CAPS_WORD_ENABLE
+# include "caps_word.h"
+#endif
+#ifdef AUTOCORRECTION_ENABLE
+# include "autocorrection/autocorrection.h"
+#endif
+#ifdef __AVR__
+# include <avr/wdt.h>
+#endif
uint16_t copy_paste_timer;
bool host_driver_disabled = false;
// Defines actions tor my global custom keycodes. Defined in drashna.h file
// Then runs the _keymap's record handier if not processed here
+/**
+ * @brief Keycode handler for keymaps
+ *
+ * This handles the keycodes at the keymap level, useful for keyboard specific customization
+ */
__attribute__((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; }
__attribute__((weak)) bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { return true; }
-bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+
+/**
+ * @brief Main user keycode handler
+ *
+ * This handles all of the keycodes for the user, including calling feature handlers.
+ *
+ * @param keycode Keycode from matrix
+ * @param record keyrecord_t data structure
+ * @return true Continue processing keycode and send to host
+ * @return false Stop process keycode and do not send to host
+ */
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
// If console is enabled, it will print the matrix position and status of each key pressed
#ifdef KEYLOGGER_ENABLE
uprintf("KL: kc: 0x%04X, col: %2u, row: %2u, pressed: %b, time: %5u, int: %b, count: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed, record->event.time, record->tap.interrupted, record->tap.count);
@@ -40,6 +52,18 @@ bool process_record_user(uint16_t keycode, keyrecord_t *re
#ifdef RGBLIGHT_ENABLE
&& process_record_user_rgb_light(keycode, record)
#endif
+#ifdef CUSTOM_UNICODE_ENABLE
+ && process_record_unicode(keycode, record)
+#endif
+#if defined(POINTING_DEVICE_ENABLE)
+ && process_record_pointing(keycode, record)
+#endif
+#ifdef CAPS_WORD_ENABLE
+ && process_caps_word(keycode, record)
+#endif
+#ifdef AUTOCORRECTION_ENABLE
+ && process_autocorrection(keycode, record)
+#endif
&& true)) {
return false;
}
@@ -117,28 +141,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *re
}
}
break;
-#ifdef UNICODE_ENABLE
- case UC_FLIP: // (ノಠ痊ಠ)ノ彡┻━┻
- if (record->event.pressed) {
- send_unicode_string("(ノಠ痊ಠ)ノ彡┻━┻");
- }
- break;
- case UC_TABL: // ┬─┬ノ( º _ ºノ)
- if (record->event.pressed) {
- send_unicode_string("┬─┬ノ( º _ ºノ)");
- }
- break;
- case UC_SHRG: // ¯\_(ツ)_/¯
- if (record->event.pressed) {
- send_unicode_string("¯\\_(ツ)_/¯");
- }
- break;
- case UC_DISA: // ಠ_ಠ
- if (record->event.pressed) {
- send_unicode_string("ಠ_ಠ");
- }
- break;
-#endif
case KC_RGB_T: // This allows me to use underglow as layer indication, or as normal
#if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
if (record->event.pressed) {
@@ -215,7 +217,23 @@ bool process_record_user(uint16_t keycode, keyrecord_t *re
}
}
break;
+ }
+ case EEP_RST:
+ if (record->event.pressed) {
+ eeconfig_disable();
+ shutdown_user();
+#ifdef __AVR__
+ wdt_enable(WDTO_250MS);
+#else
+ NVIC_SystemReset();
+#endif
}
+ return false;
+ case REBOOT:
+ if (record->event.pressed) {
+ software_reset();
+ }
+ return false;
}
return true;
}
diff --git a/users/drashna/process_records.h b/users/drashna/keyrecords/process_records.h
index 897d7bbcc9..d7a81d4607 100644
--- a/users/drashna/process_records.h
+++ b/users/drashna/keyrecords/process_records.h
@@ -1,23 +1,10 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "drashna.h"
-#if defined(KEYBOARD_handwired_tractyl_manuform_5x6_right)
+#if defined(KEYBOARD_handwired_tractyl_manuform)
# define PLACEHOLDER_SAFE_RANGE KEYMAP_SAFE_RANGE
#else
# define PLACEHOLDER_SAFE_RANGE SAFE_RANGE
@@ -46,13 +33,28 @@ enum userspace_custom_keycodes {
UC_TABL, // ┬─┬ノ( º _ ºノ)
UC_SHRG, // ¯\_(ツ)_/¯
UC_DISA, // ಠ_ಠ
+ UC_IRNY,
+ UC_CLUE,
KEYLOCK, // Locks keyboard by unmounting driver
+ KC_NOMODE,
+ KC_WIDE,
+ KC_SCRIPT,
+ KC_BLOCKS,
+ KC_REGIONAL,
+ KC_AUSSIE,
+ KC_ZALGO,
+ KC_ACCEL,
+ AUTO_CTN, // Toggle Autocorrect status
+ REBOOT,
NEW_SAFE_RANGE // use "NEWPLACEHOLDER for keymap specific codes
};
bool process_record_secrets(uint16_t keycode, keyrecord_t *record);
bool process_record_keymap(uint16_t keycode, keyrecord_t *record);
void post_process_record_keymap(uint16_t keycode, keyrecord_t *record);
+#ifdef CUSTOM_UNICODE_ENABLE
+bool process_record_unicode(uint16_t keycode, keyrecord_t *record);
+#endif
#define LOWER MO(_LOWER)
#define RAISE MO(_RAISE)
@@ -126,5 +128,20 @@ void post_process_record_keymap(uint16_t keycode, keyrecord_t *record);
#define MG_NKRO MAGIC_TOGGLE_NKRO
-#define UC_IRNY UC(0x2E2E)
-#define UC_CLUE UC(0x203D)
+
+/*
+Custom Keycodes for Diablo 3 layer
+But since TD() doesn't work when tap dance is disabled
+We use custom codes here, so we can substitute the right stuff
+*/
+#ifdef TAP_DANCE_ENABLE
+# define KC_D3_1 TD(TD_D3_1)
+# define KC_D3_2 TD(TD_D3_2)
+# define KC_D3_3 TD(TD_D3_3)
+# define KC_D3_4 TD(TD_D3_4)
+#else // TAP_DANCE_ENABLE
+# define KC_D3_1 KC_1
+# define KC_D3_2 KC_2
+# define KC_D3_3 KC_3
+# define KC_D3_4 KC_4
+#endif // TAP_DANCE_ENABLE
diff --git a/users/drashna/keyrecords/readme.md b/users/drashna/keyrecords/readme.md
new file mode 100644
index 0000000000..5f708f9edf
--- /dev/null
+++ b/users/drashna/keyrecords/readme.md
@@ -0,0 +1,9 @@
+# Keycode handling and interception
+
+ * [Autocorrection](autocorrection/readme.md)
+ * [Cap Words](capwords.md)
+ * [Diablo Tap Dancing](tap_dance.md)
+ * [Keymap Wrappers](wrappers.md)
+ * [Secret Macros](secrets.md)
+ * [Custom Keycodes](keycodes.md)
+ * [Unicode Input](unicode.md)
diff --git a/users/drashna/readme_secrets.md b/users/drashna/keyrecords/secrets.md
index a9408dc2ef..a9408dc2ef 100644
--- a/users/drashna/readme_secrets.md
+++ b/users/drashna/keyrecords/secrets.md
diff --git a/users/drashna/readme_tap_dance.md b/users/drashna/keyrecords/tap_dance.md
index a61dd1f2b0..0bf67cbd5a 100644
--- a/users/drashna/readme_tap_dance.md
+++ b/users/drashna/keyrecords/tap_dance.md
@@ -1,6 +1,8 @@
# Diablo Tap Dances
-My [Tap Dance](https://github.com/qmk/qmk_firmware/blob/master/users/drashna/tap_dances.c) file includes the tap dance declarations, and everything needed for them.
+My [Tap Dance](tap_dances.c) file includes the tap dance declarations, and everything needed for them.
+
+To disable, add `CUSTOM_TAP_DANCE = no` to your `rules.mk`.
This is used for making Diablo 3 much easier to plan, especially at high rift levels.
diff --git a/users/drashna/tap_dances.c b/users/drashna/keyrecords/tap_dances.c
index 01873489d8..a1a7439164 100644
--- a/users/drashna/tap_dances.c
+++ b/users/drashna/keyrecords/tap_dances.c
@@ -1,18 +1,5 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#include "tap_dances.h"
@@ -24,7 +11,12 @@ diablo_timer_t diablo_timer[NUM_OF_DIABLO_KEYS];
// Otherwise, you will need to hit a bunch of times, or hit the "clear" command
uint8_t diablo_times[] = {0, 1, 3, 5, 10, 30};
-// Cycle through the times for the macro, starting at 0, for disabled.
+/**
+ * @brief Main function for handling diable related tap dances.
+ *
+ * @param state Main data struction contining information about events
+ * @param user_data Local data for the dance. Allows customization to be passed on to function
+ */
void diablo_tapdance_master(qk_tap_dance_state_t *state, void *user_data) {
diable_keys_t *diablo_keys = (diable_keys_t *)user_data;
// Sets the keycode based on the index
@@ -56,7 +48,10 @@ qk_tap_dance_action_t tap_dance_actions[] = {
[TD_D3_4] = ACTION_TAP_DANCE_DIABLO(3, KC_4),
};
-// Checks each of the 4 timers/keys to see if enough time has elapsed
+/**
+ * @brief Runs check to see if timer has elapsed for each dance, and sends keycodes, if it has.
+ *
+ */
void run_diablo_macro_check(void) {
for (uint8_t index = 0; index < NUM_OF_DIABLO_KEYS; index++) {
// if key_interval is 0, it's disabled, so only run if it's set. If it's set, check the timer.
diff --git a/users/drashna/keyrecords/tap_dances.h b/users/drashna/keyrecords/tap_dances.h
new file mode 100644
index 0000000000..d9baedc867
--- /dev/null
+++ b/users/drashna/keyrecords/tap_dances.h
@@ -0,0 +1,31 @@
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+#include "drashna.h"
+
+// define diablo macro timer variables
+extern uint8_t diablo_times[];
+typedef struct {
+ uint16_t timer;
+ uint8_t key_interval;
+ uint8_t keycode;
+} diablo_timer_t;
+
+typedef struct {
+ uint8_t index;
+ uint8_t keycode;
+} diable_keys_t;
+
+extern diablo_timer_t diablo_timer[];
+
+void run_diablo_macro_check(void);
+
+#ifdef TAP_DANCE_ENABLE
+enum {
+ TD_D3_1 = 0,
+ TD_D3_2,
+ TD_D3_3,
+ TD_D3_4,
+};
+#endif // TAP_DANCE_ENABLE
diff --git a/users/drashna/keyrecords/tapping.c b/users/drashna/keyrecords/tapping.c
new file mode 100644
index 0000000000..9c4892b33d
--- /dev/null
+++ b/users/drashna/keyrecords/tapping.c
@@ -0,0 +1,64 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "drashna.h"
+
+__attribute__((weak)) uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case BK_LWER:
+ return TAPPING_TERM + 25;
+ default:
+ return TAPPING_TERM;
+ }
+}
+
+__attribute__((weak)) bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
+ // Immediately select the hold action when another key is tapped:
+ // return true;
+ // Do not select the hold action when another key is tapped.
+ // return false;
+ switch (keycode) {
+ default:
+ return false;
+ }
+}
+
+__attribute__((weak)) bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
+ // Immediately select the hold action when another key is pressed.
+ // return true;
+ // Do not select the hold action when another key is pressed.
+ // return false;
+ switch (keycode) {
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+ return true;
+ default:
+ return false;
+ }
+}
+
+__attribute__((weak)) bool get_ignore_mod_tap_interrupt(uint16_t keycode, keyrecord_t *record) {
+ // Do not force the mod-tap key press to be handled as a modifier
+ // if any other key was pressed while the mod-tap key is held down.
+ // return true;
+ // Force the mod-tap key press to be handled as a modifier if any
+ // other key was pressed while the mod-tap key is held down.
+ // return false;
+ switch (keycode) {
+ default:
+ return true;
+ }
+}
+
+__attribute__((weak)) bool get_tapping_force_hold(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ default:
+ return false;
+ }
+}
+
+__attribute__((weak)) bool get_retro_tapping(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ default:
+ return false;
+ }
+}
diff --git a/users/drashna/keyrecords/unicode.c b/users/drashna/keyrecords/unicode.c
new file mode 100644
index 0000000000..5acd51da9b
--- /dev/null
+++ b/users/drashna/keyrecords/unicode.c
@@ -0,0 +1,294 @@
+// Copyright 2020 @ridingqwerty
+// Copyright 2020 @tzarc
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "drashna.h"
+#include "process_unicode_common.h"
+
+uint16_t typing_mode;
+
+/**
+ * @brief Registers the unicode keystrokes based on desired unicode
+ *
+ * @param glyph Unicode character, supports up to 0x1FFFF (or higher)
+ */
+void tap_unicode_glyph_nomods(uint32_t glyph) {
+ uint8_t temp_mod = get_mods();
+ clear_mods();
+ clear_oneshot_mods();
+ register_unicode(glyph);
+ set_mods(temp_mod);
+}
+
+typedef uint32_t (*translator_function_t)(bool is_shifted, uint32_t keycode);
+
+#define DEFINE_UNICODE_RANGE_TRANSLATOR(translator_name, lower_alpha, upper_alpha, zero_glyph, number_one, space_glyph) \
+ static inline uint32_t translator_name(bool is_shifted, uint32_t keycode) { \
+ switch (keycode) { \
+ case KC_A ... KC_Z: \
+ return (is_shifted ? upper_alpha : lower_alpha) + keycode - KC_A; \
+ case KC_0: \
+ return zero_glyph; \
+ case KC_1 ... KC_9: \
+ return (number_one + keycode - KC_1); \
+ case KC_SPACE: \
+ return space_glyph; \
+ } \
+ return keycode; \
+ }
+
+#define DEFINE_UNICODE_LUT_TRANSLATOR(translator_name, ...) \
+ static inline uint32_t translator_name(bool is_shifted, uint32_t keycode) { \
+ static const uint32_t translation[] = {__VA_ARGS__}; \
+ uint32_t ret = keycode; \
+ if ((keycode - KC_A) < (sizeof(translation) / sizeof(uint32_t))) { \
+ ret = translation[keycode - KC_A]; \
+ } \
+ return ret; \
+ }
+
+/**
+ * @brief Handler function for outputting unicode.
+ *
+ * @param keycode Keycode from matrix.
+ * @param record keyrecord_t data structure
+ * @param translator translator lut for different unicode modes
+ * @return true Continue processing matrix press, and send to host
+ * @return false Replace keycode, and do not send to host
+ */
+bool process_record_glyph_replacement(uint16_t keycode, keyrecord_t *record, translator_function_t translator) {
+ uint8_t temp_mod = get_mods();
+ uint8_t temp_osm = get_oneshot_mods();
+ bool is_shifted = (temp_mod | temp_osm) & MOD_MASK_SHIFT;
+ if (((temp_mod | temp_osm) & (MOD_MASK_CTRL | MOD_MASK_ALT | MOD_MASK_GUI)) == 0) {
+ if (KC_A <= keycode && keycode <= KC_Z) {
+ if (record->event.pressed) {
+ tap_unicode_glyph_nomods(translator(is_shifted, keycode));
+ }
+ return false;
+ } else if (KC_1 <= keycode && keycode <= KC_0) {
+ if (is_shifted) { // skip shifted numbers, so that we can still use symbols etc.
+ return process_record_keymap(keycode, record);
+ }
+ if (record->event.pressed) {
+ register_unicode(translator(is_shifted, keycode));
+ }
+ return false;
+ } else if (keycode == KC_SPACE) {
+ if (record->event.pressed) {
+ register_unicode(translator(is_shifted, keycode));
+ }
+ return false;
+ }
+ }
+ return true;
+}
+
+DEFINE_UNICODE_RANGE_TRANSLATOR(unicode_range_translator_wide, 0xFF41, 0xFF21, 0xFF10, 0xFF11, 0x2003);
+DEFINE_UNICODE_RANGE_TRANSLATOR(unicode_range_translator_script, 0x1D4EA, 0x1D4D0, 0x1D7CE, 0x1D7C1, 0x2002);
+DEFINE_UNICODE_RANGE_TRANSLATOR(unicode_range_translator_boxes, 0x1F170, 0x1F170, '0', '1', 0x2002);
+DEFINE_UNICODE_RANGE_TRANSLATOR(unicode_range_translator_regional, 0x1F1E6, 0x1F1E6, '0', '1', 0x2003);
+
+DEFINE_UNICODE_LUT_TRANSLATOR(unicode_lut_translator_aussie,
+ 0x0250, // a
+ 'q', // b
+ 0x0254, // c
+ 'p', // d
+ 0x01DD, // e
+ 0x025F, // f
+ 0x0183, // g
+ 0x0265, // h
+ 0x1D09, // i
+ 0x027E, // j
+ 0x029E, // k
+ 'l', // l
+ 0x026F, // m
+ 'u', // n
+ 'o', // o
+ 'd', // p
+ 'b', // q
+ 0x0279, // r
+ 's', // s
+ 0x0287, // t
+ 'n', // u
+ 0x028C, // v
+ 0x028D, // w
+ 0x2717, // x
+ 0x028E, // y
+ 'z', // z
+ 0x0269, // 1
+ 0x3139, // 2
+ 0x0190, // 3
+ 0x3123, // 4
+ 0x03DB, // 5
+ '9', // 6
+ 0x3125, // 7
+ '8', // 8
+ '6', // 9
+ '0' // 0
+);
+
+bool process_record_aussie(uint16_t keycode, keyrecord_t *record) {
+ bool is_shifted = (get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT;
+ if ((KC_A <= keycode) && (keycode <= KC_0)) {
+ if (record->event.pressed) {
+ if (!process_record_glyph_replacement(keycode, record, unicode_lut_translator_aussie)) {
+ tap_code16_nomods(KC_LEFT);
+ return false;
+ }
+ }
+ } else if (record->event.pressed && keycode == KC_SPACE) {
+ tap_code16_nomods(KC_SPACE);
+ tap_code16_nomods(KC_LEFT);
+ return false;
+ } else if (record->event.pressed && keycode == KC_ENTER) {
+ tap_code16_nomods(KC_END);
+ tap_code16_nomods(KC_ENTER);
+ return false;
+ } else if (record->event.pressed && keycode == KC_HOME) {
+ tap_code16_nomods(KC_END);
+ return false;
+ } else if (record->event.pressed && keycode == KC_END) {
+ tap_code16_nomods(KC_HOME);
+ return false;
+ } else if (record->event.pressed && keycode == KC_BSPC) {
+ tap_code16_nomods(KC_DELT);
+ return false;
+ } else if (record->event.pressed && keycode == KC_DELT) {
+ tap_code16_nomods(KC_BSPC);
+ return false;
+ } else if (record->event.pressed && keycode == KC_QUOT) {
+ tap_unicode_glyph_nomods(is_shifted ? 0x201E : 0x201A);
+ tap_code16_nomods(KC_LEFT);
+ return false;
+ } else if (record->event.pressed && keycode == KC_COMMA) {
+ tap_unicode_glyph_nomods(is_shifted ? '<' : 0x2018);
+ tap_code16_nomods(KC_LEFT);
+ return false;
+ } else if (record->event.pressed && keycode == KC_DOT) {
+ tap_unicode_glyph_nomods(is_shifted ? '>' : 0x02D9);
+ tap_code16_nomods(KC_LEFT);
+ return false;
+ } else if (record->event.pressed && keycode == KC_SLASH) {
+ tap_unicode_glyph_nomods(is_shifted ? 0x00BF : '/');
+ tap_code16_nomods(KC_LEFT);
+ return false;
+ }
+ return true;
+}
+
+bool process_record_zalgo(uint16_t keycode, keyrecord_t *record) {
+ if ((KC_A <= keycode) && (keycode <= KC_0)) {
+ if (record->event.pressed) {
+ tap_code16_nomods(keycode);
+
+ int number = (rand() % (8 + 1 - 2)) + 2;
+ for (int index = 0; index < number; index++) {
+ uint16_t hex = (rand() % (0x036F + 1 - 0x0300)) + 0x0300;
+ register_unicode(hex);
+ }
+
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * @brief Main handler for unicode input
+ *
+ * @param keycode Keycode from switch matrix
+ * @param record keyrecord_t data struture
+ * @return true Send keycode from matrix to host
+ * @return false Stop processing and do not send to host
+ */
+
+bool process_record_unicode(uint16_t keycode, keyrecord_t *record) {
+ switch (keycode) {
+ case UC_FLIP: // (ノಠ痊ಠ)ノ彡┻━┻
+ if (record->event.pressed) {
+ send_unicode_string("(ノಠ痊ಠ)ノ彡┻━┻");
+ }
+ break;
+
+ case UC_TABL: // ┬─┬ノ( º _ ºノ)
+ if (record->event.pressed) {
+ send_unicode_string("┬─┬ノ( º _ ºノ)");
+ }
+ break;
+
+ case UC_SHRG: // ¯\_(ツ)_/¯
+ if (record->event.pressed) {
+ send_unicode_string("¯\\_(ツ)_/¯");
+ }
+ break;
+
+ case UC_DISA: // ಠ_ಠ
+ if (record->event.pressed) {
+ send_unicode_string("ಠ_ಠ");
+ }
+ break;
+
+ case UC_IRNY: // ⸮
+ if (record->event.pressed) {
+ register_unicode(0x2E2E);
+ }
+ break;
+ case UC_CLUE: // ‽
+ if (record->event.pressed) {
+ register_unicode(0x203D);
+ }
+ break;
+ case KC_NOMODE ... KC_ZALGO:
+ if (record->event.pressed) {
+ if (typing_mode != keycode) {
+ typing_mode = keycode;
+ } else {
+ typing_mode = 0;
+ }
+ }
+ break;
+ }
+
+ if (((get_mods() | get_oneshot_mods()) & ~MOD_MASK_SHIFT) != 0) {
+ return true;
+ }
+
+ if (((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) && record->tap.count) {
+ keycode &= 0xFF;
+ }
+
+ if (typing_mode == KC_WIDE) {
+ if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) {
+ return process_record_glyph_replacement(keycode, record, unicode_range_translator_wide);
+ }
+ } else if (typing_mode == KC_SCRIPT) {
+ if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) {
+ return process_record_glyph_replacement(keycode, record, unicode_range_translator_script);
+ }
+ } else if (typing_mode == KC_BLOCKS) {
+ if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) {
+ return process_record_glyph_replacement(keycode, record, unicode_range_translator_boxes);
+ }
+ } else if (typing_mode == KC_REGIONAL) {
+ if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) {
+ if (!process_record_glyph_replacement(keycode, record, unicode_range_translator_regional)) {
+ wait_us(500);
+ tap_unicode_glyph_nomods(0x200C);
+ return false;
+ }
+ }
+ } else if (typing_mode == KC_AUSSIE) {
+ return process_record_aussie(keycode, record);
+ } else if (typing_mode == KC_ZALGO) {
+ return process_record_zalgo(keycode, record);
+ }
+ return true;
+}
+
+/**
+ * @brief Initialize the default unicode mode on firmware startu
+ *
+ */
+void matrix_init_unicode(void) { unicode_input_mode_init(); }
diff --git a/users/drashna/keyrecords/unicode.md b/users/drashna/keyrecords/unicode.md
new file mode 100644
index 0000000000..1b3f696a82
--- /dev/null
+++ b/users/drashna/keyrecords/unicode.md
@@ -0,0 +1,27 @@
+# Custom Unicode
+
+To disable, add `CUSTOM_UNICODE_ENABLE = no` to the keymap's `rules.mk`.
+
+This disables all of the various implementations of unicode, enables the common unicode core, and allows usage.
+
+In addition to a number of unicode keycodes:
+
+* `UC_FLIP` - `(ノಠ痊ಠ)ノ彡┻━┻`
+* `UC_TABL` - `┬─┬ノ( º _ ºノ)`
+* `UC_SHRG` - `¯\_(ツ)_/¯`
+* `UC_DISA` - `ಠ_ಠ`
+* `UC_IRNY` - `⸮`
+* `UC_CLUE` - `‽`
+
+There are a number of unicode typing modes. This replaces the normal alpha keys with special unicodes.
+
+* `KC_WIDE` - this is wide mode
+* `KC_SCRIPT` - 𝓽𝓱𝓲𝓼 𝓲𝓼 𝓼𝓬𝓻𝓲𝓹𝓽 𝓶𝓸𝓭𝓮
+* `KC_BLOCKS` - 🆃🅷🅸🆂 🅸🆂 🅱🅻🅾🅲🅺 🅼🅾🅳🅴
+* `KC_REGIONAL` - 🇹‌‌🇭‌‌🇮‌‌🇸‌‌ ‌‌🇮‌‌🇸‌‌ ‌‌🇷‌‌🇪‌‌🇬‌‌🇮‌‌🇴‌‌🇳‌‌🇦‌‌🇱‌‌ ‌‌🇲‌‌🇴‌‌🇩‌‌🇪‌‌
+* `KC_AUSSIE` - ǝpoɯ ǝᴉssnɐ sᴉ sᴉɥʇ
+* `KC_ZALGO` - t̨͕͙̺͍͐̾ĥ̻ï̳̻̗̜͔ͦs͎̠͈͓͗̀ i̶̫ͭ̆s̛̫̻̜̝͑͡ z̩͈̠͗a͚̜̓͜l͈̟g͋͢͝ò͚ͥ͘͡͞ ḿ̴̡̻̼̔ͪò͔̭̿ͪ̍ḏ̻̊̄̈e̳͕̤ͣͯ
+* `KC_NOMODE` - this is the normal typing mode with no unicode glyphs
+
+
+Credit goes to ridingqwerty and tzarc for the unicode typing modes.
diff --git a/users/drashna/wrappers.h b/users/drashna/keyrecords/wrappers.h
index c1ae815579..cb8dc6189a 100644
--- a/users/drashna/wrappers.h
+++ b/users/drashna/keyrecords/wrappers.h
@@ -1,18 +1,6 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// Copyright 2020 @jola5
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "drashna.h"
diff --git a/users/drashna/readme_wrappers.md b/users/drashna/keyrecords/wrappers.md
index fd62ff1609..fd62ff1609 100644
--- a/users/drashna/readme_wrappers.md
+++ b/users/drashna/keyrecords/wrappers.md
diff --git a/users/drashna/drashna_font.h b/users/drashna/oled/drashna_font.h
index 844292a53a..7ba03c4c13 100644
--- a/users/drashna/drashna_font.h
+++ b/users/drashna/oled/drashna_font.h
@@ -3,8 +3,8 @@
// additional fonts from
// https://github.com/datacute/TinyOLED-Fonts
-#if __has_include("../../../../Documents/qmk/oled_font.h")
-# include "../../../../Documents/qmk/oled_font.h"
+#if __has_include("oled_font.h")
+# include "oled_font.h"
#else
// additional fonts from
diff --git a/users/drashna/oled/oled_stuff.c b/users/drashna/oled/oled_stuff.c
new file mode 100644
index 0000000000..c850c5336f
--- /dev/null
+++ b/users/drashna/oled/oled_stuff.c
@@ -0,0 +1,1120 @@
+/* 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"
+#endif
+#include <string.h>
+
+extern bool host_driver_disabled;
+
+uint32_t oled_timer = 0;
+char keylog_str[OLED_KEYLOGGER_LENGTH] = {0};
+static uint16_t log_timer = 0;
+static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0};
+
+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 < (sizeof(code_to_name) / sizeof(char))) {
+ 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 = timer_read32();
+ add_keylog(keycode, record);
+ }
+ return true;
+}
+
+void update_log(void) {
+ if (timer_elapsed(log_timer) > 750) {
+ // add_keylog(0);
+ }
+}
+
+/**
+ * @brief Renders keylogger buffer to oled
+ *
+ */
+void render_keylogger_status(void) {
+#ifdef OLED_DISPLAY_VERBOSE
+ oled_set_cursor(1, 6);
+#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(void) {
+#ifdef OLED_DISPLAY_VERBOSE
+ oled_set_cursor(1, 1);
+#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(void) {
+#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(1, 2);
+ oled_write_raw_P(tri_layer_image[layer_is[0]][0], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(5, 2);
+ oled_write_raw_P(tri_layer_image[layer_is[1]][0], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(9, 2);
+ oled_write_raw_P(tri_layer_image[layer_is[2]][0], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(14, 2);
+ oled_write_P(PSTR("Diablo2"), layer_state_is(_DIABLOII));
+ oled_advance_page(true);
+
+ oled_set_cursor(1, 3);
+ oled_write_raw_P(tri_layer_image[layer_is[0]][1], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(5, 3);
+ oled_write_raw_P(tri_layer_image[layer_is[1]][1], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(9, 3);
+ oled_write_raw_P(tri_layer_image[layer_is[2]][1], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(14, 3);
+ oled_write_P(PSTR("Diablo3"), layer_state_is(_DIABLO));
+ oled_advance_page(true);
+
+ oled_set_cursor(1, 4);
+ oled_write_raw_P(tri_layer_image[layer_is[0]][2], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(5, 4);
+ oled_write_raw_P(tri_layer_image[layer_is[1]][2], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(9, 4);
+ oled_write_raw_P(tri_layer_image[layer_is[2]][2], sizeof(tri_layer_image[0][0]));
+ oled_set_cursor(14, 4);
+ 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(uint8_t led_usb_state) {
+#if defined(OLED_DISPLAY_VERBOSE)
+ oled_set_cursor(1, 6);
+#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 & (1 << USB_LED_NUM_LOCK));
+ oled_write_P(PSTR(" "), false);
+ oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state & (1 << USB_LED_CAPS_LOCK));
+#if defined(OLED_DISPLAY_VERBOSE)
+ oled_write_P(PSTR(" "), false);
+ oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state & (1 << USB_LED_SCROLL_LOCK));
+#endif
+}
+
+/**
+ * @brief Renders the matrix scan rate to the host system
+ *
+ */
+void render_matrix_scan_rate(uint8_t padding) {
+#ifdef DEBUG_MATRIX_SCAN_RATE
+ 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) {
+ 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(1, 5);
+#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(void) {
+ /* 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(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(PSTR(" "), false);
+ 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);
+#ifdef AUTOCORRECTION_ENABLE
+ oled_write_P(PSTR("CRCT"), userspace_config.autocorrection);
+ 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(7, 4);
+ 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(POINTING_DEVICE_ENABLE)
+extern bool tap_toggling;
+#endif
+
+void render_user_status(void) {
+#ifdef AUDIO_ENABLE
+ bool is_audio_on = false, is_clicky_on = false;
+# ifdef SPLIT_KEYBOARD
+
+ is_audio_on = user_state.audio_enable;
+ is_clicky_on = user_state.audio_clicky_enable;
+# else
+ is_audio_on = is_audio_on();
+ is_clicky_on = is_clicky_on();
+# endif
+#endif
+#if defined(OLED_DISPLAY_VERBOSE)
+ oled_set_cursor(1, 5);
+#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(POINTING_DEVICE_ENABLE)
+ 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[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_wpm(uint8_t padding) {
+#ifdef WPM_ENABLE
+
+ 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) {
+ 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
+ oled_pan(false); // then move the entire graph one pixel to the right
+ static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0};
+ for (uint8_t i = 0; i < 7; i++) {
+ oled_set_cursor(0, i + 8);
+ oled_write_raw_P(display_border, sizeof(display_border));
+ oled_set_cursor(21, i + 8);
+ 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, 15);
+
+ oled_write_raw_P(footer_image, sizeof(footer_image));
+
+ timer = timer_read(); // refresh the timer for the next iteration
+ }
+}
+
+#if defined(POINTING_DEVICE_ENABLE)
+void render_pointing_dpi_status(uint16_t cpi, uint8_t padding) {
+ 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
+
+__attribute__((weak)) void oled_driver_render_logo_right(void) {
+#if defined(OLED_DISPLAY_VERBOSE)
+ oled_set_cursor(0, 1);
+#endif
+ render_default_layer_state();
+}
+
+// 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 32 // number of bytes in array, minimize for adequate firmware size, max is 1024
+#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(void) {
+ // 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, 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, 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, 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,
+ 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, 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, 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
+ }
+ }
+ },
+ // 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, 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, 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, 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, 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, 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, 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, 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
+ }
+ }
+ },
+ // 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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
+ }
+ }
+ },
+ // 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, 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
+ },
+ {
+ 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, 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, 0xc0, 0x20, 0x10, 0x10, 0x08, 0x04, 0x02,
+ 0x01, 0x1f, 0xa0, 0x20, 0x40, 0x80, 0x00, 0xf0
+ },
+ {
+ 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
+ },
+ {
+ 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,
+ 0x01, 0x01, 0x01, 0x06, 0x04, 0x04, 0x04, 0x04,
+ 0x05, 0x04, 0x04, 0x04, 0x07, 0x07, 0x07, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ }
+ }
+ }
+ };
+ // clang-format on
+
+ for (uint8_t i = 0; i < 4; i++) {
+ oled_set_cursor(1, i + 1);
+ oled_write_raw_P(animation[animation_type][animation_frame][i], OLED_ANIM_SIZE);
+ }
+}
+
+uint32_t kitty_animation_phases(uint32_t triger_time, void *cb_arg) {
+ static uint32_t anim_frame_duration = 500;
+#ifdef POINTING_DEVICE_ENABLE
+ 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 oled_driver_render_logo_left(void) {
+#if defined(OLED_DISPLAY_VERBOSE)
+ oled_set_cursor(0, 1);
+ render_kitty();
+
+# 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);
+# else
+ oled_set_cursor(8, 0);
+ oled_write_P(PSTR("Left"), true);
+# endif
+ oled_set_cursor(7, 1);
+# if defined(WPM_ENABLE)
+ render_wpm(1);
+# elif defined(DEBUG_MATRIX_SCAN_RATE)
+ render_matrix_scan_rate(2);
+# endif
+ oled_set_cursor(7, 2);
+# if defined(KEYBOARD_bastardkb_charybdis)
+ render_pointing_dpi_status(charybdis_get_pointer_sniping_enabled() ? charybdis_get_pointer_sniping_dpi() : charybdis_get_pointer_default_dpi(), 1);
+
+// 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(17, 1);
+ oled_write_raw_P(mouse_logo[image_index][0], 16);
+ oled_set_cursor(17, 2);
+ oled_write_raw_P(mouse_logo[image_index][1], 16);
+# elif defined(WPM_ENABLE) && defined(DEBUG_MATRIX_SCAN_RATE)
+ render_matrix_scan_rate(2);
+# endif
+
+ oled_set_cursor(0, 5);
+#else
+ render_default_layer_state();
+#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
+ oled_driver_render_logo_right();
+ /* Show Keyboard Layout */
+ render_layer_state();
+ render_mod_status(get_mods() | get_oneshot_mods());
+#if !defined(OLED_DISPLAY_VERBOSE) && defined(WPM_ENABLE) && !defined(CONVERT_TO_PROTON_C)
+ render_wpm(2);
+#endif
+ render_keylock_status(host_keyboard_leds());
+}
+
+void render_status_left(void) {
+ oled_driver_render_logo_left();
+
+ /* Show Keyboard Layout */
+ render_bootmagic_status();
+ render_user_status();
+
+ render_keylogger_status();
+}
+
+__attribute__((weak)) void oled_render_large_display(void) {}
+
+__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) {
+ update_log();
+
+ if (is_keyboard_master()) {
+#ifndef OLED_DISPLAY_TEST
+ if (timer_elapsed32(oled_timer) > 60000) {
+ oled_off();
+ return false;
+ } else
+#endif
+ {
+ oled_on();
+ }
+ }
+
+ if (!oled_task_keymap()) {
+ return false;
+ }
+
+#if defined(OLED_DISPLAY_128X128)
+ oled_set_cursor(0, 7);
+ oled_render_large_display();
+#endif
+
+#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
+ };
+ 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, 0);
+ oled_write_raw_P(header_image, sizeof(header_image));
+ oled_set_cursor(0, 1);
+#endif
+
+#ifndef OLED_DISPLAY_TEST
+ if (is_keyboard_left()) {
+#endif
+ render_status_left();
+#ifndef OLED_DISPLAY_TEST
+ } else {
+ render_status_right();
+ }
+#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));
+ }
+
+ oled_set_cursor(0, num_of_rows);
+ oled_write_raw_P(footer_image, sizeof(footer_image));
+#endif
+
+ return false;
+}
diff --git a/users/drashna/oled_stuff.h b/users/drashna/oled/oled_stuff.h
index 8795684d6a..7245f6131c 100644
--- a/users/drashna/oled_stuff.h
+++ b/users/drashna/oled/oled_stuff.h
@@ -18,6 +18,7 @@
#include "quantum.h"
#include "oled_driver.h"
+extern deferred_token kittoken;
void oled_driver_render_logo(void);
bool process_record_user_oled(uint16_t keycode, keyrecord_t *record);
@@ -27,22 +28,28 @@ void render_keylogger_status(void);
void render_default_layer_state(void);
void render_layer_state(void);
void render_keylock_status(uint8_t led_usb_state);
-void render_matrix_scan_rate(void);
+void render_matrix_scan_rate(uint8_t padding);
void render_mod_status(uint8_t modifiers);
void render_bootmagic_status(void);
void render_user_status(void);
void oled_driver_render_logo(void);
void render_wpm(uint8_t padding);
-void render_pointing_dpi_status(uint8_t padding);
+void render_pointing_dpi_status(uint16_t cpi, uint8_t padding);
void oled_driver_render_logo_left(void);
void oled_driver_render_logo_right(void);
+void oled_render_large_display(void);
+void render_wpm_graph(uint8_t max_lines_graph, uint8_t vertical_offset);
-#ifdef OLED_DISPLAY_128X64
-# define OLED_RENDER_KEYLOGGER "Keylogger: "
+#if defined(OLED_DISPLAY_128X128) || defined(OLED_DISPLAY_128X64)
+# define OLED_DISPLAY_VERBOSE
+# define OLED_RENDER_KEYLOGGER "Keylogger: "
+# ifndef OLED_KEYLOGGER_LENGTH
+# define OLED_KEYLOGGER_LENGTH 9
+# endif
# define OLED_RENDER_LAYOUT_NAME "Layout: "
# define OLED_RENDER_LAYOUT_QWERTY "Qwerty"
-# define OLED_RENDER_LAYOUT_COLEMAK_DH "Colemak-DH"
+# define OLED_RENDER_LAYOUT_COLEMAK_DH "Colemak DH"
# define OLED_RENDER_LAYOUT_COLEMAK "Colemak"
# define OLED_RENDER_LAYOUT_DVORAK "Dvorak"
# define OLED_RENDER_LAYOUT_WORKMAN "Workman"
@@ -58,11 +65,11 @@ void oled_driver_render_logo_right(void);
# define OLED_RENDER_LAYER_MODS "Mods"
# define OLED_RENDER_LOCK_NAME "Lock: "
-# define OLED_RENDER_LOCK_NUML "NUML"
+# define OLED_RENDER_LOCK_NUML "NUM"
# define OLED_RENDER_LOCK_CAPS "CAPS"
# define OLED_RENDER_LOCK_SCLK "SCLK"
-# define OLED_RENDER_MODS_NAME "Mods:"
+# define OLED_RENDER_MODS_NAME "Mods"
# define OLED_RENDER_MODS_SFT "Sft"
# define OLED_RENDER_MODS_CTL "Ctl"
# define OLED_RENDER_MODS_ALT "Alt"
@@ -84,6 +91,9 @@ void oled_driver_render_logo_right(void);
# define OLED_RENDER_WPM_COUNTER "WPM: "
#else
# define OLED_RENDER_KEYLOGGER "KLogr"
+# ifndef OLED_KEYLOGGER_LENGTH
+# define OLED_KEYLOGGER_LENGTH 5
+# endif
# define OLED_RENDER_LAYOUT_NAME "Lyout"
# define OLED_RENDER_LAYOUT_QWERTY " QRTY"
@@ -127,5 +137,23 @@ void oled_driver_render_logo_right(void);
# define OLED_RENDER_USER_NUKE "Nuke"
# define OLED_RENDER_WPM_COUNTER "WPM: "
+#endif
+
+
+extern char keylog_str[OLED_KEYLOGGER_LENGTH];
+#ifndef OLED_WPM_GRAPH_MAX_WPM
+# define OLED_WPM_GRAPH_MAX_WPM 120
+#endif
+#ifndef OLED_WPM_GRAPH_REFRESH_INTERVAL
+# define OLED_WPM_GRAPH_REFRESH_INTERVAL 300
+#endif
+#ifndef OLED_WPM_GRAPH_AREA_FILL_INTERVAL
+# define OLED_WPM_GRAPH_AREA_FILL_INTERVAL 3
+#endif
+#ifndef OLED_WPM_GRAPH_VERTCAL_LINE_INTERVAL
+# define OLED_WPM_GRAPH_VERTCAL_LINE_INTERVAL 3
+#endif
+#ifndef OLED_WPM_GRAPH_GRAPH_LINE_THICKNESS
+# define OLED_WPM_GRAPH_GRAPH_LINE_THICKNESS 2
#endif
diff --git a/users/drashna/oled/readme.md b/users/drashna/oled/readme.md
new file mode 100644
index 0000000000..dbb8187d49
--- /dev/null
+++ b/users/drashna/oled/readme.md
@@ -0,0 +1,42 @@
+# OLED Display
+
+To disable the pre genrated oled display, add `CUSTOM_OLED_DRIVER = no` to your `rules.mk`.
+
+<!-- to do: add all the stuff -->
+## OLED Font
+
+My font file has multiple fonts and multiple logs integrated into the one file. And it uses the full 255 possible characters.
+
+In addition to the default font and logos:
+
+```c
+# define OLED_FONT_5X5
+# define OLED_FONT_AZTECH
+# define OLED_FONT_BMPLAIN
+# define OLED_FONT_CRACKERS
+# define OLED_FONT_EIN
+# define OLED_FONT_HISKYF21
+# define OLED_FONT_SQUASH
+# define OLED_FONT_SUPER_DIGG
+# define OLED_FONT_ZXPIX
+```
+
+```c
+# define OLED_LOGO_CORNE
+# define OLED_LOGO_GMK_BAD
+# define OLED_LOGO_GOTHAM
+# define OLED_LOGO_HUE_MANITEE
+# define OLED_LOGO_LOOSE
+# define OLED_LOGO_SETS3N
+# define OLED_LOGO_SKEEB
+```
+
+Additionally, the font file allows for external oled font files, instead. This allows for additional files that cannot be hosted in the QMK Repo.
+
+## Display
+
+A picture is worth a thousand words. So here are two:
+
+![Right](https://i.imgur.com/4XFOVKBl.jpg)
+
+![Left](https://i.imgur.com/W5RX4pAl.jpg)
diff --git a/users/drashna/oled/sh110x.c b/users/drashna/oled/sh110x.c
new file mode 100644
index 0000000000..c850a47538
--- /dev/null
+++ b/users/drashna/oled/sh110x.c
@@ -0,0 +1,860 @@
+/*
+Copyright 2019 Ryan Caltabiano <https://github.com/XScorpion2>
+
+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 "i2c_master.h"
+#include "oled_driver.h"
+#include OLED_FONT_H
+#include "timer.h"
+#include "print.h"
+
+#include <string.h>
+
+#include "progmem.h"
+
+#include "keyboard.h"
+
+// Used commands from spec sheet: https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
+// for SH1106: https://www.velleman.eu/downloads/29/infosheets/sh1106_datasheet.pdf
+
+// Fundamental Commands
+#define CONTRAST 0x81
+#define DISPLAY_ALL_ON 0xA5
+#define DISPLAY_ALL_ON_RESUME 0xA4
+#define NORMAL_DISPLAY 0xA6
+#define INVERT_DISPLAY 0xA7
+#define DISPLAY_ON 0xAF
+#define DISPLAY_OFF 0xAE
+#define NOP 0xE3
+
+// Scrolling Commands
+#define ACTIVATE_SCROLL 0x2F
+#define DEACTIVATE_SCROLL 0x2E
+#define SCROLL_RIGHT 0x26
+#define SCROLL_LEFT 0x27
+#define SCROLL_RIGHT_UP 0x29
+#define SCROLL_LEFT_UP 0x2A
+
+// Addressing Setting Commands
+#define MEMORY_MODE 0x20
+#define COLUMN_ADDR 0x21
+#define PAGE_ADDR 0x22
+#define PAM_SETCOLUMN_LSB 0x00
+#define PAM_SETCOLUMN_MSB 0x10
+#define PAM_PAGE_ADDR 0xB0 // 0xb0 -- 0xb7
+
+// Hardware Configuration Commands
+#define DISPLAY_START_LINE 0x40
+#define SEGMENT_REMAP 0xA0
+#define SEGMENT_REMAP_INV 0xA1
+#define MULTIPLEX_RATIO 0xA8
+#define COM_SCAN_INC 0xC0
+#define COM_SCAN_DEC 0xC8
+#define DISPLAY_OFFSET 0xD3
+#define COM_PINS 0xDA
+#define COM_PINS_SEQ 0x02
+#define COM_PINS_ALT 0x12
+#define COM_PINS_SEQ_LR 0x22
+#define COM_PINS_ALT_LR 0x32
+
+// Timing & Driving Commands
+#define DISPLAY_CLOCK 0xD5
+#define PRE_CHARGE_PERIOD 0xD9
+#define VCOM_DETECT 0xDB
+
+// Advance Graphic Commands
+#define FADE_BLINK 0x23
+#define ENABLE_FADE 0x20
+#define ENABLE_BLINK 0x30
+
+// Charge Pump Commands
+#define CHARGE_PUMP 0x8D
+
+// Commands specific to the SH1107 chip
+#define SH1107_DISPLAY_START_LINE 0xDC
+#define SH1107_MEMORY_MODE_PAGE 0x20
+#define SH1107_MEMORY_MODE_VERTICAL 0x21
+
+// Misc defines
+#ifndef OLED_BLOCK_COUNT
+# define OLED_BLOCK_COUNT (sizeof(OLED_BLOCK_TYPE) * 8)
+#endif
+#ifndef OLED_BLOCK_SIZE
+# define OLED_BLOCK_SIZE (OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)
+#endif
+
+#define OLED_ALL_BLOCKS_MASK (((((OLED_BLOCK_TYPE)1 << (OLED_BLOCK_COUNT - 1)) - 1) << 1) | 1)
+
+#define OLED_IC_HAS_HORIZONTAL_MODE (OLED_IC == OLED_IC_SSD1306)
+#define OLED_IC_COM_PINS_ARE_COLUMNS (OLED_IC == OLED_IC_SH1107)
+
+#ifndef OLED_COM_PIN_COUNT
+# if OLED_IC == OLED_IC_SH1106
+# define OLED_COM_PIN_COUNT 64
+# elif OLED_IC == OLED_IC_SH1107
+# define OLED_COM_PIN_COUNT 128
+# else
+# error Invalid OLED_IC value
+# endif
+#endif
+
+#ifndef OLED_COM_PIN_OFFSET
+# define OLED_COM_PIN_OFFSET 0
+#endif
+
+// i2c defines
+#define I2C_CMD 0x00
+#define I2C_DATA 0x40
+#if defined(__AVR__)
+# define I2C_TRANSMIT_P(data) i2c_transmit_P((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
+#else // defined(__AVR__)
+# define I2C_TRANSMIT_P(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
+#endif // defined(__AVR__)
+#define I2C_TRANSMIT(data) i2c_transmit((OLED_DISPLAY_ADDRESS << 1), &data[0], sizeof(data), OLED_I2C_TIMEOUT)
+#define I2C_WRITE_REG(mode, data, size) i2c_writeReg((OLED_DISPLAY_ADDRESS << 1), mode, data, size, OLED_I2C_TIMEOUT)
+
+#define HAS_FLAGS(bits, flags) ((bits & flags) == flags)
+
+// Display buffer's is the same as the OLED memory layout
+// this is so we don't end up with rounding errors with
+// parts of the display unusable or don't get cleared correctly
+// and also allows for drawing & inverting
+uint8_t oled_buffer[OLED_MATRIX_SIZE];
+uint8_t * oled_cursor;
+OLED_BLOCK_TYPE oled_dirty = 0;
+bool oled_initialized = false;
+bool oled_active = false;
+bool oled_scrolling = false;
+bool oled_inverted = false;
+uint8_t oled_brightness = OLED_BRIGHTNESS;
+oled_rotation_t oled_rotation = 0;
+uint8_t oled_rotation_width = 0;
+uint8_t oled_scroll_speed = 0; // this holds the speed after being remapped to ssd1306 internal values
+uint8_t oled_scroll_start = 0;
+uint8_t oled_scroll_end = 7;
+#if OLED_TIMEOUT > 0
+uint32_t oled_timeout;
+#endif
+#if OLED_SCROLL_TIMEOUT > 0
+uint32_t oled_scroll_timeout;
+#endif
+#if OLED_UPDATE_INTERVAL > 0
+uint16_t oled_update_timeout;
+#endif
+
+// Internal variables to reduce math instructions
+
+#if defined(__AVR__)
+// identical to i2c_transmit, but for PROGMEM since all initialization is in PROGMEM arrays currently
+// probably should move this into i2c_master...
+static i2c_status_t i2c_transmit_P(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout) {
+ i2c_status_t status = i2c_start(address | I2C_WRITE, timeout);
+
+ for (uint16_t i = 0; i < length && status >= 0; i++) {
+ status = i2c_write(pgm_read_byte((const char *)data++), timeout);
+ if (status) break;
+ }
+
+ i2c_stop();
+
+ return status;
+}
+#endif
+
+// Flips the rendering bits for a character at the current cursor position
+static void InvertCharacter(uint8_t *cursor) {
+ const uint8_t *end = cursor + OLED_FONT_WIDTH;
+ while (cursor < end) {
+ *cursor = ~(*cursor);
+ cursor++;
+ }
+}
+
+bool oled_init(oled_rotation_t rotation) {
+#if defined(USE_I2C) && defined(SPLIT_KEYBOARD)
+ if (!is_keyboard_master()) {
+ return true;
+ }
+#endif
+
+ oled_rotation = oled_init_user(oled_init_kb(rotation));
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ oled_rotation_width = OLED_DISPLAY_WIDTH;
+ } else {
+ oled_rotation_width = OLED_DISPLAY_HEIGHT;
+ }
+ i2c_init();
+
+ static const uint8_t PROGMEM display_setup1[] = {
+ I2C_CMD,
+ DISPLAY_OFF,
+ DISPLAY_CLOCK,
+ 0x80,
+ MULTIPLEX_RATIO,
+#if OLED_IC_COM_PINS_ARE_COLUMNS
+ OLED_DISPLAY_WIDTH - 1,
+#else
+ OLED_DISPLAY_HEIGHT - 1,
+#endif
+ DISPLAY_OFFSET,
+ 0x00,
+ DISPLAY_START_LINE | 0x00,
+ CHARGE_PUMP,
+ 0x14,
+#if (OLED_IC != OLED_IC_SH1106)
+ // MEMORY_MODE is unsupported on SH1106 (Page Addressing only)
+ MEMORY_MODE,
+ 0x00, // Horizontal addressing mode
+#elif OLED_IC == OLED_IC_SH1107
+ // Page addressing mode
+ SH1107_MEMORY_MODE_PAGE,
+#endif
+ };
+ if (I2C_TRANSMIT_P(display_setup1) != I2C_STATUS_SUCCESS) {
+ print("oled_init cmd set 1 failed\n");
+ return false;
+ }
+
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_180)) {
+ static const uint8_t PROGMEM display_normal[] = {
+ I2C_CMD, SEGMENT_REMAP_INV, COM_SCAN_DEC, DISPLAY_OFFSET, OLED_COM_PIN_OFFSET,
+ };
+ if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
+ print("oled_init cmd normal rotation failed\n");
+ return false;
+ }
+ } else {
+ static const uint8_t PROGMEM display_flipped[] = {
+ I2C_CMD, SEGMENT_REMAP, COM_SCAN_INC, DISPLAY_OFFSET, (OLED_COM_PIN_COUNT - OLED_COM_PIN_OFFSET) % OLED_COM_PIN_COUNT,
+ };
+ if (I2C_TRANSMIT_P(display_flipped) != I2C_STATUS_SUCCESS) {
+ print("display_flipped failed\n");
+ return false;
+ }
+ }
+
+ static const uint8_t PROGMEM display_setup2[] = {I2C_CMD, COM_PINS, OLED_COM_PINS, CONTRAST, OLED_BRIGHTNESS, PRE_CHARGE_PERIOD, 0x22, VCOM_DETECT, 0x35, DISPLAY_ALL_ON_RESUME, NORMAL_DISPLAY, DEACTIVATE_SCROLL, DISPLAY_ON}; if (I2C_TRANSMIT_P(display_setup2) != I2C_STATUS_SUCCESS) {
+ print("display_setup2 failed\n");
+ return false;
+ }
+
+#if OLED_TIMEOUT > 0
+ oled_timeout = timer_read32() + OLED_TIMEOUT;
+#endif
+#if OLED_SCROLL_TIMEOUT > 0
+ oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT;
+#endif
+
+ oled_clear();
+ oled_initialized = true;
+ oled_active = true;
+ oled_scrolling = false;
+ return true;
+}
+
+__attribute__((weak)) oled_rotation_t oled_init_kb(oled_rotation_t rotation) { return rotation; }
+__attribute__((weak)) oled_rotation_t oled_init_user(oled_rotation_t rotation) { return rotation; }
+
+void oled_clear(void) {
+ memset(oled_buffer, 0, sizeof(oled_buffer));
+ oled_cursor = &oled_buffer[0];
+ oled_dirty = OLED_ALL_BLOCKS_MASK;
+}
+
+static void calc_bounds(uint8_t update_start, uint8_t *cmd_array) {
+ // Calculate commands to set memory addressing bounds.
+ uint8_t start_page = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_WIDTH;
+ uint8_t start_column = OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_WIDTH;
+#if !OLED_IC_HAS_HORIZONTAL_MODE
+ // Commands for Page Addressing Mode. Sets starting page and column; has no end bound.
+ // Column value must be split into high and low nybble and sent as two commands.
+ cmd_array[0] = PAM_PAGE_ADDR | start_page;
+ cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f);
+ cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f);
+ cmd_array[3] = NOP;
+ cmd_array[4] = NOP;
+ cmd_array[5] = NOP;
+#else
+ // Commands for use in Horizontal Addressing mode.
+ cmd_array[1] = start_column + OLED_COLUMN_OFFSET;
+ cmd_array[4] = start_page;
+ cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) % OLED_DISPLAY_WIDTH + cmd_array[1];
+ cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_WIDTH - 1) / OLED_DISPLAY_WIDTH - 1 + cmd_array[4];
+#endif
+}
+
+static void calc_bounds_90(uint8_t update_start, uint8_t *cmd_array) {
+ // Block numbering starts from the bottom left corner, going up and then to
+ // the right. The controller needs the page and column numbers for the top
+ // left and bottom right corners of that block.
+
+ // Total number of pages across the screen height.
+ const uint8_t height_in_pages = OLED_DISPLAY_HEIGHT / 8;
+
+ // Difference of starting page numbers for adjacent blocks; may be 0 if
+ // blocks are large enough to occupy one or more whole 8px columns.
+ const uint8_t page_inc_per_block = OLED_BLOCK_SIZE % OLED_DISPLAY_HEIGHT / 8;
+
+ // Top page number for a block which is at the bottom edge of the screen.
+ const uint8_t bottom_block_top_page = (height_in_pages - page_inc_per_block) % height_in_pages;
+
+#if !OLED_IC_HAS_HORIZONTAL_MODE
+ // Only the Page Addressing Mode is supported
+ uint8_t start_page = bottom_block_top_page - (OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT / 8);
+ uint8_t start_column = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8;
+ cmd_array[0] = PAM_PAGE_ADDR | start_page;
+ cmd_array[1] = PAM_SETCOLUMN_LSB | ((OLED_COLUMN_OFFSET + start_column) & 0x0f);
+ cmd_array[2] = PAM_SETCOLUMN_MSB | ((OLED_COLUMN_OFFSET + start_column) >> 4 & 0x0f);
+#else
+ cmd_array[1] = OLED_BLOCK_SIZE * update_start / OLED_DISPLAY_HEIGHT * 8 + OLED_COLUMN_OFFSET;
+ cmd_array[4] = bottom_block_top_page - (OLED_BLOCK_SIZE * update_start % OLED_DISPLAY_HEIGHT / 8);
+ cmd_array[2] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8 - 1 + cmd_array[1];
+ cmd_array[5] = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) % OLED_DISPLAY_HEIGHT / 8 + cmd_array[4];
+#endif
+}
+
+uint8_t crot(uint8_t a, int8_t n) {
+ const uint8_t mask = 0x7;
+ n &= mask;
+ return a << n | a >> (-n & mask);
+}
+
+static void rotate_90(const uint8_t *src, uint8_t *dest) {
+ for (uint8_t i = 0, shift = 7; i < 8; ++i, --shift) {
+ uint8_t selector = (1 << i);
+ for (uint8_t j = 0; j < 8; ++j) {
+ dest[i] |= crot(src[j] & selector, shift - (int8_t)j);
+ }
+ }
+}
+
+void oled_render(void) {
+ if (!oled_initialized) {
+ return;
+ }
+
+ // Do we have work to do?
+ oled_dirty &= OLED_ALL_BLOCKS_MASK;
+ if (!oled_dirty || oled_scrolling) {
+ return;
+ }
+
+ // Find first dirty block
+ uint8_t update_start = 0;
+ while (!(oled_dirty & ((OLED_BLOCK_TYPE)1 << update_start))) {
+ ++update_start;
+ }
+
+ // Set column & page position
+#if OLED_IC_HAS_HORIZONTAL_MODE
+ static uint8_t display_start[] = {I2C_CMD, COLUMN_ADDR, 0, OLED_DISPLAY_WIDTH - 1, PAGE_ADDR, 0, OLED_DISPLAY_HEIGHT / 8 - 1};
+#else
+ static uint8_t display_start[] = {I2C_CMD, PAM_PAGE_ADDR, PAM_SETCOLUMN_LSB, PAM_SETCOLUMN_MSB};
+#endif
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ calc_bounds(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
+ } else {
+ calc_bounds_90(update_start, &display_start[1]); // Offset from I2C_CMD byte at the start
+ }
+
+ // Send column & page position
+ if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
+ print("oled_render offset command failed\n");
+ return;
+ }
+
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ // Send render data chunk as is
+ if (I2C_WRITE_REG(I2C_DATA, &oled_buffer[OLED_BLOCK_SIZE * update_start], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
+ print("oled_render data failed\n");
+ return;
+ }
+ } else {
+ // Rotate the render chunks
+ const static uint8_t source_map[] = OLED_SOURCE_MAP;
+ const static uint8_t target_map[] = OLED_TARGET_MAP;
+
+ static uint8_t temp_buffer[OLED_BLOCK_SIZE];
+ memset(temp_buffer, 0, sizeof(temp_buffer));
+ for (uint8_t i = 0; i < sizeof(source_map); ++i) {
+ rotate_90(&oled_buffer[OLED_BLOCK_SIZE * update_start + source_map[i]], &temp_buffer[target_map[i]]);
+ }
+
+#if OLED_IC_HAS_HORIZONTAL_MODE
+ // Send render data chunk after rotating
+ if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[0], OLED_BLOCK_SIZE) != I2C_STATUS_SUCCESS) {
+ print("oled_render90 data failed\n");
+ return;
+ }
+#else
+ // For SH1106 or SH1107 the data chunk must be split into separate pieces for each page
+ const uint8_t columns_in_block = (OLED_BLOCK_SIZE + OLED_DISPLAY_HEIGHT - 1) / OLED_DISPLAY_HEIGHT * 8;
+ const uint8_t num_pages = OLED_BLOCK_SIZE / columns_in_block;
+ for (uint8_t i = 0; i < num_pages; ++i) {
+ // Send column & page position for all pages except the first one
+ if (i > 0) {
+ display_start[1]++;
+ if (I2C_TRANSMIT(display_start) != I2C_STATUS_SUCCESS) {
+ print("oled_render offset command failed\n");
+ return;
+ }
+ }
+ // Send data for the page
+ if (I2C_WRITE_REG(I2C_DATA, &temp_buffer[columns_in_block * i], columns_in_block) != I2C_STATUS_SUCCESS) {
+ print("oled_render90 data failed\n");
+ return;
+ }
+ }
+#endif
+ }
+
+ // Turn on display if it is off
+ oled_on();
+
+ // Clear dirty flag
+ oled_dirty &= ~((OLED_BLOCK_TYPE)1 << update_start);
+}
+
+void oled_set_cursor(uint8_t col, uint8_t line) {
+ uint16_t index = line * oled_rotation_width + col * OLED_FONT_WIDTH;
+
+ // Out of bounds?
+ if (index >= OLED_MATRIX_SIZE) {
+ index = 0;
+ }
+
+ oled_cursor = &oled_buffer[index];
+}
+
+void oled_advance_page(bool clearPageRemainder) {
+ uint16_t index = oled_cursor - &oled_buffer[0];
+ uint8_t remaining = oled_rotation_width - (index % oled_rotation_width);
+
+ if (clearPageRemainder) {
+ // Remaining Char count
+ remaining = remaining / OLED_FONT_WIDTH;
+
+ // Write empty character until next line
+ while (remaining--) oled_write_char(' ', false);
+ } else {
+ // Next page index out of bounds?
+ if (index + remaining >= OLED_MATRIX_SIZE) {
+ index = 0;
+ remaining = 0;
+ }
+
+ oled_cursor = &oled_buffer[index + remaining];
+ }
+}
+
+void oled_advance_char(void) {
+ uint16_t nextIndex = oled_cursor - &oled_buffer[0] + OLED_FONT_WIDTH;
+ uint8_t remainingSpace = oled_rotation_width - (nextIndex % oled_rotation_width);
+
+ // Do we have enough space on the current line for the next character
+ if (remainingSpace < OLED_FONT_WIDTH) {
+ nextIndex += remainingSpace;
+ }
+
+ // Did we go out of bounds
+ if (nextIndex >= OLED_MATRIX_SIZE) {
+ nextIndex = 0;
+ }
+
+ // Update cursor position
+ oled_cursor = &oled_buffer[nextIndex];
+}
+
+// Main handler that writes character data to the display buffer
+void oled_write_char(const char data, bool invert) {
+ // Advance to the next line if newline
+ if (data == '\n') {
+ // Old source wrote ' ' until end of line...
+ oled_advance_page(true);
+ return;
+ }
+
+ if (data == '\r') {
+ oled_advance_page(false);
+ return;
+ }
+
+ // copy the current render buffer to check for dirty after
+ static uint8_t oled_temp_buffer[OLED_FONT_WIDTH];
+ memcpy(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH);
+
+ _Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array");
+
+ // set the reder buffer data
+ uint8_t cast_data = (uint8_t)data; // font based on unsigned type for index
+ if (cast_data < OLED_FONT_START || cast_data > OLED_FONT_END) {
+ memset(oled_cursor, 0x00, OLED_FONT_WIDTH);
+ } else {
+ const uint8_t *glyph = &font[(cast_data - OLED_FONT_START) * OLED_FONT_WIDTH];
+ memcpy_P(oled_cursor, glyph, OLED_FONT_WIDTH);
+ }
+
+ // Invert if needed
+ if (invert) {
+ InvertCharacter(oled_cursor);
+ }
+
+ // Dirty check
+ if (memcmp(&oled_temp_buffer, oled_cursor, OLED_FONT_WIDTH)) {
+ uint16_t index = oled_cursor - &oled_buffer[0];
+ oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE));
+ // Edgecase check if the written data spans the 2 chunks
+ oled_dirty |= ((OLED_BLOCK_TYPE)1 << ((index + OLED_FONT_WIDTH - 1) / OLED_BLOCK_SIZE));
+ }
+
+ // Finally move to the next char
+ oled_advance_char();
+}
+
+void oled_write(const char *data, bool invert) {
+ const char *end = data + strlen(data);
+ while (data < end) {
+ oled_write_char(*data, invert);
+ data++;
+ }
+}
+
+void oled_write_ln(const char *data, bool invert) {
+ oled_write(data, invert);
+ oled_advance_page(true);
+}
+
+void oled_pan(bool left) {
+ uint16_t i = 0;
+ for (uint16_t y = 0; y < OLED_DISPLAY_HEIGHT / 8; y++) {
+ if (left) {
+ for (uint16_t x = 0; x < OLED_DISPLAY_WIDTH - 1; x++) {
+ i = y * OLED_DISPLAY_WIDTH + x;
+ oled_buffer[i] = oled_buffer[i + 1];
+ }
+ } else {
+ for (uint16_t x = OLED_DISPLAY_WIDTH - 1; x > 0; x--) {
+ i = y * OLED_DISPLAY_WIDTH + x;
+ oled_buffer[i] = oled_buffer[i - 1];
+ }
+ }
+ }
+ oled_dirty = OLED_ALL_BLOCKS_MASK;
+}
+
+oled_buffer_reader_t oled_read_raw(uint16_t start_index) {
+ if (start_index > OLED_MATRIX_SIZE) start_index = OLED_MATRIX_SIZE;
+ oled_buffer_reader_t ret_reader;
+ ret_reader.current_element = &oled_buffer[start_index];
+ ret_reader.remaining_element_count = OLED_MATRIX_SIZE - start_index;
+ return ret_reader;
+}
+
+void oled_write_raw_byte(const char data, uint16_t index) {
+ if (index > OLED_MATRIX_SIZE) index = OLED_MATRIX_SIZE;
+ if (oled_buffer[index] == data) return;
+ oled_buffer[index] = data;
+ oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE));
+}
+
+void oled_write_raw(const char *data, uint16_t size) {
+ uint16_t cursor_start_index = oled_cursor - &oled_buffer[0];
+ if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index;
+ for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
+ uint8_t c = *data++;
+ if (oled_buffer[i] == c) continue;
+ oled_buffer[i] = c;
+ oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
+ }
+}
+
+void oled_write_pixel(uint8_t x, uint8_t y, bool on) {
+ if (x >= oled_rotation_width) {
+ return;
+ }
+ uint16_t index = x + (y / 8) * oled_rotation_width;
+ if (index >= OLED_MATRIX_SIZE) {
+ return;
+ }
+ uint8_t data = oled_buffer[index];
+ if (on) {
+ data |= (1 << (y % 8));
+ } else {
+ data &= ~(1 << (y % 8));
+ }
+ if (oled_buffer[index] != data) {
+ oled_buffer[index] = data;
+ oled_dirty |= ((OLED_BLOCK_TYPE)1 << (index / OLED_BLOCK_SIZE));
+ }
+}
+
+#if defined(__AVR__)
+void oled_write_P(const char *data, bool invert) {
+ uint8_t c = pgm_read_byte(data);
+ while (c != 0) {
+ oled_write_char(c, invert);
+ c = pgm_read_byte(++data);
+ }
+}
+
+void oled_write_ln_P(const char *data, bool invert) {
+ oled_write_P(data, invert);
+ oled_advance_page(true);
+}
+
+void oled_write_raw_P(const char *data, uint16_t size) {
+ uint16_t cursor_start_index = oled_cursor - &oled_buffer[0];
+ if ((size + cursor_start_index) > OLED_MATRIX_SIZE) size = OLED_MATRIX_SIZE - cursor_start_index;
+ for (uint16_t i = cursor_start_index; i < cursor_start_index + size; i++) {
+ uint8_t c = pgm_read_byte(data++);
+ if (oled_buffer[i] == c) continue;
+ oled_buffer[i] = c;
+ oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE));
+ }
+}
+#endif // defined(__AVR__)
+
+bool oled_on(void) {
+ if (!oled_initialized) {
+ return oled_active;
+ }
+
+#if OLED_TIMEOUT > 0
+ oled_timeout = timer_read32() + OLED_TIMEOUT;
+#endif
+
+ static const uint8_t PROGMEM display_on[] =
+#ifdef OLED_FADE_OUT
+ {I2C_CMD, FADE_BLINK, 0x00};
+#else
+ {I2C_CMD, DISPLAY_ON};
+#endif
+
+ if (!oled_active) {
+ if (I2C_TRANSMIT_P(display_on) != I2C_STATUS_SUCCESS) {
+ print("oled_on cmd failed\n");
+ return oled_active;
+ }
+ oled_active = true;
+ }
+ return oled_active;
+}
+
+bool oled_off(void) {
+ if (!oled_initialized) {
+ return !oled_active;
+ }
+
+ static const uint8_t PROGMEM display_off[] =
+#ifdef OLED_FADE_OUT
+ {I2C_CMD, FADE_BLINK, ENABLE_FADE | OLED_FADE_OUT_INTERVAL};
+#else
+ {I2C_CMD, DISPLAY_OFF};
+#endif
+
+ if (oled_active) {
+ if (I2C_TRANSMIT_P(display_off) != I2C_STATUS_SUCCESS) {
+ print("oled_off cmd failed\n");
+ return oled_active;
+ }
+ oled_active = false;
+ }
+ return !oled_active;
+}
+
+bool is_oled_on(void) { return oled_active; }
+
+uint8_t oled_set_brightness(uint8_t level) {
+ if (!oled_initialized) {
+ return oled_brightness;
+ }
+
+ uint8_t set_contrast[] = {I2C_CMD, CONTRAST, level};
+ if (oled_brightness != level) {
+ if (I2C_TRANSMIT(set_contrast) != I2C_STATUS_SUCCESS) {
+ print("set_brightness cmd failed\n");
+ return oled_brightness;
+ }
+ oled_brightness = level;
+ }
+ return oled_brightness;
+}
+
+uint8_t oled_get_brightness(void) { return oled_brightness; }
+
+// Set the specific 8 lines rows of the screen to scroll.
+// 0 is the default for start, and 7 for end, which is the entire
+// height of the screen. For 128x32 screens, rows 4-7 are not used.
+void oled_scroll_set_area(uint8_t start_line, uint8_t end_line) {
+ oled_scroll_start = start_line;
+ oled_scroll_end = end_line;
+}
+
+void oled_scroll_set_speed(uint8_t speed) {
+ // Sets the speed for scrolling... does not take effect
+ // until scrolling is either started or restarted
+ // the ssd1306 supports 8 speeds
+ // FrameRate2 speed = 7
+ // FrameRate3 speed = 4
+ // FrameRate4 speed = 5
+ // FrameRate5 speed = 0
+ // FrameRate25 speed = 6
+ // FrameRate64 speed = 1
+ // FrameRate128 speed = 2
+ // FrameRate256 speed = 3
+ // for ease of use these are remaped here to be in order
+ static const uint8_t scroll_remap[8] = {7, 4, 5, 0, 6, 1, 2, 3};
+ oled_scroll_speed = scroll_remap[speed];
+}
+
+bool oled_scroll_right(void) {
+ if (!oled_initialized) {
+ return oled_scrolling;
+ }
+
+ // Dont enable scrolling if we need to update the display
+ // This prevents scrolling of bad data from starting the scroll too early after init
+ if (!oled_dirty && !oled_scrolling) {
+ uint8_t display_scroll_right[] = {I2C_CMD, SCROLL_RIGHT, 0x00, oled_scroll_start, oled_scroll_speed, oled_scroll_end, 0x00, 0xFF, ACTIVATE_SCROLL};
+ if (I2C_TRANSMIT(display_scroll_right) != I2C_STATUS_SUCCESS) {
+ print("oled_scroll_right cmd failed\n");
+ return oled_scrolling;
+ }
+ oled_scrolling = true;
+ }
+ return oled_scrolling;
+}
+
+bool oled_scroll_left(void) {
+ if (!oled_initialized) {
+ return oled_scrolling;
+ }
+
+ // Dont enable scrolling if we need to update the display
+ // This prevents scrolling of bad data from starting the scroll too early after init
+ if (!oled_dirty && !oled_scrolling) {
+ uint8_t display_scroll_left[] = {I2C_CMD, SCROLL_LEFT, 0x00, oled_scroll_start, oled_scroll_speed, oled_scroll_end, 0x00, 0xFF, ACTIVATE_SCROLL};
+ if (I2C_TRANSMIT(display_scroll_left) != I2C_STATUS_SUCCESS) {
+ print("oled_scroll_left cmd failed\n");
+ return oled_scrolling;
+ }
+ oled_scrolling = true;
+ }
+ return oled_scrolling;
+}
+
+bool oled_scroll_off(void) {
+ if (!oled_initialized) {
+ return !oled_scrolling;
+ }
+
+ if (oled_scrolling) {
+ static const uint8_t PROGMEM display_scroll_off[] = {I2C_CMD, DEACTIVATE_SCROLL};
+ if (I2C_TRANSMIT_P(display_scroll_off) != I2C_STATUS_SUCCESS) {
+ print("oled_scroll_off cmd failed\n");
+ return oled_scrolling;
+ }
+ oled_scrolling = false;
+ oled_dirty = OLED_ALL_BLOCKS_MASK;
+ }
+ return !oled_scrolling;
+}
+
+bool is_oled_scrolling(void) { return oled_scrolling; }
+
+bool oled_invert(bool invert) {
+ if (!oled_initialized) {
+ return oled_inverted;
+ }
+
+ if (invert && !oled_inverted) {
+ static const uint8_t PROGMEM display_inverted[] = {I2C_CMD, INVERT_DISPLAY};
+ if (I2C_TRANSMIT_P(display_inverted) != I2C_STATUS_SUCCESS) {
+ print("oled_invert cmd failed\n");
+ return oled_inverted;
+ }
+ oled_inverted = true;
+ } else if (!invert && oled_inverted) {
+ static const uint8_t PROGMEM display_normal[] = {I2C_CMD, NORMAL_DISPLAY};
+ if (I2C_TRANSMIT_P(display_normal) != I2C_STATUS_SUCCESS) {
+ print("oled_invert cmd failed\n");
+ return oled_inverted;
+ }
+ oled_inverted = false;
+ }
+
+ return oled_inverted;
+}
+
+uint8_t oled_max_chars(void) {
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ return OLED_DISPLAY_WIDTH / OLED_FONT_WIDTH;
+ }
+ return OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH;
+}
+
+uint8_t oled_max_lines(void) {
+ if (!HAS_FLAGS(oled_rotation, OLED_ROTATION_90)) {
+ return OLED_DISPLAY_HEIGHT / OLED_FONT_HEIGHT;
+ }
+ return OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT;
+}
+
+void oled_task(void) {
+ if (!oled_initialized) {
+ return;
+ }
+
+#if OLED_UPDATE_INTERVAL > 0
+ if (timer_elapsed(oled_update_timeout) >= OLED_UPDATE_INTERVAL) {
+ oled_update_timeout = timer_read();
+ oled_set_cursor(0, 0);
+ oled_task_kb();
+ }
+#else
+ oled_set_cursor(0, 0);
+ oled_task_kb();
+#endif
+
+#if OLED_SCROLL_TIMEOUT > 0
+ if (oled_dirty && oled_scrolling) {
+ oled_scroll_timeout = timer_read32() + OLED_SCROLL_TIMEOUT;
+ oled_scroll_off();
+ }
+#endif
+
+ // Smart render system, no need to check for dirty
+ oled_render();
+
+ // Display timeout check
+#if OLED_TIMEOUT > 0
+ if (oled_active && timer_expired32(timer_read32(), oled_timeout)) {
+ oled_off();
+ }
+#endif
+
+#if OLED_SCROLL_TIMEOUT > 0
+ if (!oled_scrolling && timer_expired32(timer_read32(), oled_scroll_timeout)) {
+# ifdef OLED_SCROLL_TIMEOUT_RIGHT
+ oled_scroll_right();
+# else
+ oled_scroll_left();
+# endif
+ }
+#endif
+}
+
+__attribute__((weak)) bool oled_task_kb(void) { return oled_task_user(); }
+__attribute__((weak)) bool oled_task_user(void) { return true; }
diff --git a/users/drashna/oled_stuff.c b/users/drashna/oled_stuff.c
deleted file mode 100644
index 396e5e05b7..0000000000
--- a/users/drashna/oled_stuff.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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"
-
-extern bool host_driver_disabled;
-
-#ifndef KEYLOGGER_LENGTH
-// # ifdef OLED_DISPLAY_128X64
-# define KEYLOGGER_LENGTH ((uint8_t)(OLED_DISPLAY_HEIGHT / OLED_FONT_WIDTH))
-// # else
-// # define KEYLOGGER_LENGTH (uint8_t *(OLED_DISPLAY_WIDTH / OLED_FONT_HEIGHT))
-// # endif
-#endif
-
-uint32_t oled_timer = 0;
-static char keylog_str[KEYLOGGER_LENGTH + 1] = {0};
-static uint16_t log_timer = 0;
-
-// 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
-
-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, ' ', sizeof(keylog_str) - 1);
- return;
- }
- if (record->tap.count) {
- keycode = keycode & 0xFF;
- } else if (keycode > 0xFF) {
- return;
- }
- }
- if (keycode > 0xFF) {
- return;
- }
-
- for (uint8_t i = 1; i < KEYLOGGER_LENGTH; i++) {
- keylog_str[i - 1] = keylog_str[i];
- }
-
- if (keycode < (sizeof(code_to_name) / sizeof(char))) {
- keylog_str[(KEYLOGGER_LENGTH - 1)] = pgm_read_byte(&code_to_name[keycode]);
- }
-
- log_timer = timer_read();
-}
-
-bool process_record_user_oled(uint16_t keycode, keyrecord_t *record) {
- if (record->event.pressed) {
-#ifdef OLED_ENABLE
- oled_timer = timer_read32();
- add_keylog(keycode, record);
-#endif
- }
- return true;
-}
-
-void update_log(void) {
- if (timer_elapsed(log_timer) > 750) {
- // add_keylog(0);
- }
-}
-
-void render_keylogger_status(void) {
- oled_write_P(PSTR(OLED_RENDER_KEYLOGGER), false);
- oled_write(keylog_str, false);
-}
-
-void render_default_layer_state(void) {
- 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_128X64
- oled_advance_page(true);
-#endif
-}
-
-void render_layer_state(void) {
- oled_write_P(PSTR(OLED_RENDER_LAYER_NAME), false);
-#ifdef OLED_DISPLAY_128X64
- oled_write_P(PSTR(" "), false);
-#endif
- oled_write_P(PSTR(OLED_RENDER_LAYER_LOWER), layer_state_is(_LOWER));
-#ifdef OLED_DISPLAY_128X64
- oled_write_P(PSTR(" "), false);
-#endif
- oled_write_P(PSTR(OLED_RENDER_LAYER_RAISE), layer_state_is(_RAISE));
-#ifdef OLED_DISPLAY_128X64
- oled_advance_page(true);
- oled_write_P(PSTR(" "), false);
- oled_write_P(PSTR("GamePad"), layer_state_is(_GAMEPAD));
- oled_write_P(PSTR(" "), false);
- oled_write_P(PSTR("Diablo"), layer_state_is(_DIABLO));
- oled_write_P(PSTR(" "), false);
- oled_write_P(PSTR("Mouse"), layer_state_is(_MOUSE));
-#endif
-}
-
-void render_keylock_status(uint8_t led_usb_state) {
- oled_write_P(PSTR(OLED_RENDER_LOCK_NAME), false);
-#if !defined(OLED_DISPLAY_128X64)
- oled_write_P(PSTR(" "), false);
-#endif
- oled_write_P(PSTR(OLED_RENDER_LOCK_NUML), led_usb_state & (1 << USB_LED_NUM_LOCK));
- oled_write_P(PSTR(" "), false);
- oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state & (1 << USB_LED_CAPS_LOCK));
-// oled_write_P(PSTR(" "), false);
-// oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state & (1 << USB_LED_SCROLL_LOCK));
-}
-
-void render_matrix_scan_rate(void) {
-#ifdef DEBUG_MATRIX_SCAN_RATE
- char matrix_rate[5];
- uint16_t n = get_matrix_scan_rate();
- matrix_rate[4] = '\0';
- matrix_rate[3] = '0' + n % 10;
- matrix_rate[2] = (n /= 10) % 10 ? '0' + (n) % 10 : (n / 10) % 10 ? '0' : ' ';
- matrix_rate[1] = n / 10 ? '0' + n / 10 : ' ';
- matrix_rate[0] = ' ';
- oled_write_P(PSTR("MS:"), false);
- oled_write(matrix_rate, false);
-#endif
-}
-
-void render_mod_status(uint8_t modifiers) {
- static const char PROGMEM mod_status[5][3] = {{0xE8, 0xE9, 0}, {0xE4, 0xE5, 0}, {0xE6, 0xE7, 0}, {0xEA, 0xEB, 0}, {0xEC, 0xED, 0}};
- oled_write_P(PSTR(OLED_RENDER_MODS_NAME), false);
-#if defined(OLED_DISPLAY_128X64)
- 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(void) {
- /* 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_128X64
- is_bootmagic_on = !keymap_config.swap_lctl_lgui;
-#else
- is_bootmagic_on = keymap_config.swap_lctl_lgui;
-#endif
-
- oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NAME), false);
-#ifdef OLED_DISPLAY_128X64
- if (keymap_config.swap_lctl_lgui)
-#else
- oled_write_P(PSTR(" "), false);
-#endif
- {
- oled_write_P(logo[1][0], is_bootmagic_on);
-#ifdef OLED_DISPLAY_128X64
- } else {
-#endif
- oled_write_P(logo[0][0], !is_bootmagic_on);
- }
-#ifndef OLED_DISPLAY_128X64
- oled_write_P(PSTR(" "), false);
- 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);
- oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NOGUI), keymap_config.no_gui);
-#ifdef OLED_DISPLAY_128X64
- oled_advance_page(true);
- oled_write_P(PSTR("Magic"), false);
- oled_write_P(PSTR(" "), false);
- 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);
-#endif
-#ifdef OLED_DISPLAY_128X64
- oled_advance_page(true);
-#endif
-}
-
-#if defined(POINTING_DEVICE_ENABLE)
-extern bool tap_toggling;
-#endif
-
-void render_user_status(void) {
-#ifdef AUDIO_ENABLE
- bool is_audio_on = false, is_clicky_on = false;
-# ifdef SPLIT_KEYBOARD
-
- is_audio_on = user_state.audio_enable;
- is_clicky_on = user_state.audio_clicky_enable;
-# else
- is_audio_on = is_audio_on();
- is_clicky_on = is_clicky_on();
-# endif
-#endif
- oled_write_P(PSTR(OLED_RENDER_USER_NAME), false);
-#if !defined(OLED_DISPLAY_128X64)
- 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_128X64)
- oled_write_P(PSTR(" "), false);
-# endif
-#elif defined(POINTING_DEVICE_ENABLE)
- 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[is_clicky_on && is_audio_on], false);
-# if !defined(OLED_DISPLAY_128X64)
- 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_ENABLE)
- static const char PROGMEM uc_mod_status[5][3] = {{0xEA, 0xEB, 0}, {0xEC, 0xED, 0}};
- oled_write_P(uc_mod_status[get_unicode_input_mode() == UC_MAC], false);
-#endif
- if (userspace_config.nuke_switch) {
-#if !defined(OLED_DISPLAY_128X64)
- 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_128X64)
- oled_advance_page(true);
-#endif
- }
-#if defined(OLED_DISPLAY_128X64)
- oled_advance_page(true);
-#endif
-}
-
-void oled_driver_render_logo(void) {
- // clang-format off
- static const char PROGMEM qmk_logo[] = {
- 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
- 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
- 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
- // clang-format on
- oled_write_P(qmk_logo, false);
-}
-
-void render_wpm(uint8_t padding) {
-#ifdef WPM_ENABLE
- uint8_t n = get_current_wpm();
- char wpm_counter[4];
- wpm_counter[3] = '\0';
- wpm_counter[2] = '0' + n % 10;
- wpm_counter[1] = (n /= 10) % 10 ? '0' + (n) % 10 : (n / 10) % 10 ? '0' : ' ';
- wpm_counter[0] = n / 10 ? '0' + n / 10 : ' ';
- 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(wpm_counter, false);
-#endif
-}
-
-#if defined(KEYBOARD_handwired_tractyl_manuform_5x6_right)
-extern kb_config_data_t kb_config;
-void render_pointing_dpi_status(uint8_t padding) {
- char dpi_status[5];
- uint16_t n = kb_config.device_cpi;
- dpi_status[4] = '\0';
- dpi_status[3] = '0' + n % 10;
- dpi_status[2] = (n /= 10) % 10 ? '0' + (n) % 10 : (n / 10) % 10 ? '0' : ' ';
- dpi_status[1] = (n /= 10) % 10 ? '0' + (n) % 10 : (n / 10) % 10 ? '0' : ' ';
- dpi_status[0] = n / 10 ? '0' + n / 10 : ' ';
- oled_write_P(PSTR("DPI: "), false);
- if (padding) {
- for (uint8_t n = padding; n > 0; n--) {
- oled_write_P(PSTR(" "), false);
- }
- }
- oled_write(dpi_status, false);
-}
-#endif
-
-__attribute__((weak)) void oled_driver_render_logo_right(void) {
-#if defined(OLED_DISPLAY_128X64)
- oled_driver_render_logo();
- render_default_layer_state();
- oled_set_cursor(0, 4);
-#else
- render_default_layer_state();
-#endif
-}
-
-__attribute__((weak)) void oled_driver_render_logo_left(void) {
-#if defined(OLED_DISPLAY_128X64)
- oled_driver_render_logo();
-# ifdef DEBUG_MATRIX_SCAN_RATE
- render_matrix_scan_rate();
-# elif defined(WPM_ENABLE)
- render_wpm(0);
-# endif
- oled_write_P(PSTR(" "), false);
-# if defined(KEYBOARD_handwired_tractyl_manuform_5x6_right)
- render_pointing_dpi_status(1);
-# endif
- oled_set_cursor(0, 4);
-#else
- render_default_layer_state();
-#endif
-}
-
-void render_status_secondary(void) {
- oled_driver_render_logo_right();
- /* Show Keyboard Layout */
- render_layer_state();
- render_mod_status(get_mods() | get_oneshot_mods());
-#if !defined(OLED_DISPLAY_128X64) && defined(WPM_ENABLE) && !defined(CONVERT_TO_PROTON_C)
- render_wpm(2);
-#endif
- // render_keylock_status(host_keyboard_leds());
-}
-
-void render_status_main(void) {
- oled_driver_render_logo_left();
-
- /* Show Keyboard Layout */
- // render_keylock_status(host_keyboard_leds());
- render_bootmagic_status();
- render_user_status();
-
- // render_keylogger_status();
-}
-
-__attribute__((weak)) oled_rotation_t oled_init_keymap(oled_rotation_t rotation) { return rotation; }
-
-oled_rotation_t oled_init_user(oled_rotation_t rotation) {
- memset(keylog_str, ' ', sizeof(keylog_str) - 1);
-
- return oled_init_keymap(rotation);
-}
-
-bool oled_task_user(void) {
- update_log();
-
- if (is_keyboard_master()) {
- if (timer_elapsed32(oled_timer) > 30000) {
- oled_off();
- return false;
- } else {
- oled_on();
- }
- }
- if (is_keyboard_left()) {
- render_status_main(); // Renders the current keyboard state (layer, lock, caps, scroll, etc)
- } else {
- render_status_secondary();
- }
- if (is_keyboard_master()) {
- render_keylogger_status();
- } else {
- render_keylock_status(host_keyboard_leds());
- }
- return false;
-}
diff --git a/users/drashna/pointing/pointing.c b/users/drashna/pointing/pointing.c
new file mode 100644
index 0000000000..0dcfe73f34
--- /dev/null
+++ b/users/drashna/pointing/pointing.c
@@ -0,0 +1,125 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "pointing.h"
+
+static uint16_t mouse_timer = 0;
+static uint16_t mouse_debounce_timer = 0;
+static uint8_t mouse_keycode_tracker = 0;
+bool tap_toggling = false, enable_acceleration = false;
+
+#ifdef TAPPING_TERM_PER_KEY
+# define TAP_CHECK get_tapping_term(KC_BTN1, NULL)
+#else
+# ifndef TAPPING_TERM
+# define TAPPING_TERM 200
+# endif
+# define TAP_CHECK TAPPING_TERM
+#endif
+
+__attribute__((weak)) report_mouse_t pointing_device_task_keymap(report_mouse_t mouse_report) {
+ return mouse_report;
+}
+
+report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
+ int8_t x = mouse_report.x, y = mouse_report.y;
+ mouse_report.x = 0;
+ mouse_report.y = 0;
+
+ if (x != 0 && y != 0) {
+ mouse_timer = timer_read();
+#ifdef OLED_ENABLE
+ oled_timer = timer_read32();
+#endif
+ if (timer_elapsed(mouse_debounce_timer) > TAP_CHECK) {
+ if (enable_acceleration) {
+ x = (x > 0 ? x * x / 16 + x : -x * x / 16 + x);
+ y = (y > 0 ? y * y / 16 + y : -y * y / 16 + y);
+ }
+ mouse_report.x = x;
+ mouse_report.y = y;
+ if (!layer_state_is(_MOUSE)) {
+ layer_on(_MOUSE);
+ }
+ }
+ } else if (timer_elapsed(mouse_timer) > 650 && layer_state_is(_MOUSE) && !mouse_keycode_tracker && !tap_toggling) {
+ layer_off(_MOUSE);
+ } else if (tap_toggling) {
+ if (!layer_state_is(_MOUSE)) {
+ layer_on(_MOUSE);
+ }
+ }
+
+ return pointing_device_task_keymap(mouse_report);
+}
+
+bool process_record_pointing(uint16_t keycode, keyrecord_t* record) {
+ switch (keycode) {
+ case TT(_MOUSE):
+ if (record->event.pressed) {
+ mouse_keycode_tracker++;
+ } else {
+#if TAPPING_TOGGLE != 0
+ if (record->tap.count == TAPPING_TOGGLE) {
+ tap_toggling ^= 1;
+# if TAPPING_TOGGLE == 1
+ if (!tap_toggling) mouse_keycode_tracker -= record->tap.count + 1;
+# else
+ if (!tap_toggling) mouse_keycode_tracker -= record->tap.count;
+# endif
+ } else {
+ mouse_keycode_tracker--;
+ }
+#endif
+ }
+ mouse_timer = timer_read();
+ break;
+ case TG(_MOUSE):
+ if (record->event.pressed) {
+ tap_toggling ^= 1;
+ }
+ break;
+ case MO(_MOUSE):
+#if defined(KEYBOARD_ploopy) || defined(KEYBOARD_handwired_tractyl_manuform)
+ case DPI_CONFIG:
+#elif defined(KEYBOARD_bastardkb_charybdis) && !defined(NO_CHARYBDIS_KEYCODES)
+ case SAFE_RANGE ... (CHARYBDIS_SAFE_RANGE-1):
+#endif
+ case KC_MS_UP ... KC_MS_WH_RIGHT:
+ record->event.pressed ? mouse_keycode_tracker++ : mouse_keycode_tracker--;
+ mouse_timer = timer_read();
+ break;
+ case KC_ACCEL:
+ enable_acceleration = record->event.pressed;
+ record->event.pressed ? mouse_keycode_tracker++ : mouse_keycode_tracker--;
+ mouse_timer = timer_read();
+ break;
+ case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:
+ break;
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ if (record->event.pressed || !record->tap.count) {
+ break;
+ }
+ default:
+ if (IS_NOEVENT(record->event)) break;
+ if ((keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX) && (((keycode >> 0x8) & 0xF) == _MOUSE)) {
+ record->event.pressed ? mouse_keycode_tracker++ : mouse_keycode_tracker--;
+ mouse_timer = timer_read();
+ break;
+ }
+ if (layer_state_is(_MOUSE) && !mouse_keycode_tracker && !tap_toggling) {
+ layer_off(_MOUSE);
+ }
+ mouse_keycode_tracker = 0;
+ mouse_debounce_timer = timer_read();
+ break;
+ }
+ return true;
+}
+
+layer_state_t layer_state_set_pointing(layer_state_t state) {
+ if (layer_state_cmp(state, _GAMEPAD) || layer_state_cmp(state, _DIABLO)) {
+ state |= ((layer_state_t)1 << _MOUSE);
+ }
+ return state;
+}
diff --git a/users/drashna/pointing/pointing.h b/users/drashna/pointing/pointing.h
new file mode 100644
index 0000000000..8b00ffc0ec
--- /dev/null
+++ b/users/drashna/pointing/pointing.h
@@ -0,0 +1,10 @@
+// Copyright 2021 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "drashna.h"
+
+report_mouse_t pointing_device_task_keymap(report_mouse_t mouse_report);
+void matrix_scan_pointing(void);
+bool process_record_pointing(uint16_t keycode, keyrecord_t* record);
+layer_state_t layer_state_set_pointing(layer_state_t state);
+extern bool tap_toggling, enable_acceleration;
diff --git a/users/drashna/pointing/readme.md b/users/drashna/pointing/readme.md
new file mode 100644
index 0000000000..7770755050
--- /dev/null
+++ b/users/drashna/pointing/readme.md
@@ -0,0 +1,19 @@
+# User Pointing Device customization
+
+To disable the customized pointing device code and implement it at the keymap, add `CUSTOM_POINTING_DEVICE = no` to your `rules.mk`.
+
+## Automatic Mouse Layer
+
+Movement on the optical sensor triggers a layer that has all of the mouse keys on that layer. After a set time, the layer will automatically turn itself off after 650ms.
+
+Also, using mousekeys will extend the amount of time that the layer will stay active.
+
+Additionally, layer keys for the mouse layer will lock the layer on.
+
+## Gaming
+
+When the gamepad or diablo layers are enabled, the mouse layer is locked on, as well.
+
+## Keycodes
+
+The only custom keycode for Pointing devices here is `KC_ACCEL`. This allow the mouse report to have an acceleration curve (exponential).
diff --git a/users/drashna/post_config.h b/users/drashna/post_config.h
index b9d934c42b..0c9bda2eeb 100644
--- a/users/drashna/post_config.h
+++ b/users/drashna/post_config.h
@@ -1,18 +1,5 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -137,3 +124,7 @@
#ifndef DYNAMIC_KEYMAP_LAYER_COUNT
# define DYNAMIC_KEYMAP_LAYER_COUNT 11
#endif
+
+#ifndef TAPPING_TERM
+# define TAPPING_TERM 175
+#endif
diff --git a/users/drashna/readme.md b/users/drashna/readme.md
index d98d1d0a6b..e52b67e835 100644
--- a/users/drashna/readme.md
+++ b/users/drashna/readme.md
@@ -2,14 +2,16 @@
This is my personal userspace file. Most of my code exists here, as it's heavily shared.
-* [RGB Customization](readme_rgb.md)
-* [Diablo Tap Dancing](readme_tap_dance.md)
-* [Keymap Wrappers](readme_wrappers.md)
-* [Custom Function Handlers](readme_handlers.md)
-* [Secret Macros](readme_secrets.md)
-* [Custom Keycodes](readme_keycodes.md)
-
-
-## Pro Micro Hacking
-
-See [this thread](https://www.reddit.com/r/olkb/comments/8sxgzb/replace_pro_micro_bootloader_with_qmk_dfu/) for details on how to flash QMK DFU to Pro Micros.
+* [Callback (keymap+misc)](callbacks.md)
+* [Keycode Handling](keyrecords/readme.md)
+ * [Autocorrection](keyrecords/autocorrection/readme.md)
+ * [Cap Words](keyrecords/capwords.md)
+ * [Diablo Tap Dancing](keyrecords/tap_dance.md)
+ * [Keymap Wrappers](keyrecords/wrappers.md)
+ * [Secret Macros](keyrecords/secrets.md)
+ * [Custom Keycodes](keyrecords/keycodes.md)
+ * [Unicode Input](keyrecords/unicode.md)
+* [OLED Display](oled/readme.md)
+* [Pointing Devices](pointing/readme.md)
+* [RGB Customization](rgb/readme.md)
+* [Split Transport](split/readme.md)
diff --git a/users/drashna/readme_handlers.md b/users/drashna/readme_handlers.md
deleted file mode 100644
index 4abaf51473..0000000000
--- a/users/drashna/readme_handlers.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Custom Userspace Function handlers
-
-Specifically QMK works by using customized handlers for everything. This allows for multiple levels of customization.
-
-`matrix_scan` calls `matrix_scan_quantum`, which calls `matrix_scan_kb`, which calls `matrix_scan_user`.
-`process_record` calls a bunch of stuff, but eventually calls `process_record_kb` which calls `process_record_user`
-The same goes for `matrix_init`, `layer_state_set`, `led_set`, and a few other functions.
-
-All (most) `_user` functions are handled here, in the userspace instead. To allow keyboard specific configuration, I've created `_keymap` functions that can be called by the keymap.c files instead.
-
-This allows for keyboard specific configuration while maintaining the ability to customize the board.
-
-My [Ergodox EZ Keymap](https://github.com/qmk/qmk_firmware/blob/master/layouts/community/ergodox/drashna/keymap.c) is a good example of this, as it uses the LEDs as modifier indicators.
-
-But for a list:
-
-```c
-__attribute__ ((weak))
-void matrix_init_keymap(void) {}
-
-void matrix_init_user(void) {
- matrix_init_keymap();
-}
-
-__attribute__((weak))
-void keyboard_post_init_keymap(void){ }
-
-void keyboard_post_init_user(void){
- keyboard_post_init_keymap();
-}
-
-__attribute__ ((weak))
-void matrix_scan_keymap(void) {}
-
-void matrix_scan_user(void) {
- matrix_scan_keymap();
-}
-
-
-__attribute__ ((weak))
-bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
- return true;
-}
-
-bool process_record_user(uint16_t keycode, keyrecord_t *record) {
- return process_record_keymap(keycode, record);
-}
-
-
-__attribute__ ((weak))
-layer_state_t layer_state_set_keymap (layer_state_t state) {
- return state;
-}
-
-layer_state_t layer_state_set_user (layer_state_t state) {
- return layer_state_set_keymap (state);
-}
-
-
-__attribute__ ((weak))
-void led_set_keymap(uint8_t usb_led) {}
-
-void led_set_user(uint8_t usb_led) {
- led_set_keymap(usb_led);
-}
-
-
-__attribute__ ((weak))
-void suspend_power_down_keymap(void) {}
-
-void suspend_power_down_user(void) {
- suspend_power_down_keymap();
-}
-
-
-__attribute__ ((weak))
-void suspend_wakeup_init_keymap(void) {}
-
-void suspend_wakeup_init_user(void) {
- suspend_wakeup_init_keymap();
-}
-
-
-__attribute__ ((weak))
-void shutdown_keymap(void) {}
-
-void shutdown_user (void) {
- shutdown_keymap();
-}
-
-__attribute__ ((weak))
-void eeconfig_init_keymap(void) {}
-
-void eeconfig_init_user(void) {
- eeconfig_init_keymap();
-}
-```
diff --git a/users/drashna/readme_keycodes.md b/users/drashna/readme_keycodes.md
deleted file mode 100644
index af4dd54bc0..0000000000
--- a/users/drashna/readme_keycodes.md
+++ /dev/null
@@ -1,10 +0,0 @@
-
-# Custom Keycodes
-
-Keycodes are defined in the drashna.h file and need to be included in the keymap.c files, so that they can be used there.
-
-A bunch of macros are present and are only included on boards that are not the Ergodox EZ or Orthodox, as they are not needed for those boards.
-
-Included is a custom macro for compiling my keyboards. This includes the bootloader target (`:teensy`, `:avrdude`, or `:dfu`), and keeps RGBLIGHT, AUDIO enabled, if it previously was (regardless of the rules file).
-
-This also includes a modified RESET keycode as well, that sets the underglow to red.
diff --git a/users/drashna/readme_rgb.md b/users/drashna/rgb/readme.md
index acf01b051e..4deaa0a463 100644
--- a/users/drashna/readme_rgb.md
+++ b/users/drashna/rgb/readme.md
@@ -1,4 +1,10 @@
-# Layer Indication Code
+# RGB
+
+Custom RGB code can be disabled by setting `CUSTOM_RGBLIGHT = no` or `CUSTOM_RGB_MATRIX = no` in your `rules.mk`
+
+## RGB Light
+
+### Layer Indication Code
At least for RGB Light, the `layer_state_set` function is used to detect the current highest layer, and change the underglow based on that layer.
@@ -8,7 +14,7 @@ I use the sethsv variants of the commands, so that different modes can be used,
RGB Matrix uses a custom, per board implementation, at the moment.
-# RGB Light Startup Animation
+### RGB Light Startup Animation
On startup, if enabled, the board will cycle through the entire hue wheel, starting and ending on the default layer color.
@@ -33,11 +39,14 @@ void keyboard_post_init_rgb(void) {
This could probably benefit from some cleanup and better handling.
+## RGB Matrix
+
+### Idle Animation
-# RGB Light Twinkling
+This feature can be toggled with the `RGB_IDL` keycode.
-This enables random twinkling of the LEDs when typing.
+This sets the mode to the Heatmap Animation when typing, but will switch to the cycle in animations when idle.
-# RGB Light Mod Indicators
+### Layer Indication
-Allows feedback of which mods (oneshot or otherwise) are enabled.
+This sets the modifier keys to indicate the current layer state, with the option to override the behavior.
diff --git a/users/drashna/rgb/rgb_matrix_stuff.c b/users/drashna/rgb/rgb_matrix_stuff.c
new file mode 100644
index 0000000000..e6d631466d
--- /dev/null
+++ b/users/drashna/rgb/rgb_matrix_stuff.c
@@ -0,0 +1,129 @@
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "drashna.h"
+#include "rgb_matrix.h"
+#include "lib/lib8tion/lib8tion.h"
+extern led_config_t g_led_config;
+
+static uint32_t hypno_timer;
+
+void rgb_matrix_layer_helper(uint8_t hue, uint8_t sat, uint8_t val, uint8_t mode, uint8_t speed, uint8_t led_type, uint8_t led_min, uint8_t led_max) {
+ HSV hsv = {hue, sat, val};
+ if (hsv.v > rgb_matrix_get_val()) {
+ hsv.v = rgb_matrix_get_val();
+ }
+
+ switch (mode) {
+ case 1: // breathing
+ {
+ uint16_t time = scale16by8(g_rgb_timer, speed / 8);
+ hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v);
+ RGB rgb = hsv_to_rgb(hsv);
+ for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
+ if (HAS_FLAGS(g_led_config.flags[i], led_type)) {
+ RGB_MATRIX_INDICATOR_SET_COLOR(i, rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ }
+ default: // Solid Color
+ {
+ RGB rgb = hsv_to_rgb(hsv);
+ for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
+ if (HAS_FLAGS(g_led_config.flags[i], led_type)) {
+ RGB_MATRIX_INDICATOR_SET_COLOR(i, rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ }
+ }
+}
+
+__attribute__((weak)) void rgb_matrix_indicator_keymap(void) {}
+
+void matrix_scan_rgb_matrix(void) {
+#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
+ if (userspace_config.rgb_matrix_idle_anim && rgb_matrix_get_mode() == RGB_MATRIX_TYPING_HEATMAP && sync_timer_elapsed32(hypno_timer) > 15000) {
+ rgb_matrix_mode_noeeprom(RGB_MATRIX_REST_MODE);
+ }
+#endif
+ rgb_matrix_indicator_keymap();
+}
+
+void keyboard_post_init_rgb_matrix(void) {
+#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
+ if (userspace_config.rgb_matrix_idle_anim) {
+ rgb_matrix_mode_noeeprom(RGB_MATRIX_REST_MODE);
+ }
+#endif
+}
+
+bool process_record_user_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
+#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
+ hypno_timer = sync_timer_read32();
+ if (userspace_config.rgb_matrix_idle_anim && rgb_matrix_get_mode() == RGB_MATRIX_REST_MODE) {
+ rgb_matrix_mode_noeeprom(RGB_MATRIX_TYPING_HEATMAP);
+ }
+#endif
+ switch (keycode) {
+ case RGB_IDL: // This allows me to use underglow as layer indication, or as normal
+#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
+ if (record->event.pressed) {
+ userspace_config.rgb_matrix_idle_anim ^= 1;
+ dprintf("RGB Matrix Idle Animation [EEPROM]: %u\n", userspace_config.rgb_matrix_idle_anim);
+ eeconfig_update_user(userspace_config.raw);
+ if (userspace_config.rgb_matrix_idle_anim) {
+ rgb_matrix_mode_noeeprom(RGB_MATRIX_TYPING_HEATMAP);
+ }
+ }
+#endif
+ break;
+ }
+ return true;
+}
+
+__attribute__((weak)) bool rgb_matrix_indicators_advanced_keymap(uint8_t led_min, uint8_t led_max) { return true; }
+void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
+ if (!rgb_matrix_indicators_advanced_keymap(led_min, led_max)) { return; }
+
+#if defined(RGBLIGHT_ENABLE)
+ if (!userspace_config.rgb_layer_change)
+#else
+ if (userspace_config.rgb_layer_change)
+#endif
+ {
+ switch (get_highest_layer(layer_state | default_layer_state)) {
+ case _DEFAULT_LAYER_1:
+ rgb_matrix_layer_helper(DEFAULT_LAYER_1_HSV, 0, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _DEFAULT_LAYER_2:
+ rgb_matrix_layer_helper(DEFAULT_LAYER_2_HSV, 0, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _DEFAULT_LAYER_3:
+ rgb_matrix_layer_helper(DEFAULT_LAYER_3_HSV, 0, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _DEFAULT_LAYER_4:
+ rgb_matrix_layer_helper(DEFAULT_LAYER_4_HSV, 0, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _GAMEPAD:
+ rgb_matrix_layer_helper(HSV_ORANGE, 1, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _DIABLO:
+ rgb_matrix_layer_helper(HSV_RED, 1, rgb_matrix_config.speed * 8, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _RAISE:
+ rgb_matrix_layer_helper(HSV_YELLOW, 1, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _LOWER:
+ rgb_matrix_layer_helper(HSV_GREEN, 1, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ case _ADJUST:
+ rgb_matrix_layer_helper(HSV_RED, 1, rgb_matrix_config.speed, LED_FLAG_MODIFIER, led_min, led_max);
+ break;
+ }
+ }
+}
+
+__attribute__((weak)) bool rgb_matrix_indicators_keymap(void) { return true; }
+void rgb_matrix_indicators_user(void) { rgb_matrix_indicators_keymap(); }
diff --git a/users/drashna/rgb/rgb_matrix_stuff.h b/users/drashna/rgb/rgb_matrix_stuff.h
new file mode 100644
index 0000000000..7c6f6c271e
--- /dev/null
+++ b/users/drashna/rgb/rgb_matrix_stuff.h
@@ -0,0 +1,15 @@
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+#include "quantum.h"
+
+bool process_record_user_rgb_matrix(uint16_t keycode, keyrecord_t *record);
+void keyboard_post_init_rgb_matrix(void);
+void matrix_scan_rgb_matrix(void);
+
+void rgb_matrix_set_color_all(uint8_t red, uint8_t green, uint8_t blue);
+void rgb_matrix_layer_helper(uint8_t hue, uint8_t sat, uint8_t val, uint8_t mode, uint8_t speed, uint8_t led_type, uint8_t led_min, uint8_t led_max);
+
+bool rgb_matrix_indicators_advanced_keymap(uint8_t led_min, uint8_t led_max);
+bool rgb_matrix_indicators_keymap(void);
diff --git a/users/drashna/rgb_stuff.c b/users/drashna/rgb/rgb_stuff.c
index 15108bde04..09071f7151 100644
--- a/users/drashna/rgb_stuff.c
+++ b/users/drashna/rgb/rgb_stuff.c
@@ -1,18 +1,5 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef RGBLIGHT_ENABLE
@@ -36,9 +23,29 @@ static bool is_enabled;
static bool is_rgblight_startup;
static HSV old_hsv;
static uint8_t old_mode;
-static uint16_t rgblight_startup_loop_timer;
+deferred_token rgb_startup_token;
# endif
+uint32_t rgb_startup_animation(uint32_t triger_time, void *cb_arg) {
+ if (is_rgblight_startup && is_keyboard_master()) {
+ static uint8_t counter = 0;
+ counter++;
+ rgblight_sethsv_noeeprom((counter + old_hsv.h) % 255, 255, 255);
+ if (counter >= 255) {
+ is_rgblight_startup = false;
+ if (userspace_config.rgb_layer_change) {
+ layer_state_set_rgb_light(layer_state);
+ } else {
+ rgblight_set_hsv_and_mode(old_hsv.h, old_hsv.s, old_hsv.v, old_mode);
+ }
+ if (!is_enabled) {
+ rgblight_disable_noeeprom();
+ }
+ }
+ }
+ return is_rgblight_startup ? 10 : 0;
+}
+
void keyboard_post_init_rgb_light(void) {
# if defined(RGBLIGHT_STARTUP_ANIMATION)
is_enabled = rgblight_is_enabled();
@@ -53,30 +60,8 @@ void keyboard_post_init_rgb_light(void) {
if (userspace_config.rgb_layer_change) {
layer_state_set_rgb_light(layer_state);
}
-}
+ rgb_startup_token = defer_exec(300, rgb_startup_animation, NULL);
-void matrix_scan_rgb_light(void) {
-# if defined(RGBLIGHT_STARTUP_ANIMATION)
- if (is_rgblight_startup && is_keyboard_master()) {
- if (sync_timer_elapsed(rgblight_startup_loop_timer) > 10) {
- static uint8_t counter;
- counter++;
- rgblight_sethsv_noeeprom((counter + old_hsv.h) % 255, 255, 255);
- rgblight_startup_loop_timer = sync_timer_read();
- if (counter == 255) {
- is_rgblight_startup = false;
- if (userspace_config.rgb_layer_change) {
- layer_state_set_rgb_light(layer_state);
- } else {
- rgblight_set_hsv_and_mode(old_hsv.h, old_hsv.s, old_hsv.v, old_mode);
- }
- if (!is_enabled) {
- rgblight_disable_noeeprom();
- }
- }
- }
- }
-# endif
}
layer_state_t layer_state_set_rgb_light(layer_state_t state) {
diff --git a/users/drashna/rgb/rgb_stuff.h b/users/drashna/rgb/rgb_stuff.h
new file mode 100644
index 0000000000..d720275b60
--- /dev/null
+++ b/users/drashna/rgb/rgb_stuff.h
@@ -0,0 +1,12 @@
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+#include "quantum.h"
+
+bool process_record_user_rgb_light(uint16_t keycode, keyrecord_t *record);
+void keyboard_post_init_rgb_light(void);
+void matrix_scan_rgb_light(void);
+layer_state_t layer_state_set_rgb_light(layer_state_t state);
+layer_state_t default_layer_state_set_rgb_light(layer_state_t state);
+void rgblight_sethsv_default_helper(uint8_t index);
diff --git a/users/drashna/rgb_matrix_stuff.c b/users/drashna/rgb_matrix_stuff.c
deleted file mode 100644
index 97811092c1..0000000000
--- a/users/drashna/rgb_matrix_stuff.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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"
-#include "rgb_matrix.h"
-#include "lib/lib8tion/lib8tion.h"
-extern led_config_t g_led_config;
-
-static uint32_t hypno_timer;
-
-void rgb_matrix_layer_helper(uint8_t hue, uint8_t sat, uint8_t val, uint8_t mode, uint8_t speed, uint8_t led_type, uint8_t led_min, uint8_t led_max) {
- HSV hsv = {hue, sat, val};
- if (hsv.v > rgb_matrix_get_val()) {
- hsv.v = rgb_matrix_get_val();
- }
-
- switch (mode) {
- case 1: // breathing
- {
- uint16_t time = scale16by8(g_rgb_timer, speed / 8);
- hsv.v = scale8(abs8(sin8(time) - 128) * 2, hsv.v);
- RGB rgb = hsv_to_rgb(hsv);
- for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
- if (HAS_FLAGS(g_led_config.flags[i], led_type)) {
- RGB_MATRIX_INDICATOR_SET_COLOR(i, rgb.r, rgb.g, rgb.b);
- }
- }
- break;
- }
- default: // Solid Color
- {
- RGB rgb = hsv_to_rgb(hsv);
- for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
- if (HAS_FLAGS(g_led_config.flags[i], led_type)) {
- RGB_MATRIX_INDICATOR_SET_COLOR(i, rgb.r, rgb.g, rgb.b);
- }
- }
- break;
- }
- }
-}
-
-__attribute__((weak)) void rgb_matrix_indicator_keymap(void) {}
-
-void matrix_scan_rgb_matrix(void) {
-#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
- if (userspace_config.rgb_matrix_idle_anim && rgb_matrix_get_mode() == RGB_MATRIX_TYPING_HEATMAP && sync_timer_elapsed32(hypno_timer) > 15000) {
- rgb_matrix_mode_noeeprom(RGB_MATRIX_REST_MODE);
- }
-#endif
- rgb_matrix_indicator_keymap();
-}
-
-void keyboard_post_init_rgb_matrix(void) {
-#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
- if (userspace_config.rgb_matrix_idle_anim) {
- rgb_matrix_mode_noeeprom(RGB_MATRIX_REST_MODE);
- }
-#endif
-}
-
-bool process_record_user_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
-#if defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
- hypno_timer = sync_timer_read32();
- if (userspace_config.rgb_matrix_idle_anim && rgb_matrix_get_mode() == RGB_MATRIX_REST_MODE) {
- rgb_matrix_mode_noeeprom(RGB_MATRIX_TYPING_HEATMAP);
- }
-#endif
- switch (keycode) {
- case RGB_IDL: // This allows me to use underglow as layer indication, or as normal
-#if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_FRAMEBUFFER_EFFECTS)
- if (record->event.pressed) {
- userspace_config.rgb_matrix_idle_anim ^= 1;
- dprintf("RGB Matrix Idle Animation [EEPROM]: %u\n", userspace_config.rgb_matrix_idle_anim);
- eeconfig_update_user(userspace_config.raw);
- if (userspace_config.rgb_matrix_idle_anim) {
- rgb_matrix_mode_noeeprom(RGB_MATRIX_TYPING_HEATMAP);
- }
- }
-#endif
- break;
- }
- return true;
-}
diff --git a/users/drashna/rgblight_breathe_table.h b/users/drashna/rgblight_breathe_table.h
index b6f7a13ac1..d406395978 100644
--- a/users/drashna/rgblight_breathe_table.h
+++ b/users/drashna/rgblight_breathe_table.h
@@ -1,18 +1,5 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef RGBLIGHT_EFFECT_BREATHE_TABLE
#define RGBLIGHT_EFFECT_BREATHE_TABLE
diff --git a/users/drashna/rules.mk b/users/drashna/rules.mk
index e9911979c7..4bc71b6939 100644
--- a/users/drashna/rules.mk
+++ b/users/drashna/rules.mk
@@ -1,5 +1,7 @@
SRC += $(USER_PATH)/drashna.c \
- $(USER_PATH)/process_records.c
+ $(USER_PATH)/callbacks.c \
+ $(USER_PATH)/keyrecords/process_records.c \
+ $(USER_PATH)/keyrecords/tapping.c
ifneq ($(PLATFORM),CHIBIOS)
ifneq ($(strip $(LTO_SUPPORTED)), no)
@@ -8,32 +10,55 @@ ifneq ($(PLATFORM),CHIBIOS)
endif
SPACE_CADET_ENABLE = no
GRAVE_ESC_ENABLE = no
+# DEBUG_MATRIX_SCAN_RATE_ENABLE = api
ifneq ($(strip $(NO_SECRETS)), yes)
- ifneq ("$(wildcard $(USER_PATH)/secrets.c)","")
- SRC += $(USER_PATH)/secrets.c
+ ifneq ("$(wildcard $(USER_PATH)/keyrecords/secrets.c)","")
+ SRC += $(USER_PATH)/keyrecords/secrets.c
endif
ifeq ($(strip $(NO_SECRETS)), lite)
OPT_DEFS += -DNO_SECRETS
endif
endif
+ifeq ($(strip $(MAKE_BOOTLOADER)), yes)
+ OPT_DEFS += -DMAKE_BOOTLOADER
+endif
+
+# At least until build.mk or the like drops, this is here to prevent
+# VUSB boards from enabling NKRO, as they do not support it. Ideally
+# this should be handled per keyboard, but until that happens ...
+ifeq ($(strip $(PROTOCOL)), VUSB)
+ NKRO_ENABLE := no
+endif
+
+CUSTOM_UNICODE_ENABLE ?= yes
+ifeq ($(strip $(CUSTOM_UNICODE_ENABLE)), yes)
+ UNICODE_ENABLE := no
+ UNICODEMAP_ENABLE := no
+ UCIS_ENABLE := no
+ UNICODE_COMMON := yes
+ OPT_DEFS += -DCUSTOM_UNICODE_ENABLE
+ SRC += $(USER_PATH)/keyrecords/unicode.c
+endif
+
CUSTOM_TAP_DANCE ?= yes
-ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
+ifeq ($(strip $(CUSTOM_TAP_DANCE)), yes)
ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
- SRC += $(USER_PATH)/tap_dances.c
+ SRC += $(USER_PATH)/keyrecords/tap_dances.c
endif
endif
CUSTOM_RGBLIGHT ?= yes
ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
ifeq ($(strip $(CUSTOM_RGBLIGHT)), yes)
- SRC += $(USER_PATH)/rgb_stuff.c
+ SRC += $(USER_PATH)/rgb/rgb_stuff.c
ifeq ($(strip $(RGBLIGHT_NOEEPROM)), yes)
OPT_DEFS += -DRGBLIGHT_NOEEPROM
endif
ifeq ($(strip $(RGBLIGHT_STARTUP_ANIMATION)), yes)
OPT_DEFS += -DRGBLIGHT_STARTUP_ANIMATION
+ DEFERRED_EXEC_ENABLE = yes
endif
endif
endif
@@ -41,7 +66,7 @@ endif
CUSTOM_RGB_MATRIX ?= yes
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
ifeq ($(strip $(CUSTOM_RGB_MATRIX)), yes)
- SRC += $(USER_PATH)/rgb_matrix_stuff.c
+ SRC += $(USER_PATH)/rgb/rgb_matrix_stuff.c
endif
endif
@@ -52,38 +77,48 @@ ifdef CONSOLE_ENABLE
endif
endif
-ifeq ($(strip $(MAKE_BOOTLOADER)), yes)
- OPT_DEFS += -DMAKE_BOOTLOADER
-endif
-
-# At least until build.mk or the like drops, this is here to prevent
-# VUSB boards from enabling NKRO, as they do not support it. Ideally
-# this should be handled per keyboard, but until that happens ...
-ifeq ($(strip $(PROTOCOL)), VUSB)
- NKRO_ENABLE = no
-endif
-
CUSTOM_OLED_DRIVER ?= yes
ifeq ($(strip $(OLED_ENABLE)), yes)
+ ifeq ($(strip $(OLED_DRIVER)), custom)
+ OPT_DEFS += -DOLED_ENABLE \
+ -DOLED_DRIVER_SH1107
+ SRC += $(USER_PATH)/oled/sh110x.c
+ QUANTUM_LIB_SRC += i2c_master.c
+ endif
ifeq ($(strip $(CUSTOM_OLED_DRIVER)), yes)
- SRC += $(USER_PATH)/oled_stuff.c
OPT_DEFS += -DCUSTOM_OLED_DRIVER_CODE
+ SRC += $(USER_PATH)/oled/oled_stuff.c
endif
+ ifeq ($(strip $(OLED_DISPLAY_TEST)), yes)
+ OPT_DEFS += -DOLED_DISPLAY_TEST
+ endif
+ DEFERRED_EXEC_ENABLE = yes
endif
-ifeq ($(strip $(PIMORONI_TRACKBALL_ENABLE)), yes)
- POINTING_DEVICE_ENABLE := yes
- OPT_DEFS += -DPIMORONI_TRACKBALL_ENABLE
- SRC += drivers/sensors/pimoroni_trackball.c
- QUANTUM_LIB_SRC += i2c_master.c
+CUSTOM_POINTING_DEVICE ?= yes
+ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
+ ifeq ($(strip $(CUSTOM_POINTING_DEVICE)), yes)
+ SRC += $(USER_PATH)/pointing/pointing.c
+ endif
endif
CUSTOM_SPLIT_TRANSPORT_SYNC ?= yes
ifeq ($(strip $(CUSTOM_SPLIT_TRANSPORT_SYNC)), yes)
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
- QUANTUM_LIB_SRC += $(USER_PATH)/transport_sync.c
+ QUANTUM_LIB_SRC += $(USER_PATH)/split/transport_sync.c
OPT_DEFS += -DCUSTOM_SPLIT_TRANSPORT_SYNC
endif
+
endif
-# DEBUG_MATRIX_SCAN_RATE_ENABLE = api
+AUTOCORRECTION_ENABLE ?= no
+ifeq ($(strip $(AUTOCORRECTION_ENABLE)), yes)
+ SRC += $(USER_PATH)/keyrecords/autocorrection/autocorrection.c
+ OPT_DEFS += -DAUTOCORRECTION_ENABLE
+endif
+
+CAPS_WORD_ENABLE ?= no
+ifeq ($(strip $(CAPS_WORD_ENABLE)), yes)
+ SRC += $(USER_PATH)/keyrecords/caps_word.c
+ OPT_DEFS += -DCAPS_WORD_ENABLE
+endif
diff --git a/users/drashna/split/readme.md b/users/drashna/split/readme.md
new file mode 100644
index 0000000000..5dad340122
--- /dev/null
+++ b/users/drashna/split/readme.md
@@ -0,0 +1,29 @@
+# Custom Split Transport
+
+To disable the customized split transport, add `CUSTOM_SPLIT_TRANSPORT_SYNC = no` to your `rules.mk`.
+
+This syncs a number of additional settings, such as the keymap_config (magic settings), user eeprom configs, and misc firmware settings.
+
+Additionally, this supports a watchdog timer reset for the secondary split side.
+
+## User State Config
+
+The User states that it sync are:
+
+* Audio Enable status
+* Audio Clicky states
+* Unicode mode
+* Pointing Device tap toggle status
+* Swap Hands status
+* Host Driver status
+
+## Userspace Config
+
+The userspace config states that are synced are:
+
+* RGB layer indication
+* "is overwatch" status
+* nuke switch
+* Swapped numbers
+* RGB Matrix idle animation
+* Autocorrect enable status
diff --git a/users/drashna/transport_sync.c b/users/drashna/split/transport_sync.c
index daa14bbef7..4c113ec257 100644
--- a/users/drashna/transport_sync.c
+++ b/users/drashna/split/transport_sync.c
@@ -1,24 +1,15 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#include "transport_sync.h"
#include "transactions.h"
#include <string.h>
+#ifdef __AVR__
+# include <avr/wdt.h>
+#endif
-#ifdef UNICODE_ENABLE
+#ifdef UNICODE_COMMON_ENABLE
+# include "process_unicode_common.h"
extern unicode_config_t unicode_config;
#endif
#ifdef AUDIO_ENABLE
@@ -32,6 +23,12 @@ extern bool tap_toggling;
#ifdef SWAP_HANDS_ENABLE
extern bool swap_hands;
#endif
+
+#if defined(SPLIT_WATCHDOG_TIMEOUT)
+static bool watchdog_ping_done = false;
+static uint32_t watchdog_timer = 0;
+#endif
+
extern userspace_config_t userspace_config;
extern bool host_driver_disabled;
@@ -56,11 +53,35 @@ void user_config_sync(uint8_t initiator2target_buffer_size, const void* initiato
}
}
+#if defined(SPLIT_WATCHDOG_TIMEOUT)
+void watchdog_handler(uint8_t in_buflen, const void* in_data, uint8_t out_buflen, void* out_data) { watchdog_ping_done = true; }
+#endif
+
+#ifdef OLED_ENABLE
+# include "oled/oled_stuff.h"
+void keylogger_string_sync(uint8_t initiator2target_buffer_size, const void* initiator2target_buffer, uint8_t target2initiator_buffer_size, void* target2initiator_buffer) {
+ if (initiator2target_buffer_size == OLED_KEYLOGGER_LENGTH) {
+ memcpy(&keylog_str, initiator2target_buffer, initiator2target_buffer_size);
+ }
+}
+#endif
+
void keyboard_post_init_transport_sync(void) {
// Register keyboard state sync split transaction
transaction_register_rpc(RPC_ID_USER_STATE_SYNC, user_state_sync);
transaction_register_rpc(RPC_ID_USER_KEYMAP_SYNC, user_keymap_sync);
transaction_register_rpc(RPC_ID_USER_CONFIG_SYNC, user_config_sync);
+#ifdef OLED_ENABLE
+ transaction_register_rpc(RPC_ID_USER_KEYLOG_STR, keylogger_string_sync);
+#endif
+
+#if defined(SPLIT_WATCHDOG_TIMEOUT)
+# if defined(PROTOCOL_LUFA)
+ wdt_disable();
+# endif
+ transaction_register_rpc(RPC_ID_USER_WATCHDOG_SYNC, watchdog_handler);
+ watchdog_timer = timer_read32();
+#endif
}
void user_transport_update(void) {
@@ -74,7 +95,7 @@ void user_transport_update(void) {
#if defined(POINTING_DEVICE_ENABLE) && defined(KEYBOARD_handwired_tractyl_manuform)
user_state.tap_toggling = tap_toggling;
#endif
-#ifdef UNICODE_ENABLE
+#ifdef UNICODE_COMMON_ENABLE
user_state.unicode_mode = unicode_config.input_mode;
#endif
#ifdef SWAP_HANDS_ENABLE
@@ -87,7 +108,7 @@ void user_transport_update(void) {
keymap_config.raw = transport_keymap_config;
userspace_config.raw = transport_userspace_config;
user_state.raw = transport_user_state;
-#ifdef UNICODE_ENABLE
+#ifdef UNICODE_COMMON_ENABLE
unicode_config.input_mode = user_state.unicode_mode;
#endif
#if defined(POINTING_DEVICE_ENABLE) && defined(KEYBOARD_handwired_tractyl_manuform)
@@ -103,9 +124,12 @@ void user_transport_update(void) {
void user_transport_sync(void) {
if (is_keyboard_master()) {
// Keep track of the last state, so that we can tell if we need to propagate to slave
- static uint16_t last_keymap = 0;
- static uint32_t last_config = 0, last_sync[3], last_user_state = 0;
- bool needs_sync = false;
+ static uint16_t last_keymap = 0;
+ static uint32_t last_config = 0, last_sync[4], last_user_state = 0;
+ bool needs_sync = false;
+#ifdef OLED_ENABLE
+ static char keylog_temp[OLED_KEYLOGGER_LENGTH] = {0};
+#endif
// Check if the state values are different
if (memcmp(&transport_user_state, &last_user_state, sizeof(transport_user_state))) {
@@ -160,8 +184,50 @@ void user_transport_sync(void) {
if (transaction_rpc_send(RPC_ID_USER_CONFIG_SYNC, sizeof(transport_userspace_config), &transport_userspace_config)) {
last_sync[2] = timer_read32();
}
+ needs_sync = false;
+ }
+
+#ifdef OLED_ENABLE
+ // Check if the state values are different
+ if (memcmp(&keylog_str, &keylog_temp, OLED_KEYLOGGER_LENGTH)) {
+ needs_sync = true;
+ memcpy(&keylog_temp, &keylog_str, OLED_KEYLOGGER_LENGTH);
+ }
+ if (timer_elapsed32(last_sync[3]) > 250) {
+ needs_sync = true;
+ }
+
+ // Perform the sync if requested
+ if (needs_sync) {
+ if (transaction_rpc_send(RPC_ID_USER_KEYLOG_STR, OLED_KEYLOGGER_LENGTH, &keylog_str)) {
+ last_sync[3] = timer_read32();
+ }
+ needs_sync = false;
+ }
+#endif
+ }
+
+#if defined(SPLIT_WATCHDOG_TIMEOUT)
+ if (!watchdog_ping_done) {
+ if (is_keyboard_master()) {
+ if (timer_elapsed32(watchdog_timer) > 100) {
+ uint8_t any_data = 1;
+ if (transaction_rpc_send(RPC_ID_USER_WATCHDOG_SYNC, sizeof(any_data), &any_data)) {
+ watchdog_ping_done = true; // successful ping
+ } else {
+ dprint("Watchdog ping failed!\n");
+ }
+ watchdog_timer = timer_read32();
+ }
+ } else {
+ if (timer_elapsed32(watchdog_timer) > 3500) {
+ software_reset();
+ while (1) {
+ }
+ }
}
}
+#endif
}
void housekeeping_task_user(void) {
diff --git a/users/drashna/split/transport_sync.h b/users/drashna/split/transport_sync.h
new file mode 100644
index 0000000000..f38fdcf1ef
--- /dev/null
+++ b/users/drashna/split/transport_sync.h
@@ -0,0 +1,26 @@
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "drashna.h"
+#ifdef OLED_ENABLE
+# include "oled/oled_stuff.h"
+extern char keylog_str[OLED_KEYLOGGER_LENGTH];
+#endif
+
+typedef union {
+ uint32_t raw;
+ struct {
+ bool audio_enable :1;
+ bool audio_clicky_enable :1;
+ bool tap_toggling :1;
+ uint8_t unicode_mode :3;
+ bool swap_hands :1;
+ bool host_driver_disabled :1;
+ };
+} user_runtime_config_t;
+
+extern user_runtime_config_t user_state;
+
+void keyboard_post_init_transport_sync(void);
diff --git a/users/drashna/tap_dances.h b/users/drashna/tap_dances.h
deleted file mode 100644
index 81e462ce29..0000000000
--- a/users/drashna/tap_dances.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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
-#include "drashna.h"
-
-// define diablo macro timer variables
-extern uint8_t diablo_times[];
-typedef struct {
- uint16_t timer;
- uint8_t key_interval;
- uint8_t keycode;
-} diablo_timer_t;
-
-typedef struct {
- uint8_t index;
- uint8_t keycode;
-} diable_keys_t;
-
-extern diablo_timer_t diablo_timer[];
-
-void run_diablo_macro_check(void);
-
-#ifdef TAP_DANCE_ENABLE
-enum {
- TD_D3_1 = 0,
- TD_D3_2,
- TD_D3_3,
- TD_D3_4,
-};
-#endif // TAP_DANCE_ENABLE
diff --git a/users/drashna/template.c b/users/drashna/template.c
index f98964ae4f..c4a62c6448 100644
--- a/users/drashna/template.c
+++ b/users/drashna/template.c
@@ -1,18 +1,5 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#include "template.h"
diff --git a/users/drashna/template.h b/users/drashna/template.h
index cb1ad75d8a..26ac98edb9 100644
--- a/users/drashna/template.h
+++ b/users/drashna/template.h
@@ -1,18 +1,5 @@
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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/>.
- */
+// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
+// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
diff --git a/users/drashna/transport_sync.h b/users/drashna/transport_sync.h
deleted file mode 100644
index 70b6ea522b..0000000000
--- a/users/drashna/transport_sync.h
+++ /dev/null
@@ -1,36 +0,0 @@
-
-/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
- *
- * 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
-
-#include "drashna.h"
-
-typedef union {
- uint32_t raw;
- struct {
- bool audio_enable :1;
- bool audio_clicky_enable :1;
- bool tap_toggling :1;
- bool unicode_mode :1;
- bool swap_hands :1;
- bool host_driver_disabled :1;
- };
-} user_runtime_config_t;
-
-extern user_runtime_config_t user_state;
-
-void keyboard_post_init_transport_sync(void);
diff --git a/users/ericgebhart/altlocal_keys.c b/users/ericgebhart/altlocal_keys.c
new file mode 100755
index 0000000000..285041b418
--- /dev/null
+++ b/users/ericgebhart/altlocal_keys.c
@@ -0,0 +1,94 @@
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "ericgebhart.h"
+#include "altlocal_keys.h"
+
+#include "keymap_bepo.h"
+
+// These are the keys for dvorak on bepo. column one is the keycode and mods for
+// the unshifted key, the second column is the keycode and mods for the shifted key.
+// GR is Good Range. It subtracts SAFE_RANGE from the keycode so we can make a
+// reasnably sized array without difficulties. The macro is for the constant declarations
+// the function is for when we use it.
+const uint16_t key_translations[][2][2] = {
+ [GR(DB_1)] = {{BP_DQUO, MOD_LSFT}, {BP_DCIR, MOD_LSFT}},
+ [GR(DB_2)] = {{BP_LDAQ, MOD_LSFT}, {BP_AT, MOD_NONE}},
+ [GR(DB_3)] = {{BP_RDAQ, MOD_LSFT}, {BP_DLR, MOD_LSFT}},
+ [GR(DB_4)] = {{BP_LPRN, MOD_LSFT}, {BP_DLR, MOD_NONE}},
+ [GR(DB_5)] = {{BP_RPRN, MOD_LSFT}, {BP_PERC, MOD_NONE}},
+ [GR(DB_6)] = {{BP_AT, MOD_LSFT}, {BP_AT, MOD_BIT(KC_RALT)}},
+ [GR(DB_7)] = {{BP_PLUS, MOD_LSFT}, {BP_P, MOD_BIT(KC_RALT)}},
+ [GR(DB_8)] = {{BP_MINS, MOD_LSFT}, {BP_ASTR, MOD_NONE}},
+ [GR(DB_9)] = {{BP_SLSH, MOD_LSFT}, {BP_LPRN, MOD_NONE}},
+ [GR(DB_0)] = {{BP_ASTR, MOD_LSFT}, {BP_RPRN, MOD_NONE}},
+ [GR(DB_GRV)] = {{BP_PERC, MOD_LSFT}, {BP_K, MOD_BIT(KC_RALT)}},
+ [GR(DB_SCOLON)] = {{BP_COMM, MOD_LSFT}, {BP_DOT, MOD_LSFT}},
+ [GR(DB_SLASH)] = {{BP_SLSH, MOD_NONE}, {BP_QUOT, MOD_LSFT}},
+ [GR(DB_BACKSLASH)] = {{BP_AGRV, MOD_BIT(KC_RALT)}, {BP_B, MOD_BIT(KC_RALT)}},
+ [GR(DB_EQL)] = {{BP_EQL, MOD_NONE}, {BP_PLUS, MOD_NONE}},
+ [GR(DB_COMM)] = {{BP_COMM, MOD_NONE}, {BP_LDAQ, MOD_BIT(KC_RALT)}},
+ [GR(DB_DOT)] = {{BP_DOT, MOD_NONE}, {BP_RDAQ, MOD_BIT(KC_RALT)}},
+ [GR(DB_QUOT)] = {{BP_QUOT, MOD_NONE}, {BP_DQUO, MOD_NONE}},
+ [GR(DB_MINUS)] = {{BP_MINS, MOD_NONE}, {KC_SPC, MOD_BIT(KC_RALT)}},
+ [GR(DB_LPRN)] = {{BP_LPRN, MOD_NONE}, {BP_LPRN, MOD_BIT(KC_RALT)}},
+ [GR(DB_RPRN)] = {{BP_RPRN, MOD_NONE}, {BP_RPRN, MOD_BIT(KC_RALT)}},
+ [GR(DB_LBRC)] = {{BP_Y, MOD_BIT(KC_RALT)}, {BP_LPRN, MOD_BIT(KC_RALT)}},
+ [GR(DB_RBRC)] = {{BP_X, MOD_BIT(KC_RALT)}, {BP_RPRN, MOD_BIT(KC_RALT)}},
+ // For the symbol layer
+ [GR(DB_HASH)] = {{BP_DLR, MOD_LSFT}, {BP_DLR, MOD_LSFT}},
+ [GR(DB_LCBR)] = {{BP_LPRN, MOD_BIT(KC_RALT)}, {BP_LPRN, MOD_BIT(KC_RALT)}},
+ [GR(DB_RCBR)] = {{BP_LPRN, MOD_BIT(KC_RALT)}, {BP_RPRN, MOD_BIT(KC_RALT)}},
+ [GR(DB_PIPE)] = {{BP_B, MOD_BIT(KC_RALT)}, {BP_B, MOD_BIT(KC_RALT)}},
+ [GR(DB_TILD)] = {{BP_K, MOD_BIT(KC_RALT)}, {BP_K, MOD_BIT(KC_RALT)}},
+ [GR(DB_CIRC)] = {{BP_AT, MOD_BIT(KC_RALT)}, {BP_AT, MOD_BIT(KC_RALT)}},
+ [GR(DB_LESS)] = {{BP_LDAQ, MOD_BIT(KC_RALT)}, {BP_LDAQ, MOD_BIT(KC_RALT)}},
+ [GR(DB_GRTR)] = {{BP_RDAQ, MOD_BIT(KC_RALT)}, {BP_RDAQ, MOD_BIT(KC_RALT)}},
+ // Keys for BEAKL on Qwerty
+ [GR(BQ_COMM)] = {{KC_COMMA, MOD_NONE}, {KC_1, MOD_LSFT}},
+ [GR(BQ_DOT)] = {{KC_DOT, MOD_NONE}, {KC_2, MOD_LSFT}},
+ [GR(BQ_QUOT)] = {{KC_QUOT, MOD_NONE}, {KC_GRV, MOD_NONE}},
+};
+
+
+uint8_t gr(uint16_t kc){
+ return (kc - SAFE_RANGE);
+}
+// send the right keycode for the right mod.
+// remove the mods we are taking care of,
+// send our keycodes then restore them.
+// all so we can make dvorak keys from bepo keycodes.
+void send_keycode(uint16_t kc){
+ uint8_t tmp_mods = get_mods();
+ bool is_shifted = ( tmp_mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) );
+ //uint8_t key[2][2] = key_translations[GR(kc)];
+ // need to turn of the shift if it is on.
+ unregister_mods((MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)));
+ if(is_shifted){
+ register_mods(SHIFTED_MODS(kc));
+ register_code(SHIFTED_KEY(kc));
+ unregister_code(SHIFTED_KEY(kc));
+ unregister_mods(SHIFTED_MODS(kc));
+ } else{
+ register_mods(UNSHIFTED_MODS(kc));
+ register_code(UNSHIFTED_KEY(kc));
+ unregister_code(UNSHIFTED_KEY(kc));
+ unregister_mods(UNSHIFTED_MODS(kc));
+ }
+ clear_mods();
+ register_mods(tmp_mods);
+}
diff --git a/users/ericgebhart/altlocal_keys.h b/users/ericgebhart/altlocal_keys.h
new file mode 100644
index 0000000000..b7fa977b92
--- /dev/null
+++ b/users/ericgebhart/altlocal_keys.h
@@ -0,0 +1,36 @@
+#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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/>.
+*/
+
+// for the creation of dvorak keys on an Bepo keyboard at the OS layer.
+// so we can create an array of reasonable size
+// for our translation keys. We have to create a
+// good range of numbers
+#define GR(x) (x-SAFE_RANGE)
+
+// void tap(uint16_t keycode){ register_code(keycode); unregister_code(keycode); };
+
+uint8_t gr(uint16_t);
+void send_keycode(uint16_t);
+
+#define MOD_NONE 0x00
+
+// indexs for the keycode translation table.
+#define UNSHIFTED_KEY(key) key_translations[gr(key)][0][0]
+#define UNSHIFTED_MODS(key) key_translations[gr(key)][0][1]
+#define SHIFTED_KEY(key) key_translations[gr(key)][1][0]
+#define SHIFTED_MODS(key) key_translations[gr(key)][1][1]
diff --git a/users/ericgebhart/base_layers.h b/users/ericgebhart/base_layers.h
deleted file mode 100644
index fd88a40aef..0000000000
--- a/users/ericgebhart/base_layers.h
+++ /dev/null
@@ -1,283 +0,0 @@
-#pragma once
-/*
- Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
-
- 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 "core_keysets.h"
-
-/******************************************************************/
-/* These are the keys for the middle and bottom edge of any layout*/
-/* That way we only need to set them once and use them everywhere */
-/* The thumb keys, the bottom rows, etc. */
-/******************************************************************/
-/******************************************************************/
-/* Middle Keysets for the XD75 */
-/******************************************************************/
-
-// For the middle keys of an xd75. It's got one more column in the middle than
-// the ergodox, or the viterbi. And the Ergodox is missing a key in column 7
-// counting from either end. Which is the first and 3rd columns of these sets.
-
-// it's all an experient. I'm not sure what make sense here.
-// stealing what I can from the ergodox layout.
-/* The XD75 has 3 keys inbetween the usual left and right hand */
-#define ___ORTHO_15_MIDDLE_T___ OSL(LAYERS), LCTL(KC_A), MDIA_SYMB_KP_LAYERS
-#define ___ORTHO_15_MIDDLE_1___ LCTL(KC_C), LCTL(KC_X), LCTL(KC_V)
-#define ___ORTHO_15_MIDDLE_2___ TO(SYMB), TO(_RGB), TO(KEYPAD)
-#define ___ORTHO_15_MIDDLE_3___ OSL(SYMB), TO(MDIA), OSL(KEYPAD)
-#define ___ORTHO_15_MIDDLE_4___ CTL_BSPC, ALT_DEL, XMONAD_ESC, ALT_ENT, CTL_SPC
-
-// The same, for BEPO
-#define ___ORTHO_15_MIDDLE_T_BP___ OSL(LAYERS), LCTL(BP_A), MDIA_SYMB_KP_LAYERS
-#define ___ORTHO_15_MIDDLE_1_BP___ LCTL(BP_C), LCTL(BP_X), LCTL(BP_V)
-#define ___ORTHO_15_MIDDLE_2_BP___ TO(SYMB_ON_BEPO), TO(_RGB), TO(KEYPAD_ON_BEPO)
-#define ___ORTHO_15_MIDDLE_3_BP___ OSL(SYMB_ON_BEPO), TO(MDIA), OSL(KEYPAD_ON_BEPO)
-
-// The Viterbi only has 2 keys in the middle.
-#define ___ORTHO_14_MIDDLE_T___ OSL(LAYERS), MDIA_SYMB_KP_LAYERS
-#define ___ORTHO_14_MIDDLE_1___ LCTL(KC_C), LCTL(KC_V)
-#define ___ORTHO_14_MIDDLE_2___ TO(SYMB), TO(KEYPAD)
-#define ___ORTHO_14_MIDDLE_3___ OSL(SYMB), OSL(KEYPAD)
-
-// becomes the upper thumbs, the real 4th row if we throw away
-// the number row at the top
-#define ___ORTHO_14_MIDDLE_4___ LSFT(KC_TAB), HOME_END, KC_PGDN, KC_TAB
-// basically the thumb keys like on the ergodox.
-#define ___MIDDLE_THUMBS___ CTL_BSPC, ALT_DEL, XMONAD_ESC, KC_PGDN, ALT_ENT, CTL_SPC
-
-// The same, for BEPO
-#define ___ORTHO_14_MIDDLE_T_BP___ OSL(LAYERS), MDIA_SYMB_KP_LAYERS
-#define ___ORTHO_14_MIDDLE_1_BP___ LCTL(BP_C), LCTL(BP_V)
-#define ___ORTHO_14_MIDDLE_2_BP___ TO(SYMB_ON_BEPO), TO(KEYPAD_ON_BEPO)
-#define ___ORTHO_14_MIDDLE_3_BP___ OSL(SYMB_ON_BEPO), OSL(KEYPAD_ON_BEPO)
-
-#define ___ORTHO_14_MIDDLE_4_BP___ LSFT(KC_TAB), HOME_END, KC_PGUP, KC_TAB
-
-
-/********************************************************************/
-/** The top rows for numbers, symbols and Fkeys. **/
-/********************************************************************/
-#define ___ORTHO_15_N___ ___NUMBER_L___, ___ORTHO_15_MIDDLE_T___, ___NUMBER_R___
-#define ___ORTHO_15_B_N___ ___NUMBER_BEPO_L___, ___ORTHO_15_MIDDLE_T_BP___, ___NUMBER_BEPO_R___
-// the full bepo symbol row.
-#define ___ORTHO_15_B_SYMB___ BP_DLR, ___SYMBOL_BEPO_L___, ___ORTHO_15_MIDDLE_T_BP___, ___SYMBOL_BEPO_R___, BP_EQL
-
-// transparent in the middle because I only put this on transient layers.
-#define ___ORTHO_15_FUNC_1_12___ ___FUNC_1_6___, ___3___, ___FUNC_7_12___
-
-
-/********************************************************************/
-/** The bottom row and thumbs as needed. **/
-/********************************************************************/
-#define ___BOTTOM_LEFT___ LCTL(KC_C), LCTL(KC_V), KC_INS, KC_LEFT, KC_RIGHT
-#define ___BOTTOM_RIGHT___ KC_UP, KC_DOWN, KC_BSLASH, LCTL(KC_V), LCTL(KC_C)
-
-// the bottom rows for keyboards on bepo.
-// bepo on bepo - not enough space to go around....
-#define ___BOTTOM_LEFT_BP___ LCTL(BP_C), BP_ECIR, LCTL(BP_V), KC_LEFT, KC_RIGHT
-#define ___BOTTOM_RIGHT_BP___ KC_UP, KC_DOWN, DB_BACKSLASH, BP_CCED, BP_PERC
-
-// for dvorak on bepo
-#define ___BOTTOM_LEFT_FR___ LCTL(BP_C), LCTL(BP_C), LCTL(BP_V), KC_LEFT, KC_RIGHT
-#define ___BOTTOM_RIGHT_FR___ KC_UP, KC_DOWN, DB_BACKSLASH, LCTL(KC_V), LCTL(KC_C)
-
-#define ___ORTHO_15_BOTTOM___ ___BOTTOM_LEFT___, ___ORTHO_15_MIDDLE_4___, ___BOTTOM_RIGHT___
-#define ___ORTHO_15_BOTTOM_FR___ ___BOTTOM_LEFT_FR___, ___ORTHO_15_MIDDLE_4___, ___BOTTOM_RIGHT_FR___
-#define ___ORTHO_15_BOTTOM_BP___ ___BOTTOM_LEFT_BP___, ___ORTHO_15_MIDDLE_4___, ___BOTTOM_RIGHT_BP___
-
-#define ___ORTHO_14_BOTTOM___ ___BOTTOM_LEFT___, ___ORTHO_14_MIDDLE_4___, ___BOTTOM_RIGHT___
-#define ___ORTHO_14_BOTTOM_FR___ ___BOTTOM_LEFT_FR___, ___ORTHO_14_MIDDLE_4___, ___BOTTOM_RIGHT_FR___
-#define ___ORTHO_14_BOTTOM_BP___ ___BOTTOM_LEFT_BP___, ___ORTHO_14_MIDDLE_4___, ___BOTTOM_RIGHT_BP___
-#define ___ORTHO_14_THUMBS_BOTTOM___ ___4___, ___MIDDLE_THUMBS___, ___4___
-
-
-#define ___ERGODOX_THUMB_LEFT___ \
- OSL(SYMB), OSM(KC_LGUI), \
- HOME_END, \
- CTL_BSPC, ALT_DEL, XMONAD_ESC
-
-#define ___ERGODOX_THUMB_RIGHT___ \
- XXX, OSL(KEYPAD), \
- KC_PGUP, \
- KC_PGDN, ALT_ENT, CTL_SPC
-
-#define ___ERGODOX_THUMB_RIGHT_BP___ \
- XXX, OSL(KEYPAD_ON_BEPO), \
- KC_PGUP, \
- KC_PGDN, ALT_ENT, CTL_SPC
-
-#define ___ERGODOX_THUMB_LEFT_BP___ \
- OSL(SYMB_ON_BEPO), OSM(KC_LGUI), \
- HOME_END, \
- CTL_BSPC, ALT_DEL, XMONAD_ESC
-
-/********************************************************************************/
-/* the interior rows for ortholinear keyboards. the first number is the length */
-/* So you can put what you want on the outside ends, make new middles as needed */
-/* It would be nice to make this a little more dynamic. There is little */
-/* differenc between them. */
-/********************************************************************************/
-
-//// ortho15 core rows. used with my xd75.
-/***********************************************************/
-/* ORTHO15 interior rows. used with my xd75 */
-/***********************************************************/
-#define ___13_DVORAK_1___ ___DVORAK_L1___, ___ORTHO_15_MIDDLE_1___, ___DVORAK_R1___
-#define ___13_DVORAK_2___ ___DVORAK_L2___, ___ORTHO_15_MIDDLE_2___, ___DVORAK_R2___
-#define ___13_DVORAK_3___ ___DVORAK_L3___, ___ORTHO_15_MIDDLE_3___, ___DVORAK_R3___
-
-#define ___13_QWERTY_1___ ___QWERTY_L1___, ___ORTHO_15_MIDDLE_1___, ___QWERTY_R1___
-#define ___13_QWERTY_2___ ___QWERTY_L2___, ___ORTHO_15_MIDDLE_2___, ___QWERTY_R2___
-#define ___13_QWERTY_3___ ___QWERTY_L3___, ___ORTHO_15_MIDDLE_3___, ___QWERTY_R3___
-
-#define ___13_COLEMAK_1___ ___COLEMAK_L1___, ___ORTHO_15_MIDDLE_1___, ___COLEMAK_R1___
-#define ___13_COLEMAK_2___ ___COLEMAK_L2___, ___ORTHO_15_MIDDLE_2___, ___COLEMAK_R2___
-#define ___13_COLEMAK_3___ ___COLEMAK_L3___, ___ORTHO_15_MIDDLE_3___, ___COLEMAK_R3___
-
-#define ___13_WORKMAN_1___ ___WORKMAN_L1___, ___ORTHO_15_MIDDLE_1___, ___WORKMAN_R1___
-#define ___13_WORKMAN_2___ ___WORKMAN_L2___, ___ORTHO_15_MIDDLE_2___, ___WORKMAN_R2___
-#define ___13_WORKMAN_3___ ___WORKMAN_L3___, ___ORTHO_15_MIDDLE_3___, ___WORKMAN_R3___
-
-#define ___13_NORMAN_1___ ___NORMAN_L1___, ___ORTHO_15_MIDDLE_1___, ___NORMAN_R1___
-#define ___13_NORMAN_2___ ___NORMAN_L2___, ___ORTHO_15_MIDDLE_2___, ___NORMAN_R2___
-#define ___13_NORMAN_3___ ___NORMAN_L3___, ___ORTHO_15_MIDDLE_3___, ___NORMAN_R3___
-
-#define ___13_DVORAK_B_1___ ___DVORAK_FR_L1___, ___ORTHO_15_MIDDLE_1_BP___, ___DVORAK_FR_R1___
-#define ___13_DVORAK_B_2___ ___DVORAK_FR_L2___, ___ORTHO_15_MIDDLE_2_BP___, ___DVORAK_FR_R2___
-#define ___13_DVORAK_B_3___ ___DVORAK_FR_L3___, ___ORTHO_15_MIDDLE_3_BP___, ___DVORAK_FR_R3___
-
-#define ___13_BEPO_1___ ___BEPO_FR_L1___, ___ORTHO_15_MIDDLE_1_BP___, ___BEPO_FR_R1___
-#define ___13_BEPO_2___ ___BEPO_FR_L2___, ___ORTHO_15_MIDDLE_2_BP___, ___BEPO_FR_R2___
-#define ___13_BEPO_3___ ___BEPO_FR_L3___, ___ORTHO_15_MIDDLE_3_BP___, ___BEPO_FR_R3___
-
-// transparent xmonad/dvorak layer
-#define ___15_XMONAD_1___ ___, ___DVORAK_L1___, ___3___, ___DVORAK_R1___, ___
-#define ___15_XMONAD_2___ ___, ___DVORAK_L2___, ___3___, ___DVORAK_R2___, ___
-#define ___15_XMONAD_3___ ___, ___DVORAK_L3___, ___3___, ___DVORAK_R3___, ___
-
-// transparent xmonad/dvorak layer in bepo
-#define ___15_XMONAD_B_1___ ___, ___DVORAK_FR_L1___, ___3___, ___DVORAK_FR_R1___, ___
-#define ___15_XMONAD_B_2___ ___, ___DVORAK_FR_L2___, ___3___, ___DVORAK_FR_R2___, ___
-#define ___15_XMONAD_B_3___ ___, ___DVORAK_FR_L3___, ___3___, ___DVORAK_FR_R3___, ___
-
-#define ___15_SYMB_1___ ___SYMBOLS6_1___, ___3___, ___SYMPAD_1___
-#define ___15_SYMB_2___ ___SYMBOLS6_2___, ___3___, ___SYMPAD_2___
-#define ___15_SYMB_3___ ___SYMBOLS6_3___, ___3___, ___SYMPAD_3___
-#define ___15_SYMB_4___ ___SYMBOLS6_4___, ___3___, ___SYMPAD_4___
-
-#define ___15_KP_1___ ___2___, ___FUNCPAD_T___, ___5___, ___KEYPAD_1___, ___
-#define ___15_KP_2___ ___2___, ___FUNCPAD_1___, ___5___, ___KEYPAD_2___, ___
-#define ___15_KP_3___ ___2___, ___FUNCPAD_2___, ___5___, ___KEYPAD_3___, KC_PENT
-#define ___15_KP_4___ ___2___, ___FUNCPAD_3___, ___5___, ___KEYPAD_4___, ___
-
-#define ___15_KP_B_1___ ___2___, ___FUNCPAD_T___, ___5___, ___KEYPAD_1_BP___, ___
-#define ___15_KP_B_2___ ___2___, ___FUNCPAD_1___, ___5___, ___KEYPAD_2_BP___, ___
-#define ___15_KP_B_3___ ___2___, ___FUNCPAD_2___, ___5___, ___KEYPAD_3_BP___, KC_PENT
-#define ___15_KP_B_4___ ___2___, ___FUNCPAD_3___, ___5___, ___KEYPAD_4_BP___, ___
-
-#define ___15_SYMB_B_1___ ___SYMBOLS6_1_BP___, ___3___, ___SYMPAD_1_BP___
-#define ___15_SYMB_B_2___ ___SYMBOLS6_2_BP___, ___3___, ___SYMPAD_2_BP___
-#define ___15_SYMB_B_3___ ___SYMBOLS6_3_BP___, ___3___, ___SYMPAD_3_BP___
-#define ___15_SYMB_B_4___ ___SYMBOLS6_4_BP___, ___3___, ___SYMPAD_4_BP___
-
-#define ___15_MDIA_1___ ___MOUSE_BTNS_L___, ___4___, KC_VOLU, ___MUTE_PRV_PLAY_NXT_STOP___
-#define ___15_MDIA_2___ ___, ___MOUSE_LDUR___, ___4___, KC_VOLD, ___VI_ARROWS___, ___
-#define ___15_MDIA_3___ ___, ___MWHEEL_LDUR___, ___4___, KC_PGUP, ___MOUSE_BTNS_R___
-#define ___15_MDIA_4___ ___2___, ___MACCL___, ___4___, KC_PGDN, ___5___
-
-#define ___15_LAYERS_1___ ___X3___, ___2_LAYERS_B1___, ___5___, ___3_LAYERS_T_BP___, ___X2___
-#define ___15_LAYERS_2___ ___X3___, ___2_LAYERS_B2___, ___5___, ___3_LAYERS_T___, ___X2___
-#define ___15_LAYERS_3___ ___X2___, ___3_LAYERS_B3___, ___5___, ___3_LAYERS_T_CTL___, ___X2___
-
-#define ___15_RGB_1___ ___, ___RGB_HUE_SAT_INT_UP___, ___5___, ___5___
-#define ___15_RGB_2___ ___, ___RGB_HUE_SAT_INT_DN___, RGB_TOG, ___4___, ___RGB_P_B_R_SW_SN___
-#define ___15_RGB_3___ ___5___, ___5___, ___RGB_KXGT___, ___
-
-
-
-/***********************************************************/
-/* ORTHO14 base layer interior rows. used with my viterbi */
-/***********************************************************/
-#define ___12_DVORAK_1___ ___DVORAK_L1___, ___ORTHO_14_MIDDLE_1___, ___DVORAK_R1___
-#define ___12_DVORAK_2___ ___DVORAK_L2___, ___ORTHO_14_MIDDLE_2___, ___DVORAK_R2___
-#define ___12_DVORAK_3___ ___DVORAK_L3___, ___ORTHO_14_MIDDLE_3___, ___DVORAK_R3___
-
-#define ___12_QWERTY_1___ ___QWERTY_L1___, ___ORTHO_14_MIDDLE_1___, ___QWERTY_R1___
-#define ___12_QWERTY_2___ ___QWERTY_L2___, ___ORTHO_14_MIDDLE_2___, ___QWERTY_R2___
-#define ___12_QWERTY_3___ ___QWERTY_L3___, ___ORTHO_14_MIDDLE_3___, ___QWERTY_R3___
-
-#define ___12_COLEMAK_1___ ___COLEMAK_L1___, ___ORTHO_14_MIDDLE_1___, ___COLEMAK_R1___
-#define ___12_COLEMAK_2___ ___COLEMAK_L2___, ___ORTHO_14_MIDDLE_2___, ___COLEMAK_R2___
-#define ___12_COLEMAK_3___ ___COLEMAK_L3___, ___ORTHO_14_MIDDLE_3___, ___COLEMAK_R3___
-
-#define ___12_WORKMAN_1___ ___WORKMAN_L1___, ___ORTHO_14_MIDDLE_1___, ___WORKMAN_R1___
-#define ___12_WORKMAN_2___ ___WORKMAN_L2___, ___ORTHO_14_MIDDLE_2___, ___WORKMAN_R2___
-#define ___12_WORKMAN_3___ ___WORKMAN_L3___, ___ORTHO_14_MIDDLE_3___, ___WORKMAN_R3___
-
-#define ___12_NORMAN_1___ ___NORMAN_L1___, ___ORTHO_14_MIDDLE_1___, ___NORMAN_R1___
-#define ___12_NORMAN_2___ ___NORMAN_L2___, ___ORTHO_14_MIDDLE_2___, ___NORMAN_R2___
-#define ___12_NORMAN_3___ ___NORMAN_L3___, ___ORTHO_14_MIDDLE_3___, ___NORMAN_R3___
-
-#define ___12_DVORAK_B_1___ ___DVORAK_FR_L1___, ___ORTHO_14_MIDDLE_1_BP___, ___DVORAK_FR_R1___
-#define ___12_DVORAK_B_2___ ___DVORAK_FR_L2___, ___ORTHO_14_MIDDLE_2_BP___, ___DVORAK_FR_R2___
-#define ___12_DVORAK_B_3___ ___DVORAK_FR_L3___, ___ORTHO_14_MIDDLE_3_BP___, ___DVORAK_FR_R3___
-
-#define ___12_BEPO_2___ ___BEPO_FR_L1___, ___ORTHO_14_MIDDLE_1_BP___, ___BEPO_FR_R1___
-#define ___12_BEPO_3___ ___BEPO_FR_L2___, ___ORTHO_14_MIDDLE_2_BP___, ___BEPO_FR_R2___
-#define ___12_BEPO_4___ ___BEPO_FR_L3___, ___ORTHO_14_MIDDLE_3_BP___, ___BEPO_FR_R3___
-
-
-// transparent layers.
-#define ___14_XMONAD_1___ ___, ___DVORAK_L1___, ___2___, ___DVORAK_R1___, ___
-#define ___14_XMONAD_2___ ___, ___DVORAK_L2___, ___2___, ___DVORAK_R2___, ___
-#define ___14_XMONAD_3___ ___, ___DVORAK_L3___, ___2___, ___DVORAK_R3___, ___
-
-#define ___14_XMONAD_B_1___ ___, ___DVORAK_FR_L1___, ___2___, ___DVORAK_FR_R1___, ___
-#define ___14_XMONAD_B_2___ ___, ___DVORAK_FR_L2___, ___2___, ___DVORAK_FR_R2___, ___
-#define ___14_XMONAD_B_3___ ___, ___DVORAK_FR_L3___, ___2___, ___DVORAK_FR_R3___, ___
-
-#define ___14_SYMB_1___ ___SYMBOLS6_1___, ___2___, ___SYMPAD_1___
-#define ___14_SYMB_2___ ___SYMBOLS6_2___, ___2___, ___SYMPAD_2___
-#define ___14_SYMB_3___ ___SYMBOLS6_3___, ___2___, ___SYMPAD_3___
-#define ___14_SYMB_4___ ___SYMBOLS6_4___, ___2___, ___SYMPAD_4___
-
-#define ___14_KP_1___ ___2___, ___FUNCPAD_T___, ___4___, ___KEYPAD_1___, ___
-#define ___14_KP_2___ ___2___, ___FUNCPAD_1___, ___4___, ___KEYPAD_2___, ___
-#define ___14_KP_3___ ___2___, ___FUNCPAD_2___, ___4___, ___KEYPAD_3___, KC_PENT
-#define ___14_KP_4___ ___2___, ___FUNCPAD_3___, ___4___, ___KEYPAD_4___, ___
-
-#define ___14_KP_B_1___ ___2___, ___FUNCPAD_T___, ___4___, ___KEYPAD_1_BP___, ___
-#define ___14_KP_B_2___ ___2___, ___FUNCPAD_1___, ___4___, ___KEYPAD_2_BP___, ___
-#define ___14_KP_B_3___ ___2___, ___FUNCPAD_2___, ___4___, ___KEYPAD_3_BP___, KC_PENT
-#define ___14_KP_B_4___ ___2___, ___FUNCPAD_3___, ___4___, ___KEYPAD_4_BP___, ___
-
-#define ___14_SYMB_B_1___ ___SYMBOLS6_1_BP___, ___2___, ___SYMPAD_1_BP___
-#define ___14_SYMB_B_2___ ___SYMBOLS6_2_BP___, ___2___, ___SYMPAD_2_BP___
-#define ___14_SYMB_B_3___ ___SYMBOLS6_3_BP___, ___2___, ___SYMPAD_3_BP___
-#define ___14_SYMB_B_4___ ___SYMBOLS6_4_BP___, ___2___, ___SYMPAD_4_BP___
-
-#define ___14_MDIA_1___ ___MOUSE_BTNS_L___, ___3___, KC_VOLU, ___MUTE_PRV_PLAY_NXT_STOP___
-#define ___14_MDIA_2___ ___, ___MOUSE_LDUR___, ___3___, KC_VOLD, ___VI_ARROWS___, ___
-#define ___14_MDIA_3___ ___, ___MWHEEL_LDUR___, ___3___, KC_PGUP, ___MOUSE_BTNS_R___
-#define ___14_MDIA_4___ ___2___, ___MACCL___, ___3___, KC_PGDN, ___5___
-
-#define ___14_LAYERS_1___ ___X3___, ___2_LAYERS_B1___, ___4___, ___3_LAYERS_T_BP___, ___X2___
-#define ___14_LAYERS_2___ ___X3___, ___2_LAYERS_B2___, ___4___, ___3_LAYERS_T___, ___X2___
-#define ___14_LAYERS_3___ ___X2___, ___3_LAYERS_B3___, ___4___, ___3_LAYERS_T_CTL___, ___X2___
-
-#define ___14_RGB_1___ ___, ___RGB_HUE_SAT_INT_UP___, ___4___, ___5___
-#define ___14_RGB_2___ ___, ___RGB_HUE_SAT_INT_DN___, RGB_TOG, ___3___, ___RGB_P_B_R_SW_SN___
-#define ___14_RGB_3___ ___5___, ___4___, ___RGB_KXGT___, ___
diff --git a/users/ericgebhart/caps_word.c b/users/ericgebhart/caps_word.c
new file mode 100644
index 0000000000..ba81c15d66
--- /dev/null
+++ b/users/ericgebhart/caps_word.c
@@ -0,0 +1,81 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// For full documentation, see
+// https://getreuer.info/posts/keyboards/caps-word
+
+#include "caps_word.h"
+
+bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
+ static bool caps_word_enabled = false;
+ static bool shifted = false;
+#ifndef NO_ACTION_ONESHOT
+ const uint8_t mods = get_mods() | get_oneshot_mods();
+#else
+ const uint8_t mods = get_mods();
+#endif // NO_ACTION_ONESHOT
+
+ if (!caps_word_enabled) {
+ // Pressing both shift keys at the same time enables caps word.
+ if ((mods & MOD_MASK_SHIFT) == MOD_MASK_SHIFT) {
+ clear_mods();
+#ifndef NO_ACTION_ONESHOT
+ clear_oneshot_mods();
+#endif // NO_ACTION_ONESHOT
+ shifted = false;
+ caps_word_enabled = true;
+ return false;
+ }
+ return true;
+ }
+
+ if (!record->event.pressed) { return true; }
+
+ if (!(mods & ~MOD_MASK_SHIFT)) {
+ switch (keycode) {
+ case QK_MOD_TAP ... QK_MOD_TAP_MAX:
+ case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
+ // Earlier return if this has not been considered tapped yet.
+ if (record->tap.count == 0) { return true; }
+ // Get the base tapping keycode of a mod- or layer-tap key.
+ keycode &= 0xff;
+ }
+
+ switch (keycode) {
+ // Letter keys should be shifted.
+ case KC_A ... KC_Z:
+ if (!shifted) { register_code(KC_LSFT); }
+ shifted = true;
+ return true;
+
+ // Keycodes that continue caps word but shouldn't get shifted.
+ case KC_1 ... KC_0:
+ case KC_BSPC:
+ case KC_MINS:
+ case KC_UNDS:
+ if (shifted) { unregister_code(KC_LSFT); }
+ shifted = false;
+ return true;
+
+ // Any other keycode disables caps word.
+ }
+ }
+
+ // Disable caps word.
+ caps_word_enabled = false;
+ if (shifted) { unregister_code(KC_LSFT); }
+ shifted = false;
+ return true;
+}
diff --git a/users/ericgebhart/caps_word.h b/users/ericgebhart/caps_word.h
new file mode 100644
index 0000000000..a59b2e4338
--- /dev/null
+++ b/users/ericgebhart/caps_word.h
@@ -0,0 +1,35 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// Caps Word, activated by pressing both shift keys at the same time.
+//
+// This library implements "Caps Word", which is like conventional Caps Lock,
+// but automatically disables itself at the end of the word. This is useful for
+// typing all-caps identifiers like `MOD_MASK_ALT`.
+//
+// Caps Word is activated by pressing the left and right shift keys at the same
+// time. This way you don't need a dedicated key for using Caps Word. I've
+// tested that this works as expected with one-shot mods and Space Cadet Shift.
+// If your shift keys are mod-taps, activate Caps Word by holding both shift
+// mod-tap keys until the tapping term, release them, then begin typing.
+//
+// For full documentation, see
+// https://getreuer.info/posts/keyboards/caps-word
+
+#pragma once
+
+#include QMK_KEYBOARD_H
+
+bool process_caps_word(uint16_t keycode, keyrecord_t* record);
diff --git a/users/ericgebhart/combos.def b/users/ericgebhart/combos.def
new file mode 100644
index 0000000000..9b5f2c8a9e
--- /dev/null
+++ b/users/ericgebhart/combos.def
@@ -0,0 +1,10 @@
+// name result chord keys
+COMB(LNAV, TG(_NAV), SPC_TOPR, ENT_NAV)
+COMB(OSLSYM, OSL(_SYMB), ESC_TOPR, BSPC_SYMB)
+COMB(OSLSYMBP, OSL(_SYMB_BP), ESC_TOPR_BP, BSPC_SYMB_BP)
+COMB(LKEYPAD, TG(_KEYPAD), SPC_TOPR, BSPC_SYMB)
+COMB(LKEYPADBP, TG(_KEYPAD_BP), SPC_TOPR_BP, BSPC_SYMB_BP)
+COMB(LLAYERS, OSL(_LAYERS), KC_TAB, ENT_NAV)
+
+//COMB(JKL_SPC, KC_SPC, KC_J, KC_X)
+//SUBS(TH_THE, "the", KC_T, KC_H) // SUBS uses SEND_STRING to output the given string.
diff --git a/users/ericgebhart/config.h b/users/ericgebhart/config.h
index 934c3debba..116d48f4ab 100755
--- a/users/ericgebhart/config.h
+++ b/users/ericgebhart/config.h
@@ -1,8 +1,29 @@
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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/>.
+*/
+
#ifndef USERSPACE_CONFIG_H
#define USERSPACE_CONFIG_H
#include "../../config.h"
+#define NO_ACTION_MACRO
+#define NO_ACTION_FUNCTION
+#define COMBO_MUST_HOLD_MODS
+#define COMBO_HOLD_TERM 150
// Sets good default for the speed of the mouse.
#undef MOUSEKEY_INTERVAL
#undef MOUSEKEY_DELAY
@@ -26,7 +47,7 @@
#undef TAPPING_TERM
#undef IGNORE_MOD_TAP_INTERRUPT
-#define TAPPING_TOGGLE 1
+#define TAPPING_TOGGLE 2
#define TAPPING_TERM 200
#define IGNORE_MOD_TAP_INTERRUPT
diff --git a/users/ericgebhart/core_keys.h b/users/ericgebhart/core_keys.h
index a71d905749..73beaaf7ab 100644..100755
--- a/users/ericgebhart/core_keys.h
+++ b/users/ericgebhart/core_keys.h
@@ -19,42 +19,13 @@
#include "quantum.h"
#include "process_keycode/process_tap_dance.h"
#include "eeconfig.h"
+#include "keymap_bepo.h"
+#include "altlocal_keys.h"
//#define ONESHOT_TAP_TOGGLE 2 /* Tapping this number of times holds the key until tapped once again. */
-void tap(uint16_t keycode);
bool process_record_secrets(uint16_t keycode, keyrecord_t *record);
-
-typedef union {
- uint8_t raw;
- struct {
- bool clicky_enable :1;
- bool rgb_layer_change :1;
- bool is_overwatch :1;
- bool nuke_switch :1;
- };
-} userspace_config_t;
-
-
-// for the creation of dvorak keys on an Bepo keyboard at the OS layer.
-// so we can create an array of reasonable size
-// for our translation keys. We have to create a
-// good range of numbers
-#define GR(x) (x-SAFE_RANGE)
-
-uint8_t gr(uint8_t);
-void send_keycode(uint8_t);
-
-#define MOD_NONE 0x00
-
-// indexs for the keycode translation table.
-#define UNSHIFTED_KEY(key) key_translations[gr(key)][0][0]
-#define UNSHIFTED_MODS(key) key_translations[gr(key)][0][1]
-#define SHIFTED_KEY(key) key_translations[gr(key)][1][0]
-#define SHIFTED_MODS(key) key_translations[gr(key)][1][1]
-
-
enum userspace_custom_keycodes {
// keep the keycodes using the send_key function close to SAFE_RANGE
// so the array of keycodes remains a reasonbale size.
@@ -91,37 +62,106 @@ enum userspace_custom_keycodes {
DB_LESS,
DB_GRTR,
// End of dvorak on bepo translation keys.
+ // BEAKL on Qwerty..
+ BQ_DOT,
+ BQ_COMM,
+ BQ_QUOT,
+ // End of beakl on qwerty
+ BB_DOT,
+ BB_COMM,
+ BB_QUOT,
+ // End of beakl on Bepo
EPRM,
VRSN,
- KC_DVORAK_ON_BEPO,
- KC_BEPO,
- KC_NORMAN,
+ // Default keyboard layouts - Same order as enum.
+ KC_DVORAK,
KC_QWERTY,
KC_COLEMAK,
- KC_DVORAK,
- KC_WORKMAN,
+ KC_BEAKL,
+ // KC_WORKMAN,
+ // KC_NORMAN,
+ // KC_MALTRON,
+ // KC_EUCALYN,
+ // KC_CARPLAX,
+ KC_DVORAK_BP,
+ KC_BEAKL_BP,
+ KC_BEPO,
+ KC_LAYERS,
+
+ // Misc.
KC_MAKE,
KC_RESET,
KC_RGB_T,
+ RGB_IDL,
KC_SECRET_1,
KC_SECRET_2,
KC_SECRET_3,
KC_SECRET_4,
KC_SECRET_5,
- KC_CCCV
+ KC_CCCV, // Ctrl-C V in one key.
+ BP_CCCV,
+ KC_CTCN, // Ctrl-T N in one key.
+ BP_CTCN,
+ KC_CWCQ, // Ctrl-W Q in one key.
+ BP_CWCQ,
+ KC_XM_PORD, // Xmonad gui-e, gui-t for the scratchpads or desktops.
+ BP_XM_PORD,
+ KC_OCPRN, // Open, or open and close, cursor in the middle with hold.
+ BP_OCPRN,
+ KC_OCBRC,
+ BP_OCBRC,
+ KC_OCCBR,
+ BP_OCCBR,
+ KC_OCDQUO,
+ BP_OCDQUO,
+ KC_OCQUOT,
+ BP_OCQUOT,
+ KC_OCGRV,
+ BP_OCGRV,
+ KC_OCLTGT,
+ BP_OCLTGT,
+ UC_FLIP,
+ UC_TABL,
+ UC_SHRG,
+ UC_DISA,
+ KC_SPACETEST,
+ NEW_SAFE_RANGE
};
-#define SFTGUI_T(kc) { MT(MOD_LGUI | MOD_LSFT, kc) }
-#define SFT_GUI_ESC MT(MOD_LSFT | MOD_LGUI, KC_PGDN) // shift LGUI or Escape.
-#define ALT_ENT ALT_T(KC_ENT) // Alt or enter
-#define CTL_SPC CTL_T(KC_SPC) // ctrl or space
-#define CTL_BSPC CTL_T(KC_BSPC) // ctrl or backspace
-#define ALT_DEL ALT_T(KC_DEL) // Alt or delete
-#define GUI_ESC GUI_T(KC_ESC) // Gui or escape
-#define ALGR_SYMB ALGR_T(TG(SYMB)) // Alt gre or toggle symbol layer
-
-
+#define CTLGUI_T(kc) MT(MOD_LGUI | MOD_LCTL, kc)
+#define SFTGUI_T(kc) MT(MOD_LGUI | MOD_LSFT, kc)
+#define ALTGUI_T(kc) MT(MOD_LGUI | MOD_LALT, kc)
+
+#define ALT_ENT ALT_T(KC_ENT) // Alt or enter
+#define CTL_SPC CTL_T(KC_SPC) // ctrl or space
+#define CTL_BSPC CTL_T(KC_BSPC) // ctrl or backspace
+#define ALT_DEL ALT_T(KC_DEL) // Alt or delete
+#define GUI_ESC GUI_T(KC_ESC) // Gui or escape
+#define ALGR_SYMB ALGR_T(TG(_SYMB)) // Alt gre or toggle symbol layer
+
+#define ENT_NAV LT(_NAV, KC_ENT)
+#define ENT_TOPR LT(_TOPROWS, KC_ENT)
+#define ENT_TOPR_BP LT(_TOPROWS_BP, KC_ENT)
+#define ESC_TOPR LT(_TOPROWS, KC_ESC)
+#define ESC_TOPR_BP LT(_TOPROWS_BP, KC_ESC)
+#define ESC_SYMB LT(_SYMB, KC_ESC)
+#define ESC_SYMB_BP LT(_SYMB_BP, KC_ESC)
+#define SPC_NAV LT(_NAV, KC_SPC)
+#define SPC_TOPR LT(_TOPROWS, KC_SPC)
+#define SPC_TOPR_BP LT(_TOPROWS_BP, KC_SPC)
+#define SPC_LAYR LT(_LAYERS, KC_SPC)
+#define SPC_LAYR_BP LT(_LAYERS, KC_SPC)
+#define SPC_ADJ LT(_ADJUST, KC_SPC)
+#define SPC_ADJ_BP LT(_ADJUST, KC_SPC)
+#define BSPC_SYMB LT(_SYMB, KC_BSPC)
+#define BSPC_SYMB_BP LT(_SYMB_BP, KC_BSPC)
+#define BSPC_TOPR LT(_TOPROWS, KC_BSPC)
+#define BSPC_TOPR_BP LT(_TOPROWS_BP, KC_BSPC)
+#define SPC_NUM LT(_KEYPAD, KC_SPC)
+#define SPC_NUM_BP LT(_KEYPAD_BP, KC_SPC)
+#define BSPC_NUM LT(_KEYPAD, KC_BSPC)
+#define BSPC_NUM_BP LT(_KEYPAD_BP, KC_BSPC)
// OSM keycodes, to keep things clean and easy to change
#define KC_MLSF OSM(MOD_LSFT)
@@ -138,6 +178,9 @@ enum userspace_custom_keycodes {
#define MG_NKRO MAGIC_TOGGLE_NKRO
+#define UC_IRNY UC(0x2E2E)
+#define UC_CLUE UC(0x203D)
+
//// TAP DANCE
@@ -166,11 +209,16 @@ enum {
TD_DEF_LAYER_SW = 5,
TD_DEF_OS_LAYER_SW = 6,
TD_MOUSE_BTNS = 7,
- TD_DVORAK_BEPO = 8
+ TD_DVORAK_BEPO = 8,
+ TD_UP_HOME = 9,
+ TD_DOWN_END = 10,
+ TD_RIGHT_TAB = 11,
+ TD_LEFT_BACKTAB = 12
};
// Tap dance
+#define KC_BKTAB LSFT(KC_TAB)
#define TAB_BKTAB TD(TD_TAB_BKTAB) // Tab or backtab tapdance.
#define MDIA_SYMB_KP_LAYERS TD(TD_MDIA_SYMB) // MDIA, symb, keypad, layouts layer tapdance toggle.
#define DEF_LAYER_SW TD(TD_DEF_LAYER_SW) // dvorak, dvorak_on_bepo, bepo default layer
@@ -179,100 +227,34 @@ enum {
#define XMONAD_ESC TD(TD_XMONAD_ESC) // Escape, dvorak, media or symb. - tap and hold tap dance. 1-4
#define DVORAK_ET_BEPO TD(TD_DVORAK_BEPO) // Escape, dvorak, media or symb. - tap and hold tap dance. 1-4
#define TDMOUSE_BTNS TD(TD_MOUSE_BTNS) // hmmm. 1-5
+#define RIGHT_TAB TD(TD_RIGHT_TAB) // Bad idea these 4. Maybe with good timing...
+#define LEFT_BACKTAB TD(TD_LEFT_BACKTAB)
+#define UP_HOME TD(TD_UP_HOME)
+#define DOWN_END TD(TD_DOWN_END) // No! Down Down Not End....
// HOME ROW LAYER TOGGLE (LT) and Shift.
// both sides of the home row have "shift, ___, media , symb, ___" and "___, symb, media, ___, shift".
// so pinky fingers are shift when held and the index and second fingers are symbol and
// media layers when held.
-// Dvorak
-// shift and layer switch on hold on the home row.
-#define KC_SFT_T_A SFT_T(KC_A)
-#define KC_SFT_T_S SFT_T(KC_S)
-
-#define KC_LT_SYMB_U LT(SYMB, KC_U)
-#define KC_LT_SYMB_H LT(SYMB, KC_H)
-
-#define KC_LT_MDIA_E LT(MDIA, KC_E)
-#define KC_LT_MDIA_T LT(MDIA, KC_T)
-
-// Need to add this to the others.
-#define KC_LT_KP_N LT(KEYPAD, KC_N)
-#define KC_LT_KP_O LT(KEYPAD, KC_O)
-
-// for dvorak on bepo
-#define BP_SFT_T_A SFT_T(BP_A)
-#define BP_SFT_T_S SFT_T(BP_S)
-
-#define BP_LT_SYMB_U LT(SYMB, BP_U)
-#define BP_LT_SYMB_H LT(MDIA, BP_H)
-
-#define BP_LT_MDIA_E LT(MDIA, BP_E)
-#define BP_LT_MDIA_T LT(MDIA, BP_T)
-
-// Need to add this to the others.
-#define BP_LT_KP_N LT(KEYPAD, BP_N)
-#define BP_LT_KP_O LT(KEYPAD, BP_O)
-
-// for bepo on bepo
-#define BP_SFT_T_T SFT_T(BP_T)
-#define BP_SFT_T_W SFT_T(BP_W)
-
-#define BP_LT_SYMB_I LT(SYMB_ON_BEPO, BP_I)
-#define BP_LT_MDIA_E LT(MDIA, BP_E)
-#define BP_LT_KP_U LT(KEYPAD, BP_U)
-
-#define BP_LT_SYMB_S LT(SYMB_ON_BEPO, BP_S)
-#define BP_LT_MDIA_R LT(MDIA, BP_R)
-#define BP_LT_KP_N LT(KEYPAD, BP_N)
-
-#define BP_SFT_T_A SFT_T(BP_A)
-#define BP_SFT_T_S SFT_T(BP_S)
-#define BP_SFT_T_E SFT_T(BP_E)
-#define BP_SFT_T_M SFT_T(BP_M)
-
-#define BP_SFT_T_ECRC SFT_T(BP_ECIR)
-#define BP_SFT_T_CCED SFT_T(BP_CCED)
-#define BP_LT_SYMB_COMM LT(SYMB,BP_COMM)
-
-//QWERTY
-#define KC_SFT_T_SCLN SFT_T(KC_SCLN)
-
-#define KC_LT_MDIA_D LT(MDIA, KC_D)
-#define KC_LT_MDIA_K LT(MDIA, KC_K)
-#define KC_LT_SYMB_F LT(SYMB, KC_F)
-#define KC_LT_SYMB_J LT(SYMB, KC_J)
-
-//COLEMAK
-#define KC_SFT_T_O SFT_T(KC_O)
-#define KC_LT_MDIA_S LT(MDIA, KC_S)
-#define KC_LT_SYMB_T LT(SYMB, KC_T)
-
-#define KC_LT_MDIA_E LT(MDIA, KC_E)
-#define KC_LT_SYMB_N LT(SYMB, KC_N)
-
-//WORKMAN
-#define KC_SFT_T_I SFT_T(KC_I)
-#define KC_LT_MDIA_H LT(MDIA, KC_H)
-
-//NORMAN
-// For keys on the homerow. Hold for shift, keypad,mouse,and smbol layers
-#define KC_SFT_T_U SFT_T(KC_U)
-#define KC_LT_MDIA_I LT(MDIA, KC_I)
-
// The most portable copy/paste keys (windows (mostly), linux, and some terminal emulators).
+// The KC_CCCV key takes care of the last two...
#define MK_CUT LSFT(KC_DEL) // shift + delete
#define MK_COPY LCTL(KC_INS) // ctrl + insert
#define MK_PASTE LSFT(KC_INS) // shift + insert
+#undef ___ //kint defines it as KC_NO
#define ___ KC_TRNS
#define XXX KC_NO
// Blocking keys
+#define _X_ XXX
#define ___X___ XXX
#define ___X2___ XXX, XXX
#define ___X3___ ___X2___, XXX
#define ___X5___ ___X3___, XXX, XXX
+#define ___X6___ ___X5___, XXX
+#define ___X12___ ___X6___, ___X6___
#define ___X15___ ___X5___, ___X5___, ___X5___
// Transparent keys
@@ -281,13 +263,18 @@ enum {
#define ___4___ ___3___, ___
#define ___5___ ___4___, ___
#define ___6___ ___5___, ___
+#define ___12___ ___6___, ___6___
#define ___14___ ___5___, ___4___, ___5___
#define ___15___ ___5___, ___5___, ___5___
+#define ___16___ ___15___, ___
int on_qwerty(void);
int get_xmonad_layer(void);
+
+#ifdef TAP_DANCES_ENABLE
int cur_dance (qk_tap_dance_state_t *state);
//for the x tap dance. Put it here so it can be used in any keymap
void x_finished (qk_tap_dance_state_t *state, void *user_data);
void x_reset (qk_tap_dance_state_t *state, void *user_data);
+#endif
diff --git a/users/ericgebhart/core_keysets.h b/users/ericgebhart/core_keysets.h
index 5baf02ccf6..f51f743921 100644..100755
--- a/users/ericgebhart/core_keysets.h
+++ b/users/ericgebhart/core_keysets.h
@@ -17,277 +17,329 @@
*/
#include "core_keys.h"
-
/********************************************************************/
-/** Parts are parts, pieces of keysets so we have some decent **/
-/** building blocks to make keymaps with. **/
+/** The Core rows of each given layout. **/
/********************************************************************/
+//Dvorak on a qwerty software layer in the OS
+#define ___DVORAK_L1___ KC_QUOT, KC_COMM, KC_DOT, KC_P, KC_Y
+#define ___DVORAK_L2___ KC_A, KC_O, KC_E, KC_U, KC_I
+#define ___DVORAK_L3___ KC_SCLN, KC_Q, KC_J, KC_K, KC_X
+
+#define ___DVORAK_R1___ KC_F, KC_G, KC_C, KC_R, KC_L
+#define ___DVORAK_R2___ KC_D, KC_H, KC_T, KC_N, KC_S
+#define ___DVORAK_R3___ KC_B, KC_M, KC_W, KC_V, KC_Z
+
+#define ___DVORAK___ ___DVORAK_L1___, ___DVORAK_R1___, \
+ ___DVORAK_L2___, ___DVORAK_R2___, \
+ ___DVORAK_L3___, ___DVORAK_R3___
+
+/* BEAKL 15 (main layer): */
+/* 40123 76598 */
+/* qhoux gcrfz */
+/* - yiea. dstnb ; */
+/* j/,k' wmlpv */
+
+// Remember the - and ; outside pinky keys.
+// Or use the 6 size.
+// Both are on the symbol layer too. So you
+// wont lose them at least.
+// BQ_COMM, BQ_QUOT, BQ_DOT - Beakl->Qwerty
+// BB_COMM, BB_QUOT, BB_DOT - Beakl->Bepo
+// take care of the different shifted chars.
+/* BEAKL 15 (shift layer): */
+/* QHOUX GCRFZ */
+/* - YIEA@ DSTNB ; */
+/* J?!K` WMLPV */
+#define ___BEAKL15_L1___ KC_Q, KC_H, KC_O, KC_U, KC_X
+#define ___BEAKL15_L2___ KC_Y, KC_I, KC_E, KC_A, BQ_DOT
+#define ___BEAKL15_L3___ KC_J, KC_SLASH, BQ_COMM, KC_K, BQ_QUOT
+
+#define ___BEAKL15_R1___ KC_G, KC_C, KC_R, KC_F, KC_Z
+#define ___BEAKL15_R2___ KC_D, KC_S, KC_T, KC_N, KC_B
+#define ___BEAKL15_R3___ KC_W, KC_M, KC_L, KC_P, KC_V
+
+#define ___BEAKL15___ ___BEAKL15_L1___, ___BEAKL15_R1___, \
+ ___BEAKL15_L2___, ___BEAKL15_R2___, \
+ ___BEAKL15_L3___, ___BEAKL15_R3___
+
+#define ___6BEAKL15_L1___ ___, KC_Q, KC_H, KC_O, KC_U, KC_X
+#define ___6BEAKL15_L2___ KC_MINS, KC_Y, KC_I, KC_E, KC_A, BQ_DOT
+#define ___6BEAKL15_L3___ ___, KC_J, KC_SLASH, BQ_COMM, KC_K, BQ_QUOT
+
+#define ___6BEAKL15_R1___ KC_G, KC_C, KC_R, KC_F, KC_Z, ___
+#define ___6BEAKL15_R2___ KC_D, KC_S, KC_T, KC_N, KC_B, KC_SCLN
+#define ___6BEAKL15_R3___ KC_W, KC_M, KC_L, KC_P, KC_V, ___
+
+#define ___6BEAKL15___ ___6BEAKL15_L1___, ___6BEAKL15_R1___, \
+ ___6BEAKL15_L2___, ___6BEAKL15_R2___, \
+ ___6BEAKL15_L3___, ___6BEAKL15_R3___
+// Qwerty based layers that I don't really use.
+#define ___QWERTY_L1___ KC_Q, KC_W, KC_E, KC_R, KC_T
+#define ___QWERTY_L2___ KC_A, KC_S, KC_D, KC_F, KC_G
+#define ___QWERTY_L3___ KC_Z, KC_X, KC_C, KC_V, KC_B
-// Since our quirky block definitions are basically a list of comma separated
-// arguments, we need a wrapper in order for these definitions to be
-// expanded before being used as arguments to the LAYOUT_xxx macro.
-#if (!defined(LAYOUT) && defined(KEYMAP))
-#define LAYOUT KEYMAP
-#endif
+#define ___QWERTY_R1___ KC_Y, KC_U, KC_I, KC_O, KC_P
+#define ___QWERTY_R2___ KC_H, KC_J, KC_K, KC_L, KC_SCLN
+#define ___QWERTY_R3___ KC_N, KC_M, KC_COMM, KC_DOT, KC_SLASH
-#define LAYOUT_ergodox_wrapper(...) LAYOUT_ergodox(__VA_ARGS__)
-#define LAYOUT_ergodox_pretty_wrapper(...) LAYOUT_ergodox_pretty(__VA_ARGS__)
-#define KEYMAP_wrapper(...) LAYOUT(__VA_ARGS__)
-#define LAYOUT_wrapper(...) LAYOUT(__VA_ARGS__)
+#define ___QWERTY___ ___QWERTY_L1___, ___QWERTY_R1___, \
+ ___QWERTY_L2___, ___QWERTY_R2___, \
+ ___QWERTY_L3___, ___QWERTY_R3___
-#define LAYOUT_ortho_5x15_wrapper(...) LAYOUT_ortho_5x15(__VA_ARGS__)
-#define LAYOUT_ortho_5x14_wrapper(...) LAYOUT_ortho_5x14(__VA_ARGS__)
+// Qwerty based layers that I don't really use.
+// COLEMAK
+#define ___COLEMAK_L1___ KC_Q, KC_W, KC_F, KC_P, KC_G
+#define ___COLEMAK_L2___ KC_A, KC_R, KC_S, KC_T, KC_D
+#define ___COLEMAK_L3___ KC_Z, KC_X, KC_C, KC_V, KC_B
-/********************************************************************/
-/** The Core rows of each given layout. **/
-/********************************************************************/
-//Dvorak on a qwerty software layer in the OS
-#define ___DVORAK_L1___ KC_QUOT, KC_COMM, KC_DOT, KC_P, KC_Y
-#define ___DVORAK_L2___ KC_SFT_T_A, KC_LT_KP_O, KC_LT_MDIA_E, KC_LT_SYMB_U, KC_I
-#define ___DVORAK_L3___ KC_SCLN, KC_Q, KC_J, KC_K, KC_X
+#define ___COLEMAK_R1___ KC_J, KC_L, KC_U, KC_Y, KC_SCLN
+#define ___COLEMAK_R2___ KC_H, KC_N, KC_E, KC_I, KC_O
+#define ___COLEMAK_R3___ KC_K, KC_M, KC_COMM, KC_DOT, KC_SLASH
-#define ___DVORAK_R1___ KC_F, KC_G, KC_C, KC_R, KC_L
-#define ___DVORAK_R2___ KC_D, KC_LT_SYMB_H, KC_LT_MDIA_T, KC_LT_KP_N, KC_SFT_T_S
-#define ___DVORAK_R3___ KC_B, KC_M, KC_W, KC_V, KC_Z
+#define ___COLEMAK___ ___COLEMAK_L1___, ___COLEMAK_R1___, \
+ ___COLEMAK_L2___, ___COLEMAK_R2___, \
+ ___COLEMAK_L3___, ___COLEMAK_R3___
-// Qwerty based layers that I don't really use.
-#define ___QWERTY_L1___ KC_Q, KC_W, KC_E, KC_R, KC_T
-#define ___QWERTY_L2___ KC_SFT_T_A, KC_S, KC_LT_MDIA_D, KC_LT_SYMB_F, KC_G
-#define ___QWERTY_L3___ KC_Z, KC_X, KC_C, KC_V, KC_B
+// COLEMAK-DH
+#define ___COLEMAK_DH_L1___ KC_Q, KC_W, KC_F, KC_P, KC_B
+#define ___COLEMAK_DH_L2___ KC_A, KC_R, KC_S, KC_T, KC_G
+#define ___COLEMAK_DH_L3___ KC_Z, KC_X, KC_C, KC_D, KC_V
-#define ___QWERTY_R1___ KC_Y, KC_U, KC_I, KC_O, KC_P
-#define ___QWERTY_R2___ KC_H, KC_LT_SYMB_J, KC_LT_MDIA_K, KC_L, KC_SFT_T_SCLN
-#define ___QWERTY_R3___ KC_N, KC_M, KC_COMM, KC_DOT, KC_SLASH
+#define ___COLEMAK_DH_R1___ KC_J, KC_L, KC_U, KC_Y, KC_SCLN
+#define ___COLEMAK_DH_R2___ KC_M, KC_N, KC_E, KC_I, KC_O
+#define ___COLEMAK_DH_R3___ KC_K, KC_H, KC_COMM, KC_DOT, KC_SLASH
-// COLEMAK
-#define ___COLEMAK_L1___ KC_Q, KC_W, KC_F, KC_P, KC_G
-#define ___COLEMAK_L2___ KC_SFT_T_A, KC_R, KC_LT_MDIA_S, KC_LT_SYMB_T, KC_D
-#define ___COLEMAK_L3___ KC_Z, KC_X, KC_C, KC_V, KC_B
+#define ___COLEMAK_DH___ ___COLEMAK_DH_L1___, ___COLEMAK_DH_R1___, \
+ ___COLEMAK_DH_L2___, ___COLEMAK_DH_R2___, \
+ ___COLEMAK_DH_L3___, ___COLEMAK_DH_R3___
-#define ___COLEMAK_R1___ KC_J, KC_L, KC_U, KC_Y, KC_SCLN
-#define ___COLEMAK_R2___ KC_H, KC_LT_SYMB_N, KC_LT_MDIA_E, KC_I, KC_SFT_T_O
-#define ___COLEMAK_R3___ KC_K, KC_M, KC_COMM, KC_DOT, KC_SLASH
-// COLEMAK-DH
-#define ___COLEMAK_DH_L1___ KC_Q, KC_W, KC_F, KC_P, KC_B
-#define ___COLEMAK_DH_L2___ KC_SFT_T_A, KC_R, KC_LT_MDIA_S, KC_LT_SYMB_T, KC_G
-#define ___COLEMAK_DH_L3___ KC_Z, KC_X, KC_C, KC_D, KC_V
+// WORKMAN
+#define ___WORKMAN_L1___ KC_Q, KC_D, KC_R, KC_W, KC_B
+#define ___WORKMAN_L2___ KC_A, KC_S, KC_H, KC_T, KC_G
+#define ___WORKMAN_L3___ KC_Z, KC_X, KC_M, KC_C, KC_V
-#define ___COLEMAK_DH_R1___ KC_J, KC_L, KC_U, KC_Y, KC_SCLN
-#define ___COLEMAK_DH_R2___ KC_M, KC_LT_SYMB_N, KC_LT_MDIA_E, KC_I, KC_SFT_T_O
-#define ___COLEMAK_DH_R3___ KC_K, KC_H, KC_COMM, KC_DOT, KC_SLASH
+#define ___WORKMAN_R1___ KC_J, KC_F, KC_U, KC_P, KC_SCLN
+#define ___WORKMAN_R2___ KC_Y, KC_N, KC_E, KC_O, KC_I
+#define ___WORKMAN_R3___ KC_K, KC_L, KC_COMM, KC_DOT, KC_SLASH
-// WORKMAN
-#define ___WORKMAN_L1___ KC_Q, KC_D, KC_R, KC_W, KC_B
-#define ___WORKMAN_L2___ KC_SFT_T_A, KC_S, KC_LT_MDIA_H, KC_LT_SYMB_T, KC_G
-#define ___WORKMAN_L3___ KC_Z, KC_X, KC_M, KC_C, KC_V
+#define ___WORKMAN___ ___WORKMAN_L1___, ___WORKMAN_R1___, \
+ ___WORKMAN_L2___, ___WORKMAN_R2___, \
+ ___WORKMAN_L3___, ___WORKMAN_R3___
-#define ___WORKMAN_R1___ KC_J, KC_F, KC_U, KC_P, KC_SCLN
-#define ___WORKMAN_R2___ KC_Y, KC_LT_SYMB_N, KC_LT_MDIA_E, KC_O, KC_SFT_T_I
-#define ___WORKMAN_R3___ KC_K, KC_L, KC_COMM, KC_DOT, KC_SLASH
// NORMAN
-#define ___NORMAN_L1___ KC_Q, KC_W, KC_D, KC_F, KC_K
-#define ___NORMAN_L2___ KC_SFT_T_A, KC_S, KC_LT_MDIA_E, KC_LT_SYMB_T, KC_G
-#define ___NORMAN_L3___ KC_Z, KC_X, KC_C, KC_V, KC_B
+#define ___NORMAN_L1___ KC_Q, KC_W, KC_D, KC_F, KC_K
+#define ___NORMAN_L2___ KC_A, KC_S, KC_E, KC_T, KC_G
+#define ___NORMAN_L3___ KC_Z, KC_X, KC_C, KC_V, KC_B
-#define ___NORMAN_R1___ KC_J, KC_U, KC_R, KC_L, KC_SCLN
-#define ___NORMAN_R2___ KC_Y, KC_LT_SYMB_N, KC_LT_MDIA_I, KC_O, KC_SFT_T_U
-#define ___NORMAN_R3___ KC_P, KC_M, KC_COMM, KC_DOT, KC_SLASH
+#define ___NORMAN_R1___ KC_J, KC_U, KC_R, KC_L, KC_SCLN
+#define ___NORMAN_R2___ KC_Y, KC_N, KC_I, KC_O, KC_U
+#define ___NORMAN_R3___ KC_P, KC_M, KC_COMM, KC_DOT, KC_SLASH
-// BEPO MAPS
-// Dvorak on fr-bepo software layer in the OS.
-// for dvorak and all the other qwerty like keyboards on bepo
-#define ___DVORAK_FR_L1___ DB_QUOT, DB_COMM, DB_DOT, BP_P, BP_Y
-#define ___DVORAK_FR_L2___ BP_SFT_T_A, BP_LT_KP_O, BP_LT_MDIA_E, BP_LT_SYMB_U, BP_I
-#define ___DVORAK_FR_L3___ DB_SCOLON, BP_Q, BP_J, BP_K, BP_X
+#define ___NORMAN___ ___NORMAN_L1___, ___NORMAN_R1___, \
+ ___NORMAN_L2___, ___NORMAN_R2___, \
+ ___NORMAN_L3___, ___NORMAN_R3___
-#define ___DVORAK_FR_R1___ BP_F, BP_G, BP_C, BP_R, BP_L
-#define ___DVORAK_FR_R2___ BP_D, BP_LT_SYMB_H, BP_LT_MDIA_T, BP_LT_KP_N, BP_SFT_T_S
-#define ___DVORAK_FR_R3___ BP_B, BP_M, BP_W, BP_V, BP_Z
+#define ___MALTRON_L1___ KC_Q, KC_P, KC_Y, KC_C, KC_B
+#define ___MALTRON_L2___ KC_A, KC_N, KC_I, KC_S, KC_F
+#define ___MALTRON_L3___ KC_SCLN, KC_SLSH, KC_J, KC_G, KC_COMM
-// Bepo on fr-bepo software layer
-// for bepo on bepo
-/* BP_DLR, BP_DQUO, BP_LDAQ, BP_RDAQ, BP_LPRN, BP_RPRN, KC_DEL, */
-#define ___SYMBOL_BEPO_L___ /* BP_DLR */ BP_DQUO, BP_LDAQ, BP_RDAQ, BP_LPRN, BP_RPRN
-/* KC_DEL, BP_AT, BP_PLUS, BP_MINS, BP_SLSH, BP_ASTR, BP_EQL, */
-#define ___SYMBOL_BEPO_R___ BP_AT, BP_PLUS, BP_MINS, BP_SLSH, BP_ASTR /* BP_EQL, BP_PERC */
+#define ___MALTRON_R1___ KC_V, KC_M, KC_U, KC_Z, KC_L
+#define ___MALTRON_R2___ KC_D, KC_T, KC_D, KC_O, KC_R
+#define ___MALTRON_R3___ KC_DOT, KC_W, KC_K, KC_MINS, KC_X
-#define ___BEPO_FR_L1___ BP_B, BP_EACU, BP_P, BP_O, BP_EGRV
-#define ___BEPO_FR_L2___ BP_SFT_T_A, BP_LT_KP_U, BP_LT_SYMB_I, BP_LT_MDIA_E, BP_COMM
-#define ___BEPO_FR_L3___ /*BP_ECIR*/ BP_AGRV, BP_Y, BP_X, BP_DOT, BP_K
+#define ___MALTRON___ ___MALTRON_L1___, ___MALTRON_R1___, \
+ ___MALTRON_L2___, ___MALTRON_R2___, \
+ ___MALTRON_L3___, ___MALTRON_R3___
-#define ___BEPO_FR_R1___ /* BP_DCIR,*/ BP_V, BP_D, BP_L, BP_J, BP_Z
-#define ___BEPO_FR_R2___ /* BP_C, */ BP_T, BP_LT_SYMB_S, BP_LT_MDIA_R, BP_LT_KP_N, BP_SFT_T_M //BP_CCED
-#define ___BEPO_FR_R3___ BP_QUOT, BP_Q, BP_G, BP_H, BP_F //BP_SFT_T_W
-/* BP_DLR, BP_DQUO, BP_LDAQ, BP_RDAQ, BP_LPRN, BP_RPRN, KC_DEL, */
-/* KC_TAB, BP_B, BP_EACU, BP_P, BP_O, BP_EGRV, KC_BSPC, */
-/* KC_LSFT, BP_A, BP_U, BP_I, BP_E, BP_COMM, */
-/* KC_LCTRL, BP_AGRV, BP_Y, BP_X, BP_DOT, BP_K, KC_ENT, */
-/* ESC_FN, BP_ECIR, KC_LGUI, KC_LALT, SPC_RALT, */
-/* TT(SWAP), KC_MNXT, */
-/* KC_MPLY, */
-/* TT(FN), TT(NUMS), KC_MPRV, */
+#define ___EUCALYN_L1___ KC_SLSH, KC_COMM, KC_DOT, KC_F, KC_Q
+#define ___EUCALYN_L2___ KC_A, KC_O, KC_E, KC_I, KC_U
+#define ___EUCALYN_L3___ KC_Z, KC_X, KC_C, KC_V, KC_W
-/* /\* right hand *\/ */
-/* KC_DEL, BP_AT, BP_PLUS, BP_MINS, BP_SLSH, BP_ASTR, BP_EQL, */
-/* KC_BSPC, BP_DCIR, BP_V, BP_D, BP_L, BP_J, BP_Z, */
-/* BP_C, BP_T, BP_S, BP_R, BP_N, M_RSFT, */
-/* KC_ENT, BP_QUOT, BP_Q, BP_G, BP_H, BP_F, W_RCTL, */
+#define ___EUCALYN_R1___ KC_M, KC_R, KC_D, KC_Y, KC_P
+#define ___EUCALYN_R2___ KC_G, KC_T, KC_K, KC_S, KC_N
+#define ___EUCALYN_R3___ KC_B, KC_H, KC_J, KC_L, KC_SCLN
+#define ___EUCALYN___ ___EUCALYN_L1___, ___EUCALYN_R1___, \
+ ___EUCALYN_L2___, ___EUCALYN_R2___, \
+ ___EUCALYN_L3___, ___EUCALYN_R3___
-/*******************************************************************/
-/** For the top rows. Numbers for most things, symbols for Bepo. **/
-/*******************************************************************/
-// for everything on qwerty.
-#define ___NUMBER_L___ KC_1, KC_2, KC_3, KC_4, KC_5
-#define ___NUMBER_R___ KC_6, KC_7, KC_8, KC_9, KC_0
+#define ___CARPLAX_QFMLWY_L1___ KC_Q, KC_F, KC_M, KC_L, KC_W
+#define ___CARPLAX_QFMLWY_L2___ KC_D, KC_S, KC_T, KC_N, KC_R
+#define ___CARPLAX_QFMLWY_L3___ KC_Z, KC_V, KC_G, KC_C, KC_X
-// function key rows, works for everyone.
-#define ___FUNC_L___ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5
-#define ___FUNC_R___ KC_F6, KC_F7, KC_F8, KC_F9, KC_F10
+#define ___CARPLAX_QFMLWY_R1___ KC_Y, KC_U, KC_O, KC_B, KC_J
+#define ___CARPLAX_QFMLWY_R2___ KC_I, KC_A, KC_E, KC_H, KC_SCLN
+#define ___CARPLAX_QFMLWY_R3___ KC_P, KC_K, KC_COMM, KC_DOT, KC_SLSH
-#define ___FUNC_1_6___ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6
-#define ___FUNC_7_12___ KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12
+#define ___CARPLAX_QFMLWY___ ___CARPLAX_QFMLWY_L1___, ___CARPLAX_QFMLWY_R1___, \
+ ___CARPLAX_QFMLWY_L2___, ___CARPLAX_QFMLWY_R2___, \
+ ___CARPLAX_QFMLWY_L3___, ___CARPLAX_QFMLWY_R3___
-// a top symbol row if someone wants it.
-#define ___SYMB_L___ KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC
-#define ___SYMB_R___ KC_CIRC, KC_AMPR, KC_AST, KC_LPRN, KC_RPRN
-// For numbers on bepo. Bepo has numbers on shifted keys, the
-// reverse of most keyboard layouts.
-#define ___NUMBER_BEPO_L___ DB_1, DB_2, DB_3, DB_4, DB_5
-#define ___NUMBER_BEPO_R___ DB_6, DB_7, DB_8, DB_9, DB_0
+#define ___CARPLAX_QGMLWB_L1___ KC_Q, KC_G, KC_M, KC_L, KC_W
+#define ___CARPLAX_QGMLWB_L2___ KC_D, KC_S, KC_T, KC_N, KC_R
+#define ___CARPLAX_QGMLWB_L3___ KC_Z, KC_X, KC_C, KC_F, KC_J
+#define ___CARPLAX_QGMLWB_R1___ KC_B, KC_Y, KC_U, KC_V, KC_SCLN
+#define ___CARPLAX_QGMLWB_R2___ KC_I, KC_A, KC_E, KC_O, KC_H
+#define ___CARPLAX_QGMLWB_R3___ KC_K, KC_P, KC_COMM, KC_DOT, KC_SLSH
-/*******************************************************************/
-/* keysets for the auxillary layers. */
-/* the KC_P? codes don't work for me. I don't use those shifted */
-/* values anyway. */
-/*******************************************************************/
-// Keypads
-#define ___KEYPAD_1___ KC_7, KC_8, KC_9, KC_PSLS
-#define ___KEYPAD_2___ KC_4, KC_5, KC_6, KC_PAST
-#define ___KEYPAD_3___ KC_1, KC_2, KC_3, KC_PMNS
-#define ___KEYPAD_4___ KC_0, KC_DOT, KC_PEQL, KC_PPLS
+#define ___CARPLAX_QGMLWB___ ___CARPLAX_QGMLWB_L1___, ___CARPLAX_QGMLWB_R1___, \
+ ___CARPLAX_QGMLWB_L2___, ___CARPLAX_QGMLWB_R2___, \
+ ___CARPLAX_QGMLWB_L3___, ___CARPLAX_QGMLWB_R3___
-// Keypad from the default keymap.c of the xd75
-#define ___KEYPAD_1_ALT___ KC_P7, KC_P8, KC_P9, KC_MINS
-#define ___KEYPAD_2_ALT___ KC_P4, KC_P5, KC_P6, KC_PLUS
-#define ___KEYPAD_3_ALT___ KC_P1, KC_P2, KC_P3, KC_PENT
-#define ___KEYPAD_4_ALT___ KC_P0, KC_DOT, KC_PENT, KC_PENT
-// For Bepo
-#define ___KEYPAD_1_BP___ DB_7, DB_8, DB_9, BP_SLSH
-#define ___KEYPAD_2_BP___ DB_4, DB_5, DB_6, BP_ASTR
-#define ___KEYPAD_3_BP___ DB_1, DB_2, DB_3, DB_MINUS
-#define ___KEYPAD_4_BP___ DB_0, DB_DOT, DB_EQL, BP_PLUS
+#define ___CARPLAX_QGMLWY_L1___ KC_Q, KC_G, KC_M, KC_L, KC_W
+#define ___CARPLAX_QGMLWY_L2___ KC_D, KC_S, KC_T, KC_N, KC_R
+#define ___CARPLAX_QGMLWY_L3___ KC_Z, KC_X, KC_C, KC_V, KC_J
+#define ___CARPLAX_QGMLWY_R1___ KC_Y, KC_F, KC_U, KC_B, KC_SCLN
+#define ___CARPLAX_QGMLWY_R2___ KC_I, KC_A, KC_E, KC_O, KC_H
+#define ___CARPLAX_QGMLWY_R3___ KC_K, KC_P, KC_COMM, KC_DOT, KC_SLSH
-// SYMBOLS
-// An arrangement for the left hand with a focus on the ()[]{}s.
-#define ___SYMBOLS_1___ KC_EXLM, KC_AT, KC_LCBR, KC_RCBR, KC_PIPE
-#define ___SYMBOLS_2___ KC_HASH, KC_DLR, KC_LPRN, KC_RPRN, KC_GRV
-#define ___SYMBOLS_3___ KC_PERC, KC_CIRC, KC_LBRC, KC_RBRC, KC_TILD
+#define ___CARPLAX_QGMLWY___ ___CARPLAX_QGMLWY_L1___, ___CARPLAX_QGMLWY_R1___, \
+ ___CARPLAX_QGMLWY_L2___, ___CARPLAX_QGMLWY_R2___, \
+ ___CARPLAX_QGMLWY_L3___, ___CARPLAX_QGMLWY_R3___
-// A larger 6 column arrangement for the left hand, A merge of dvorak and the above.
-#define ___SYMBOLS6_1___ KC_GRV, KC_LT, KC_GT, KC_LCBR, KC_RCBR, KC_HASH
-#define ___SYMBOLS6_2___ KC_AMPR, KC_AT, KC_ASTR, KC_LPRN, KC_RPRN, KC_PERC
-#define ___SYMBOLS6_3___ KC_DLR, KC_DQT, KC_QUOT, KC_LBRC, KC_RBRC, KC_COLON
-#define ___SYMBOLS6_4___ ___2___, KC_TILD, KC_DOT, KC_EXLM, KC_SCLN
-#define ___SYMBOLS5_4___ ___, KC_TILD, KC_DOT, KC_EXLM, KC_SCLN
+// BEPO Based Layouts.
+// Bepo, Dvorak and Beakl on fr-bepo software layer in the OS.
+// for dvorak and all the other qwerty like keyboards on bepo
+#define ___DVORAK_FR_L1___ DB_QUOT, DB_COMM, DB_DOT, BP_P, BP_Y
+#define ___DVORAK_FR_L2___ BP_A, BP_O, BP_E, BP_U, BP_I
+#define ___DVORAK_FR_L3___ DB_SCOLON, BP_Q, BP_J, BP_K, BP_X
+#define ___DVORAK_FR_R1___ BP_F, BP_G, BP_C, BP_R, BP_L
+#define ___DVORAK_FR_R2___ BP_D, BP_H, BP_T, BP_N, BP_S
+#define ___DVORAK_FR_R3___ BP_B, BP_M, BP_W, BP_V, BP_Z
-// A symbol pad. Basically the same layout as a number pad with the symbols
-// instead of the numbers with some extras around it, in familiar places for the
-// right hand.
-#define ___SYMPAD_1___ KC_GRV, KC_AMPR, KC_ASTR, KC_LCBR, KC_PLUS, KC_PIPE
-#define ___SYMPAD_2___ KC_TILD, KC_DLR, KC_PERC, KC_CIRC, KC_ASTR, KC_GRV
-#define ___SYMPAD_3___ ___, KC_EXLM, KC_AT, KC_HASH, KC_MINUS, KC_SLASH
-#define ___SYMPAD_4___ ___, KC_RCBR, KC_DOT, KC_EQUAL, KC_UNDS, KC_BSLASH
+#define ___DVORAK_FR___ ___DVORAK_FR_L1___, ___DVORAK_FR_R1___, \
+ ___DVORAK_FR_L2___, ___DVORAK_FR_R2___, \
+ ___DVORAK_FR_L3___, ___DVORAK_FR_R3___
-#define ___5_SYMPAD_4___ KC_RCBR, KC_DOT, KC_EQUAL, KC_UNDS, KC_BSLASH
+/* BEAKL 15 (main layer): */
-// Function pad. Same idea as above, but for function keys.
-#define ___FUNCPAD_T___ KC_F10, KC_F11, KC_F12
-#define ___FUNCPAD_1___ KC_F7, KC_F8, KC_F9
-#define ___FUNCPAD_2___ KC_F4, KC_F5, KC_F6
-#define ___FUNCPAD_3___ KC_F1, KC_F2, KC_F3
+#define ___DVORAK6_FR_L1___ DB_GRV, ___DVORAK_FR_L1___
+#define ___DVORAK6_FR_L2___ TAB_BKTAB, ___DVORAK_FR_L2___
+#define ___DVORAK6_FR_L3___ ___, ___DVORAK_FR_L3___
+#define ___DVORAK6_FR_R1___ ___DVORAK_FR_R1___, BP_MIN
+#define ___DVORAK6_FR_R2___ ___DVORAK_FR_R2___, BP_SLSH
+#define ___DVORAK6_FR_R3___ ___DVORAK_FR_R3___, DB_BACKSLASH
-//--- all over again for BEPO
+#define ___6DVORAK_FR___ ___6DVORAK_FR_L1___, ___6DVORAK_FR_R1___, \
+ ___6DVORAK_FR_L2___, ___6DVORAK_FR_R2___, \
+ ___6DVORAK_FR_L3___, ___6DVORAK_FR_R3___
+
+// dont forget ; and -. the 'a' home row is official placement.
+#define ___BEAKL15_FR_L1___ BP_Q, BP_H, BP_O, BP_U, BP_X
+#define ___BEAKL15_FR_L2___ BP_Y, BP_I, BP_E, BP_A, BB_DOT
+#define ___BEAKL15_FR_L2a___ BP_MIN, BP_Y, BP_I, BP_E, BP_A, BB_DOT
+#define ___BEAKL15_FR_L3___ BP_J, BP_SLSH, BB_COMM, BP_K, BB_QUOT
+
+#define ___BEAKL15_FR_R1___ BP_G, BP_C, BP_R, BP_F, BP_Z
+#define ___BEAKL15_FR_R2___ BP_D, BP_S, BP_T, BP_N, BP_B
+#define ___BEAKL15_FR_R2a___ BP_D, BP_S, BP_T, BP_N, BP_B, DB_SCLN
+#define ___BEAKL15_FR_R3___ BP_W, BP_M, BP_L, BP_P, BP_V
+
+#define ___6BEAKL15_FR___ ___, ___BEAKL15_FR_L1___, ___BEAKL15_FR_R1___, ___, \
+ ___BEAKL15_FR_L2a___, ___BEAKL15_FR_R2a___, \
+ ___, ___BEAKL15_FR_L3___, ___BEAKL15_FR_R3___, ___
+
+#define ___BEAKL15_FR___ ___BEAKL15_FR_L1___, ___BEAKL15_FR_R1___, \
+ ___BEAKL15_FR_L2___, ___BEAKL15_FR_R2___, \
+ ___BEAKL15_FR_L3___, ___BEAKL15_FR_R3___
+
+#define ___BEPO_L1___ BP_B, BP_EACU, BP_P, BP_O, BP_EGRV
+#define ___BEPO_L2___ BP_A, BP_U, BP_I, BP_E, BP_COMM
+#define ___BEPO_L3___ /*BP_ECRC*/ BP_AGRV, BP_Y, BP_X, BP_DOT, BP_K
+
+#define ___BEPO_R1___ /* BP_DCRC,*/ BP_V, BP_D, BP_L, BP_J, BP_Z
+#define ___BEPO_R2___ /* BP_C, */ BP_T, BP_S, BP_R, BP_N, BP_M //BP_CCED
+#define ___BEPO_R3___ BP_QUOT, BP_Q, BP_G, BP_H, BP_F //BP_SFT_T_W
+
+// Bepo for a 3x6 split. CCED switched hands. :-( 'Altgr-c c' does the same.
+// W has to drop down to the bottom. Silly unbalanced layout.
+#define ___BEPO6_L1___ BP_CCED, ___BEPO_L1___
+#define ___BEPO6_L2___ TAB_BKTAB, ___BEPO_L2___
+#define ___BEPO6_L3___ BP_ECIR, ___BEPO_L3___
+
+#define ___BEPO6_R1___ ___BEPO_R1___, BP_PERC
+#define ___BEPO6_R2___ ___BEPO_R2___, BP_C
+#define ___BEPO6_R3___ ___BEPO_R3___, BP_W
+
+#define ___BEPO6___ ___BEPO6_L1___, ___BEPO6_R1___, \
+ ___BEPO6_L2___, ___BEPO6_R2___, \
+ ___BEPO6_L3___, ___BEPO6_R3___
+
+#define ___BEPO___ ___BEPO_L1___, ___BEPO_R1___, \
+ ___BEPO_L2___, ___BEPO_R2___, \
+ ___BEPO_L3___, ___BEPO_R3___
+
+
+/*******************************************************************/
+/** TOP ROWS Func,Symbols, Numbers you find there. **/
+/*******************************************************************/
+// for everything on qwerty.
+#define ___NUMBER_L___ KC_1, KC_2, KC_3, KC_4, KC_5
+#define ___NUMBER_R___ KC_6, KC_7, KC_8, KC_9, KC_0
+
+#define ___NUMBER_BEAKL15_L___ KC_4, KC_0, KC_1, KC_2, KC_3
+#define ___NUMBER_BEAKL15_R___ KC_7, KC_6, KC_5, KC_9, KC_8
+
+// a top symbol row if someone wants it.
+#define ___SYMB_L___ KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC
+#define ___SYMB_R___ KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN
+
+/// BEPO ////
+// For numbers on bepo. Bepo has numbers on shifted keys, the
+// reverse of many layouts.
+#define ___NUMBER_BEPO_L___ DB_1, DB_2, DB_3, DB_4, DB_5
+#define ___NUMBER_BEPO_R___ DB_6, DB_7, DB_8, DB_9, DB_0
+
+// In case you want to try BEAKL 15 Numbers
+#define ___NUMBER_BEAKL15_BP_L___ DB_4, DB_0, DB_1, DB_2, DB_3
+#define ___NUMBER_BEAKL15_BP_R___ DB_7, DB_6, DB_5, DB_9, DB_8
-// SYMBOLS FOR BEPO
// The top row. Bepo has symbols not numbers. Numbers are the shifted values.
+// There are actually 13 keys specified for bepo.
#define ___SYMBOL_BEPO_L___ /* BP_DLR */ BP_DQUO, BP_LDAQ, BP_RDAQ, BP_LPRN, BP_RPRN
-/* KC_DEL, BP_AT, BP_PLUS, BP_MINS, BP_SLSH, BP_ASTR, BP_EQL, */
#define ___SYMBOL_BEPO_R___ BP_AT, BP_PLUS, BP_MINS, BP_SLSH, BP_ASTR /* BP_EQL, BP_PERC */
-// An arrangement for the left hand with a focus on the ()[]{}s.
-#define ___SYMBOLS_1_BP___ KC_EXLM, BP_AT, DB_LCBR, DB_RCBR, DB_PIPE
-#define ___SYMBOLS_2_BP___ DB_HASH, BP_DLR, DB_LPRN, DB_RPRN, DB_GRV
-#define ___SYMBOLS_3_BP___ BP_PERC, DB_CIRC, DB_LBRC, DB_RBRC, DB_TILD
-
-// A larger 6 column arrangement for the left hand, A merge of dvorak and the above.
-#define ___SYMBOLS6_1_BP___ DB_GRV, DB_LESS, DB_GRTR, DB_LCBR, DB_RCBR, DB_HASH
-#define ___SYMBOLS6_2_BP___ KC_AMPR, BP_AT, BP_ASTR, DB_LPRN, DB_RPRN, BP_PERC
-#define ___SYMBOLS6_3_BP___ BP_DLR, BP_DQUO, DB_QUOT, DB_LBRC, DB_RBRC, KC_COLON
-#define ___SYMBOLS6_4_BP___ ___2___, DB_TILD, DB_DOT, KC_EXLM, DB_SCOLON
-
-#define ___SYMBOLS5_4_BP___ ___, DB_TILD, DB_DOT, KC_EXLM, DB_SCOLON
-
-// A symbol pad. Basically the same layout as a number pad with the symbols
-// instead of the numbers with some extras around it, in familiar places for the
-// right hand.
-#define ___SYMPAD_1_BP___ DB_GRV, BP_AMPR, BP_ASTR, DB_LCBR, BP_PLUS, DB_PIPE
-#define ___SYMPAD_2_BP___ DB_TILD, BP_DLR, BP_PERC, DB_CIRC, BP_ASTR, DB_GRV
-#define ___SYMPAD_3_BP___ ___, BP_EXLM, BP_AT, DB_HASH, BP_MINS, BP_SLSH
-#define ___SYMPAD_4_BP___ ___, DB_RCBR, DB_DOT, BP_EQL, BP_MINS, DB_BACKSLASH
-
-#define ___5_SYMPAD_4_BP___ DB_RCBR, DB_DOT, BP_EQL, BP_MINS, DB_BACKSLASH
-
-// Parts are parts.
-// MOUSE, ARROW and MEDIA KEY SETS
-#define ___MOUSE_LDUR___ KC_MS_L, KC_MS_D, KC_MS_U, KC_MS_R
-#define ___MWHEEL_LDUR___ KC_WH_L, KC_WH_D, KC_WH_U, KC_WH_R
-#define ___MOUSE_BTNS_R___ KC_BTN1, KC_BTN2, KC_BTN3, KC_BTN4, KC_BTN5
-#define ___MOUSE_BTNS_L___ KC_BTN5, KC_BTN4, KC_BTN3, KC_BTN2, KC_BTN1
-#define ___MOUSE_ACCL_012___ KC_ACL0, KC_ACL1, KC_ACL2
-#define ___MACCL___ ___MOUSE_ACCL_012___
-
-#define ___PRV_PLAY_NXT_STOP KC_MPRV, KC_MPLY, KC_MNXT, KC_MSTP
-#define ___VDN_MUTE_VUP___ KC_VOLD, KC_MUTE, KC_VOLU
-
-#define ___MUTE_PRV_PLAY_NXT_STOP___ KC_MUTE, KC_MPRV, KC_MPLY, KC_MNXT, KC_MSTP
-#define ___MUTE_PLAY_STOP___ KC_MUTE, KC_MPLY, KC_MSTP
-#define ___VI_ARROWS___ KC_LEFT, KC_DOWN, KC_UP, KC_RIGHT
-
-// RGB FUNCTION Keysets
-// RGB row for the _FN layer from the redo of the default keymap.c
-#define ___RGB_HUE_SAT_INT_UP___ RGB_HUI, RGB_SAI, RGB_VAI, RGB_RMOD
-#define ___RGB_HUE_SAT_INT_DN___ RGB_HUD, RGB_SAD, RGB_VAD, RGB_MOD
-#define ___RGB_MODE_PRV_NXT___ RGB_RMOD, RGB_MOD
-#define ___RGB_TOGGLE___ RGB_TOG
-#define ___RGB_P_B_R_SW_SN___ RGB_M_P, RGB_M_B, RGB_M_R, RGB_M_SW, RGB_M_SN
-#define ___RGB_KXGT___ RGB_M_K, RGB_M_X, RGB_M_G, RGB_M_T
-
-// Print screen, screen lock, pause
-#define ___PSCR_SLCK_PAUS___ KC_PSCR, KC_SLCK, KC_PAUS
-
-// LAYER Keyset rows. Changing the Default base layer or the transient layers.
-// Some are full length. The baselayers leave the ends open. hence a 13.
-// for an ORtho 15.
-#define ___2_LAYERS_B1___ DF(BEPO), DF(DVORAK_ON_BEPO)
-#define ___2_LAYERS_B2___ DF(COLEMAK), DF(DVORAK)
-#define ___3_LAYERS_B3___ DF(QWERTY), DF(NORMAN), DF(WORKMAN)
-#define ___3_LAYERS_B4___ ___X3___
-// transient layers.
-#define ___3_LAYERS_T_BP___ TO(MDIA), TO(SYMB_ON_BEPO), TO(KEYPAD_ON_BEPO)
-#define ___3_LAYERS_T___ TO(MDIA), TO(SYMB), TO(KEYPAD)
-#define ___3_LAYERS_T_CTL___ TO(_RGB), ___X2___
+#define ___6SYMBOL_BEPO_L___ BP_DLR, ___SYMBOL_BEPO_L___
+#define ___6SYMBOL_BEPO_R___ ___SYMBOL_BEPO_R___, BP_EQL /* BP_PERC */
+
+// a top qwerty style symbol row if someone wants it.
+#define ___SYMB_L_FR___ DB_EXLM, BP_AT, BP_HASH, BP_DLR, BP_PERC
+#define ___SYMB_R_FR___ DB_CIRC, BP_AMPR, BP_ASTR, BP_LPRN, BP_RPRN
+
+
+// function key rows, works for everyone.
+#define ___FUNC_L___ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5
+#define ___FUNC_R___ KC_F6, KC_F7, KC_F8, KC_F9, KC_F10
+
+#define ___FUNC_1_6___ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6
+#define ___FUNC_7_12___ KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12
+
+#define ___FUNC_BEAKL_L___ KC_F4, KC_F10, KC_F1, KC_F2, KC_F3
+#define ___FUNC_BEAKL_R___ KC_F7, KC_F6, KC_F5, KC_F9, KC_F8
+
+#define ___12_FUNC_BEAKL___ KC_F11, ___FUNC_BEAKL_L___, ___FUNC_BEAKL_R___, KC_F12
+
+// Altogether. Defines all the various top rows that
+// are present with all these layouts.
+// All together as blocks of 10
+#define ___NUMS___ ___NUMBER_L___, ___NUMBER_R___
+#define ___SYMS___ ___SYMB_L___, ___SYMB_R___
+#define ___BKLNUMS___ ___NUMBER_BEAKL15_L___, ___NUMBER_BEAKL15_R___
+#define ___NUMS_BP___ ___NUMBER_BEPO_L___, ___NUMBER_BEPO_R___
+#define ___SYMS_BEPO___ ___SYMBOL_BEPO_L___, ___SYMBOL_BEPO_L___
+#define ___BKLNUMS_BP___ ___NUMBER_BEAKL15_BP_L___, ___NUMBER_BEAKL15_BP_R___
+#define ___FUNCS_1_10___ ___FUNC_L___, ___FUNC_R___
diff --git a/users/ericgebhart/edge_keys.h b/users/ericgebhart/edge_keys.h
new file mode 100644
index 0000000000..f37425322c
--- /dev/null
+++ b/users/ericgebhart/edge_keys.h
@@ -0,0 +1,238 @@
+#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "core_keysets.h"
+
+/******************************************************************/
+/* This is where I put my Keyboard layouts, Everything on the */
+/* edges, the functions on keys like LT() and SFT_T() */
+/* can be applied here. The physical shape of the keyboard is */
+/* also accounted for here. This makes it very simple to add a */
+/* new keyboard and reuse all of my layouts and layers */
+/* */
+/* The particular pieces we define here (as needed) are: */
+/* * Edge pinky keys, */
+/* * Middle section keys */
+/* * Bottom/5th row */
+/* * Thumbkeys */
+/* * Any functional additions to wrap the keys. ie. LT() */
+/* */
+/* With all of that in hand, we then create a LAYOUT wrapper */
+/* macro that takes a list of keys, to create a keyboard matrix */
+/* that fits the keyboard. Simple. */
+/* */
+/* The thumb keys, the bottom rows, etc. */
+/* */
+/* An attempt has been made to adapt the kinesis and ergodox */
+/* Thumb keys to the rectangular shapes of the xd75 and viterbi. */
+/* which are 15x and 14x matrices respectively. */
+/* The Corne was a perfect fit */
+/******************************************************************/
+
+/******************************************************************/
+/* * The XD75 is a 5x15 Ortholinear matrix which means it has 3 */
+/* keys inbetween the usual left and right hand keys */
+/* * The Viterbi is a split 5x14 Ortholinear with 2 middle keys. */
+/* * The Ergodox is a split 5x14 Ortholinear with 2 middle keys, */
+/* thumbkeys. It is missing middle keys on (home) row 3. */
+/* * The Corne is a split 3x12 with 6 thumb keys. It has no */
+/* extra middle keys */
+/* */
+/******************************************************************/
+
+
+/******************************************************************/
+/* In all cases these keyboards are defined in a matrix which is */
+/* a set of rows. Maybe like so, or not. */
+/* */
+/* -------------------------|------------------------ */
+/* | Left0 | Numbers L | mid|dle0 | numbers R | Right0 | */
+/* | Left1 | keys0-5 | mid|dle1 | Keys6-10 | Right1 | */
+/* | Left2 | keys11-15 | mid|dle2 | Keys16-20 | Right2 | */
+/* | Left3 | keys20-25 | mid|dle3 | Keys25-30 | Right3 | */
+/* | Row5L | Row5R | */
+/* | ThumbsL | ThumbsR | */
+/* -------------------------|------------------------ */
+
+/* Generally speaking, the keys on the right and left don't change. */
+/* Neither does the bottom row or the thumbs. Frequently the numbers */
+/* row is identical across layers. Mostly, we want our Base layers to */
+/* be predctable. */
+
+// EDGES
+// outside pinky keys row 0-3.
+// Qwerty and Bepo, - Applies
+// to foreign layouts on bepo. dvorak_bp, beakl_bp.
+#define LEFT0 KC_GRV
+#define LEFT1 KC_GRV
+#define LEFT2 KC_TAB
+#define LEFT3 KC_BSLASH
+//#define LEFT3 KC_COLN
+
+#define LEFT0_BP DB_GRV
+#define LEFT1_BP DB_GRV
+#define LEFT2_BP KC_TAB
+#define LEFT3_BP DB_BACKSLASH
+//#define LEFT3_BP BP_COLN
+
+#define RIGHT0 KC_EQL
+#define RIGHT1 KC_SLASH
+#define RIGHT2 KC_MINS
+#define RIGHT3 KC_SCLN
+
+#define RIGHT0_BP BP_EQL
+#define RIGHT1_BP BP_SLSH
+#define RIGHT2_BP BP_MINS
+#define RIGHT3_BP BP_SCLN
+
+/******************************************************************/
+/* Middle Keysets for various keyboards */
+// MIDDLES
+/// Middle left and right keys.
+/******************************************************************/
+#define ___MIDDLE_LT___ OSL(_LAYERS)
+#define ___MIDDLE_L1___ KC_CCCV
+#define ___MIDDLE_L2___ TO(_SYMB)
+#define ___MIDDLE_L3___ TO(_NAV)
+
+#define ___MIDDLE_RT___ _X_
+#define ___MIDDLE_R1___ KC_CCCV
+#define ___MIDDLE_R2___ TO(_TOPROWS)
+#define ___MIDDLE_R3___ OSL(_KEYPAD)
+
+#define ___MIDDLE_L1_BP___ BP_CCCV
+#define ___MIDDLE_L2_BP___ TO(_SYMB_BP)
+
+#define ___MIDDLE_R1_BP___ BP_CCCV
+#define ___MIDDLE_R2_BP___ TO(_KEYPAD_BP)
+#define ___MIDDLE_R3_BP___ OSL(_KEYPAD_BP)
+
+// 3 keys in the middle of a 15x matrix
+#define ___3_MIDDLE_T___ ___MIDDLE_LT___, LCTL(KC_A), ___MIDDLE_RT___
+#define ___3_MIDDLE_1___ ___MIDDLE_L1___, LCTL(KC_X), ___MIDDLE_R1___
+#define ___3_MIDDLE_2___ ___MIDDLE_L2___, TO(_RGB), ___MIDDLE_R2___
+#define ___3_MIDDLE_3___ ___MIDDLE_L3___, TO(_SYMB), ___MIDDLE_R3___
+
+// The same, for BEPO
+#define ___3_MIDDLE_T_BP___ ___MIDDLE_LT___, LCTL(BP_A), ___MIDDLE_RT___
+#define ___3_MIDDLE_1_BP___ ___MIDDLE_L1_BP___, LCTL(BP_X), ___MIDDLE_R1_BP___
+#define ___3_MIDDLE_2_BP___ ___MIDDLE_L2_BP___, TO(_RGB), ___MIDDLE_R2_BP___
+#define ___3_MIDDLE_3_BP___ ___MIDDLE_L3___, TO(_SYMB_BP), ___MIDDLE_R3_BP___
+
+// 2 keys in the middle of a 14x matrix - For viterbi and ergodox.
+#define ___2_MIDDLE_T___ ___MIDDLE_LT___, ___MIDDLE_RT___
+#define ___2_MIDDLE_1___ ___MIDDLE_L1___, ___MIDDLE_R1___
+#define ___2_MIDDLE_2___ ___MIDDLE_L2___, ___MIDDLE_R2___
+#define ___2_MIDDLE_3___ ___MIDDLE_L3___, ___MIDDLE_R3___
+
+// The same, for BEPO
+#define ___2_MIDDLE_T_BP___ ___MIDDLE_LT___, ___MIDDLE_RT___
+#define ___2_MIDDLE_1_BP___ ___MIDDLE_L1_BP___, ___MIDDLE_R1_BP___
+#define ___2_MIDDLE_2_BP___ ___MIDDLE_L2_BP___, ___MIDDLE_R2_BP___
+#define ___2_MIDDLE_3_BP___ ___MIDDLE_L3___, ___MIDDLE_R3_BP___
+
+/********************************************************************/
+/* THUMBS */
+/* Define the thumb clusters for all the keyboards. */
+/********************************************************************/
+
+// for xd75 or other layouts with a center column.
+// #define ___5_MIDDLE_THUMBS___ CTL_BSPC, ALT_DEL, XMONAD_ESC, ALT_ENT, CTL_SPC
+#define ___5_MIDDLE_THUMBS___ ALT_DEL, BSPC_TOPR, ESC_SYMB, ENT_NAV, SPC_TOPR
+#define ___5_MIDDLE_THUMBS_BP___ ALT_DEL, BSPC_TOPR_BP, ESC_SYMB_BP, ENT_NAV, SPC_TOPR_BP
+
+// for a last, 4th thumb row. for rebound.
+// backtab, home end, ----, pgup, pgdn, tab ?
+#define ___13_BOTTOM___ \
+ KC_BKTAB, HOME_END, KC_TAB, TT(_NAV), BSPC_SYMB, ESC_TOPR, \
+ OSL(_LAYERS), \
+ ENT_NAV, SPC_TOPR, KC_LEFT, KC_PGUP, KC_PGDN, KC_RIGHT
+
+#define ___13_BOTTOM_BP___ \
+ KC_BKTAB, HOME_END, KC_TAB, TT(_NAV), BSPC_SYMB_BP, ESC_TOPR_BP, \
+ OSL(_LAYERS), \
+ ENT_NAV, SPC_TOPR_BP, KC_LEFT, KC_PGUP, KC_PGDN, KC_RIGHT
+
+// becomes the upper thumbs, the real 4th row if we throw away
+// the number row at the top.
+// this is the 4th row on the viterbi above the thumbrow if the number
+// row is not used for numbers.
+#define ___4_MIDDLE_4___ LSFT(KC_TAB), HOME_END, KC_PGDN, KC_TAB
+#define ___4_MIDDLE_4b___ TAB_BKTAB, HOME_END, KC_PGDN, KC_PGUP
+
+/********************************************************************/
+/** The bottom row and thumbs as needed. **/
+/********************************************************************/
+// I do not use those pinky keys. I had useful things there but there
+// are better more useful ways than those pinkys.
+#define ___5_BOTTOM_LEFT___ ___X2___, KC_INS, KC_LEFT, KC_RIGHT
+#define ___5_BOTTOM_RIGHT___ KC_UP, KC_DOWN, KC_BSLASH, ___X2___
+
+#define ___4_BOTTOM_LEFT___ LCTL(KC_V), KC_INS, KC_LEFT, KC_RIGHT
+#define ___4_BOTTOM_RIGHT___ KC_UP, KC_DOWN, KC_BSLASH, LCTL(KC_C)
+
+// the bottom rows for keyboards on bepo.
+// bepo on bepo - not enough space to go around....
+#define ___5_BOTTOM_LEFT_BP___ _X_, BP_EACU, _X_, KC_LEFT, KC_RIGHT
+#define ___5_BOTTOM_RIGHT_BP___ KC_UP, KC_DOWN, DB_BACKSLASH, BP_CCED, BP_PERC
+
+#define ___4_BOTTOM_LEFT_BP___ LCTL(BP_C), BP_EACU, KC_LEFT, KC_RIGHT
+#define ___4_BOTTOM_RIGHT_BP___ KC_UP, KC_DOWN, DB_BACKSLASH, BP_CCED
+
+// for dvorak and beakl on bepo
+#define ___5_BOTTOM_LEFT_FR___ ___X3___, KC_LEFT, KC_RIGHT
+#define ___5_BOTTOM_RIGHT_FR___ KC_UP, KC_DOWN, DB_BACKSLASH, ___X2___
+
+// basically a 5th row in a 5x matrix. but maybe a 4th if there isnt a number row.
+#define ___15_BOTTOM___ ___5_BOTTOM_LEFT___, ___5_MIDDLE_THUMBS___, ___5_BOTTOM_RIGHT___
+#define ___15_BOTTOM_FR___ ___5_BOTTOM_LEFT_FR___, ___5_MIDDLE_THUMBS___, ___5_BOTTOM_RIGHT_FR___
+#define ___15_BOTTOM_BP___ ___5_BOTTOM_LEFT_BP___, ___5_MIDDLE_THUMBS___, ___5_BOTTOM_RIGHT_BP___
+
+#define ___14_BOTTOM___ ___5_BOTTOM_LEFT___, ___4_MIDDLE_4b___, ___5_BOTTOM_RIGHT___
+#define ___14_BOTTOM_FR___ ___5_BOTTOM_LEFT_FR___, ___4_MIDDLE_4b___, ___5_BOTTOM_RIGHT_FR___
+#define ___14_BOTTOM_BP___ ___5_BOTTOM_LEFT_BP___, ___4_MIDDLE_4b___, ___5_BOTTOM_RIGHT_BP___
+#define ___14_THUMBS_BOTTOM___ ___X4___, ___6_MIDDLE_THUMBS___, ___X4___
+
+// bottom row of ergodox thumbs, bottom middle of all layouts.
+// start with the minimilist thumb row of 6, like the Corne, 2x3.
+
+#define ___THUMBS_1___ TT(_KEYPAD), MO(_ADJUST), MO(_LAYERS), OSL(_TOPROWS)
+#define ___THUMBS_1_BP___ TT(_KEYPAD_BP), MO(_ADJUST), MO(_LAYERS), OSL(_TOPROWS_BP)
+#define ___THUMBS_2___ HOME_END, KC_PGUP
+#define ___THUMBS_3___ ___6_ERGO_THUMBS___
+
+#define ___4_THUMBS_1_BP___ TT(_KEYPAD_BP), KC_HOME, KC_PGUP, OSL(_TOPROWS_BP)
+#define ___4_THUMBS_1___ TT(_KEYPAD), KC_HOME, KC_PGUP, OSL(_TOPROWS)
+#define ___6_THUMBS_2___ KC_LSFT, KC_BKTAB, KC_END, KC_PGDN, KC_TAB, KC_RSFT
+
+#define ___6_THUMBS_2b___ BSPC_SYMB, ESC_TOPR, KC_END, KC_PGUP, ENT_NAV, SPC_TOPR
+#define ___6_ERGO_THUMBSb___ TT(_LAYERS), BSPC_SYMB, KC_XM_PORD, KC_PGDN, TT(_NAV), KC_XM_PORD
+#define ___6_THUMBS_2b_BP___ BSPC_SYMB_BP, ESC_TOPR_BP, KC_END, KC_PGDN, ENT_TOPR_BP, SPC_NAV
+
+#define ___6_ERGO_THUMBS___ TT(_NAV), BSPC_SYMB, ESC_TOPR, ENT_NAV, SPC_TOPR, KC_XM_PORD
+#define ___6_ERGO_THUMBS_BP___ TT(_NAV), BSPC_SYMB_BP, ESC_TOPR, ENT_NAV, SPC_TOPR_BP, BP_XM_PORD
+
+#define ___6_MIDDLE_THUMBS___ ___6_ERGO_THUMBS___
+
+#define ___12_DOX_ALL_THUMBS___ ___THUMBS_1___, ___THUMBS_2___, ___THUMBS_3___
+#define ___12_DOX_ALL_THUMBS_BP___ ___THUMBS_1_BP___, ___THUMBS_2___, ___THUMBS_3___
+
+#define ___16_ALL_THUMBSb___ ___4_THUMBS_1___, ___6_THUMBS_2b___, ___6_ERGO_THUMBSb___
+#define ___16_ALL_THUMBS___ ___4_THUMBS_1___, ___6_THUMBS_2___, ___6_ERGO_THUMBS___
+#define ___16_ALL_THUMBSb_BP___ ___4_THUMBS_1_BP___, ___6_THUMBS_2b_BP___, ___6_ERGO_THUMBS___
+#define ___16_ALL_THUMBS_BP___ ___4_THUMBS_1_BP___, ___6_THUMBS_2_BP___, ___6_ERGO_THUMBS_BP___
diff --git a/users/ericgebhart/ericgebhart.c b/users/ericgebhart/ericgebhart.c
index d34563865d..2a34110ae2 100644..100755
--- a/users/ericgebhart/ericgebhart.c
+++ b/users/ericgebhart/ericgebhart.c
@@ -27,12 +27,8 @@
float tone_copy[][2] = SONG(SCROLL_LOCK_ON_SOUND);
float tone_paste[][2] = SONG(SCROLL_LOCK_OFF_SOUND);
-static uint16_t copy_paste_timer;
userspace_config_t userspace_config;
-void tap(uint16_t keycode){ register_code(keycode); unregister_code(keycode); };
-
-
// Add reconfigurable functions here, for keymap customization
// This allows for a global, userspace functions, and continued
// customization of the keymap. Use _keymap instead of _user
@@ -44,595 +40,9 @@ __attribute__ ((weak))
void matrix_scan_keymap(void) {}
__attribute__ ((weak))
-bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
- return true;
-}
-
-__attribute__ ((weak))
-bool process_record_secrets(uint16_t keycode, keyrecord_t *record) {
- return true;
-}
-
-__attribute__ ((weak))
uint32_t layer_state_set_keymap (uint32_t state) {
return state;
}
__attribute__ ((weak))
void led_set_keymap(uint8_t usb_led) {}
-
-// check default layerstate to see which layer we are on.
-// if (biton32(layer_state) == _DIABLO) { --- current layer
-// if (biton32(default_layer_state) == _DIABLO) { --- current default layer
-// check for left shift on.
-// if (mods & MOD_BIT(KC_LSFT)) register_code(KC_LSFT);
-
-static void switch_default_layer(uint8_t layer) {
- default_layer_set(1UL<<layer);
- clear_keyboard();
-}
-
-// so the keyboard remembers which layer it's in after power disconnect.
-/*
- uint32_t default_layer_state_set_kb(uint32_t state) {
- eeconfig_update_default_layer(state);
- return state;
- }
-*/
-
-// These are the keys for dvorak on bepo. column one is the keycode and mods for
-// the unshifted key, the second column is the keycode and mods for the shifted key.
-// GR is Good Range. It subtracts SAFE_RANGE from the keycode so we can make a
-// reasnably sized array without difficulties. The macro is for the constant declarations
-// the function is for when we use it.
-const uint8_t key_translations[][2][2] = {
- [GR(DB_1)] = {{BP_DQUO, MOD_LSFT}, {BP_DCIR, MOD_LSFT}},
- [GR(DB_2)] = {{BP_LDAQ, MOD_LSFT}, {BP_AT, MOD_NONE}},
- [GR(DB_3)] = {{BP_RDAQ, MOD_LSFT}, {BP_DLR, MOD_LSFT}},
- [GR(DB_4)] = {{BP_LPRN, MOD_LSFT}, {BP_DLR, MOD_NONE}},
- [GR(DB_5)] = {{BP_RPRN, MOD_LSFT}, {BP_PERC, MOD_NONE}},
- [GR(DB_6)] = {{BP_AT, MOD_LSFT}, {BP_AT, MOD_BIT(KC_RALT)}},
- [GR(DB_7)] = {{BP_PLUS, MOD_LSFT}, {BP_P, MOD_BIT(KC_RALT)}},
- [GR(DB_8)] = {{BP_MINS, MOD_LSFT}, {BP_ASTR, MOD_NONE}},
- [GR(DB_9)] = {{BP_SLSH, MOD_LSFT}, {BP_LPRN, MOD_NONE}},
- [GR(DB_0)] = {{BP_ASTR, MOD_LSFT}, {BP_RPRN, MOD_NONE}},
- [GR(DB_GRV)] = {{BP_PERC, MOD_LSFT}, {BP_K, MOD_BIT(KC_RALT)}},
- [GR(DB_SCOLON)] = {{BP_COMM, MOD_LSFT}, {BP_DOT, MOD_LSFT}},
- [GR(DB_SLASH)] = {{BP_SLSH, MOD_NONE}, {BP_QUOT, MOD_LSFT}},
- [GR(DB_BACKSLASH)] = {{BP_AGRV, MOD_BIT(KC_RALT)}, {BP_B, MOD_BIT(KC_RALT)}},
- [GR(DB_EQL)] = {{BP_EQL, MOD_NONE}, {BP_PLUS, MOD_NONE}},
- [GR(DB_COMM)] = {{BP_COMM, MOD_NONE}, {BP_LDAQ, MOD_BIT(KC_RALT)}},
- [GR(DB_DOT)] = {{BP_DOT, MOD_NONE}, {BP_RDAQ, MOD_BIT(KC_RALT)}},
- [GR(DB_QUOT)] = {{BP_QUOT, MOD_NONE}, {BP_DQUO, MOD_NONE}},
- [GR(DB_MINUS)] = {{BP_MINS, MOD_NONE}, {KC_SPC, MOD_BIT(KC_RALT)}},
- [GR(DB_LPRN)] = {{BP_LPRN, MOD_NONE}, {BP_LPRN, MOD_BIT(KC_RALT)}},
- [GR(DB_RPRN)] = {{BP_RPRN, MOD_NONE}, {BP_RPRN, MOD_BIT(KC_RALT)}},
- [GR(DB_LBRC)] = {{BP_Y, MOD_BIT(KC_RALT)}, {BP_LPRN, MOD_BIT(KC_RALT)}},
- [GR(DB_RBRC)] = {{BP_X, MOD_BIT(KC_RALT)}, {BP_RPRN, MOD_BIT(KC_RALT)}},
- // For the symbol layer
- [GR(DB_HASH)] = {{BP_DLR, MOD_LSFT}, {BP_DLR, MOD_LSFT}},
- [GR(DB_LCBR)] = {{BP_LPRN, MOD_BIT(KC_RALT)}, {BP_LPRN, MOD_BIT(KC_RALT)}},
- [GR(DB_RCBR)] = {{BP_LPRN, MOD_BIT(KC_RALT)}, {BP_RPRN, MOD_BIT(KC_RALT)}},
- [GR(DB_PIPE)] = {{BP_B, MOD_BIT(KC_RALT)}, {BP_B, MOD_BIT(KC_RALT)}},
- [GR(DB_TILD)] = {{BP_K, MOD_BIT(KC_RALT)}, {BP_K, MOD_BIT(KC_RALT)}},
- [GR(DB_CIRC)] = {{BP_AT, MOD_BIT(KC_RALT)}, {BP_AT, MOD_BIT(KC_RALT)}},
- [GR(DB_LESS)] = {{BP_LDAQ, MOD_BIT(KC_RALT)}, {BP_LDAQ, MOD_BIT(KC_RALT)}},
- [GR(DB_GRTR)] = {{BP_RDAQ, MOD_BIT(KC_RALT)}, {BP_RDAQ, MOD_BIT(KC_RALT)}},
-};
-
-
-uint8_t gr(uint8_t kc){
- return (kc - SAFE_RANGE);
-}
-// send the right keycode for the right mod.
-// remove the mods we are taking care of,
-// send our keycodes then restore them.
-// all so we can make dvorak keys from bepo keycodes.
-void send_keycode(uint8_t kc){
- uint8_t tmp_mods = get_mods();
- bool is_shifted = ( tmp_mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) );
- //uint8_t key[2][2] = key_translations[GR(kc)];
- // need to turn of the shift if it is on.
- unregister_mods((MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)));
- if(is_shifted){
- register_mods(SHIFTED_MODS(kc));
- register_code(SHIFTED_KEY(kc));
- unregister_code(SHIFTED_KEY(kc));
- unregister_mods(SHIFTED_MODS(kc));
- } else{
- register_mods(UNSHIFTED_MODS(kc));
- register_code(UNSHIFTED_KEY(kc));
- unregister_code(UNSHIFTED_KEY(kc));
- unregister_mods(UNSHIFTED_MODS(kc));
- }
- clear_mods();
- register_mods(tmp_mods);
-}
-
-
-bool process_record_user(uint16_t keycode, keyrecord_t *record) {
-
-// If console is enabled, it will print the matrix position and status of each key pressed
-#ifdef KEYLOGGER_ENABLE
-xprintf("KL: row: %u, column: %u, pressed: %u\n", record->event.key.col, record->event.key.row, record->event.pressed);
-#endif //KEYLOGGER_ENABLE
-
-// still dont know how to make #&_ And RALT is not ALTGR, That isn't working in the bepo keyboard
-// either. No {} either probably for the same reasons. ALtGR is the key to some of these.
- switch (keycode) {
- // Handle the key translations for Dvorak on bepo. It's best if these are the first
- // enums after SAFE_RANGE.
- case DB_1:
- case DB_2:
- case DB_3:
- case DB_4:
- case DB_5:
- case DB_6:
- case DB_7:
- case DB_8:
- case DB_9:
- case DB_0:
- case DB_GRV:
- case DB_SCOLON:
- case DB_SLASH:
- case DB_BACKSLASH:
- case DB_EQL:
- case DB_DOT:
- case DB_COMM:
- case DB_QUOT:
- case DB_MINUS:
- case DB_LPRN:
- case DB_RPRN:
- case DB_LBRC:
- case DB_RBRC:
- if(record->event.pressed)
- send_keycode(keycode);
- unregister_code(keycode);
- break;
-
- case KC_QWERTY:
- if (record->event.pressed) {
- set_single_persistent_default_layer(QWERTY);
- }
- return false;
- break;
- case KC_COLEMAK:
- if (record->event.pressed) {
- set_single_persistent_default_layer(COLEMAK);
- }
- return false;
- break;
- case KC_DVORAK:
- if (record->event.pressed) {
- set_single_persistent_default_layer(DVORAK);
- }
- return false;
- break;
- case KC_WORKMAN:
- if (record->event.pressed) {
- set_single_persistent_default_layer(WORKMAN);
- }
- return false;
- break;
-
- case KC_MAKE: // Compiles the firmware, and adds the flash command based on keyboard bootloader
- if (!record->event.pressed) {
- SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP
-#if (defined(BOOTLOADER_DFU) || defined(BOOTLOADER_LUFA_DFU) || defined(BOOTLOADER_QMK_DFU))
- ":dfu"
-#elif defined(BOOTLOADER_HALFKAY)
- ":teensy"
-#elif defined(BOOTLOADER_CATERINA)
- ":avrdude"
-#endif // bootloader options
- SS_TAP(X_ENTER));
- }
- return false;
- break;
-
-
- case KC_RESET: // Custom RESET code
- if (!record->event.pressed) {
- reset_keyboard();
- }
- return false;
- break;
-
-
- case EPRM: // Resets EEPROM
- if (record->event.pressed) {
- eeconfig_init();
- default_layer_set(1UL<<eeconfig_read_default_layer());
- layer_state_set(layer_state);
- }
- return false;
- break;
- case VRSN: // Prints firmware version
- if (record->event.pressed) {
- SEND_STRING(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION ", Built on: " QMK_BUILDDATE);
- }
- return false;
- break;
-
- /* Code has been depreciated
- case KC_SECRET_1 ... KC_SECRET_5: // Secrets! Externally defined strings, not stored in repo
- if (!record->event.pressed) {
- clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
- send_string(decoy_secret[keycode - KC_SECRET_1]);
- }
- return false;
- break;
- */
-
- // These are a serious of gaming macros.
- // Only enables for the viterbi, basically,
- // to save on firmware space, since it's limited.
-#ifdef MACROS_ENABLED
- case KC_OVERWATCH: // Toggle's if we hit "ENTER" or "BACKSPACE" to input macros
- if (record->event.pressed) { userspace_config.is_overwatch ^= 1; eeprom_update_byte(EECONFIG_USER, userspace_config.raw); }
- return false; break;
-#endif // MACROS_ENABLED
-
- case KC_CCCV: // One key copy/paste
- if(record->event.pressed){
- copy_paste_timer = timer_read();
- } else {
- if (timer_elapsed(copy_paste_timer) > TAPPING_TERM) { // Hold, copy
- register_code(KC_LCTL);
- tap(KC_C);
- unregister_code(KC_LCTL);
-#ifdef AUDIO_ENABLE
- PLAY_SONG(tone_copy);
-#endif
- } else { // Tap, paste
- register_code(KC_LCTL);
- tap(KC_V);
- unregister_code(KC_LCTL);
-#ifdef AUDIO_ENABLE
- PLAY_SONG(tone_paste);
-#endif
- }
- }
- return false;
- break;
- case CLICKY_TOGGLE:
-#ifdef AUDIO_CLICKY
- userspace_config.clicky_enable = clicky_enable;
- eeprom_update_byte(EECONFIG_USER, userspace_config.raw);
-#endif
- break;
-#ifdef UNICODE_ENABLE
- case UC_FLIP: // (╯°□°)╯ ︵ ┻━┻
- if (record->event.pressed) {
- register_code(KC_RSFT);
- tap(KC_9);
- unregister_code(KC_RSFT);
- process_unicode((0x256F | QK_UNICODE), record); // Arm
- process_unicode((0x00B0 | QK_UNICODE), record); // Eye
- process_unicode((0x25A1 | QK_UNICODE), record); // Mouth
- process_unicode((0x00B0 | QK_UNICODE), record); // Eye
- register_code(KC_RSFT);
- tap(KC_0);
- unregister_code(KC_RSFT);
- process_unicode((0x256F | QK_UNICODE), record); // Arm
- tap(KC_SPC);
- process_unicode((0x0361 | QK_UNICODE), record); // Flippy
- tap(KC_SPC);
- process_unicode((0x253B | QK_UNICODE), record); // Table
- process_unicode((0x2501 | QK_UNICODE), record); // Table
- process_unicode((0x253B | QK_UNICODE), record); // Table
- }
- return false;
- break;
-#endif // UNICODE_ENABLE
-
-}
-
-return true;
- // return process_record_keymap(keycode, record) && process_record_secrets(keycode, record);
-}
-
-void tap_dance_mouse_btns (qk_tap_dance_state_t *state, void *user_data) {
- switch(state->count){
- case 1:
- register_code(KC_BTN1);
- break;
- case 2:
- register_code(KC_BTN2);
- break;
- case 3:
- register_code(KC_BTN3);
- break;
- case 4:
- register_code(KC_BTN4);
- break;
- case 5:
- register_code(KC_BTN5);
- break;
- default:
- break;
- }
- reset_tap_dance(state);
-}
-
-// counting on all the qwerty layers to be less than dvorak_on_bepo
-int on_qwerty(){
- uint8_t deflayer = (biton32(default_layer_state));
- return (deflayer < DVORAK_ON_BEPO);
-}
-
-void tap_dance_df_bepo_layers_switch (qk_tap_dance_state_t *state, void *user_data) {
- switch(state->count){
- case 1:
- switch_default_layer(DVORAK_ON_BEPO);
- break;
- case 2:
- switch_default_layer(BEPO);
- break;
- case 3:
- layer_invert(LAYERS);
- break;
- default:
- break;
- }
- reset_tap_dance(state);
-}
-
-void tap_dance_layer_switch (qk_tap_dance_state_t *state, void *user_data) {
- switch(state->count){
- case 1:
- if(on_qwerty())
- layer_invert(SYMB);
- else
- layer_invert(SYMB_ON_BEPO);
- break;
- case 2:
- layer_invert(MDIA);
- break;
- case 3:
- layer_invert(LAYERS);
- break;
- case 4:
- if(on_qwerty())
- layer_invert(KEYPAD);
- else
- layer_invert(KEYPAD_ON_BEPO);
- break;
- default:
- break;
- }
- reset_tap_dance(state);
-}
-
-void tap_dance_default_layer_switch (qk_tap_dance_state_t *state, void *user_data) {
- switch(state->count){
- case 1:
- switch_default_layer(DVORAK);
- break;
- case 2:
- switch_default_layer(DVORAK_ON_BEPO);
- break;
- case 3:
- switch_default_layer(BEPO);
- break;
- default:
- break;
- }
- reset_tap_dance(state);
-}
-
-// switch the default layer to another qwerty based layer.
-void switch_default_layer_on_qwerty(int count) {
- switch(count){
- case 1:
- switch_default_layer(DVORAK);
- break;
- case 2:
- switch_default_layer(QWERTY);
- break;
- case 3:
- switch_default_layer(COLEMAK);
- break;
- case 4:
- switch_default_layer(WORKMAN);
- break;
- case 5:
- switch_default_layer(NORMAN);
- break;
- default:
- switch_default_layer(DVORAK);
- break;
- }
-}
-
-// switch the default layer to another bepo based layer.
-void switch_default_layer_on_bepo(int count) {
- switch(count){
- case 1:
- switch_default_layer(DVORAK_ON_BEPO);
- break;
- case 2:
- switch_default_layer(BEPO);
- break;
- default:
- switch_default_layer(DVORAK_ON_BEPO);
- break;
- }
-}
-
-
-// tap to change the default layer. Distinguishes between layers that are based on
-// a qwerty software keyboard and a bepo software keyboard.
-// if shifted, choose layers based on the other software keyboard, otherwise choose only
-// layers that work on the current software keyboard.
-void tap_dance_default_os_layer_switch (qk_tap_dance_state_t *state, void *user_data) {
- //uint8_t shifted = (get_mods() & MOD_BIT(KC_LSFT|KC_RSFT));
- bool shifted = ( keyboard_report->mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) );
- int qwerty = on_qwerty();
-
-
- // shifted, choose between layers on the other software keyboard
- if(shifted){
- if (qwerty)
- switch_default_layer_on_bepo(state->count);
- else
- switch_default_layer_on_qwerty(state->count);
-
- // not shifted, choose between layers on the same software keyboard
- } else {
- if (qwerty)
- switch_default_layer_on_qwerty(state->count);
- else
- switch_default_layer_on_bepo(state->count);
- }
-
- reset_tap_dance(state);
-}
-
-
-/* Return an integer that corresponds to what kind of tap dance should be executed.
- *
- * How to figure out tap dance state: interrupted and pressed.
- *
- * Interrupted: If the state of a dance dance is "interrupted", that means that another key has been hit
- * under the tapping term. This is typically indicitive that you are trying to "tap" the key.
- *
- * Pressed: Whether or not the key is still being pressed. If this value is true, that means the tapping term
- * has ended, but the key is still being pressed down. This generally means the key is being "held".
- *
- * One thing that is currenlty not possible with qmk software in regards to tap dance is to mimic the "permissive hold"
- * feature. In general, advanced tap dances do not work well if they are used with commonly typed letters.
- * For example "A". Tap dances are best used on non-letter keys that are not hit while typing letters.
- *
- * Good places to put an advanced tap dance:
- * z,q,x,j,k,v,b, any function key, home/end, comma, semi-colon
- *
- * Criteria for "good placement" of a tap dance key:
- * Not a key that is hit frequently in a sentence
- * Not a key that is used frequently to double tap, for example 'tab' is often double tapped in a terminal, or
- * in a web form. So 'tab' would be a poor choice for a tap dance.
- * Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the
- * letter 'p', the word 'pepper' would be quite frustating to type.
- *
- * For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested
- *
- */
-int cur_dance (qk_tap_dance_state_t *state) {
- if (state->count == 1) {
- if (state->interrupted || !state->pressed) return SINGLE_TAP;
- //key has not been interrupted, but they key is still held. Means you want to send a 'HOLD'.
- else return SINGLE_HOLD;
- }
- else if (state->count == 2) {
- /*
- * DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap
- * action when hitting 'pp'. Suggested use case for this return value is when you want to send two
- * keystrokes of the key, and not the 'double tap' action/macro.
- */
- if (state->interrupted) return DOUBLE_SINGLE_TAP;
- else if (state->pressed) return DOUBLE_HOLD;
- else return DOUBLE_TAP;
- }
- //Assumes no one is trying to type the same letter three times (at least not quickly).
- //If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add
- //an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP'
- if (state->count == 3) {
- if (state->interrupted || !state->pressed) return TRIPLE_TAP;
- else return TRIPLE_HOLD;
- }
- else return 8; //magic number. At some point this method will expand to work for more presses
-}
-//instanalize an instance of 'tap' for the 'x' tap dance.
-static tdtap xtap_state = {
- .is_press_action = true,
- .state = 0
-};
-/*
- This so I can have a single key that acts like LGUI in DVORAK no
- matter which keymap is my current default.
- It also allows for the
- shift gui and ctl gui, on the same key, So the same key is Escape,
- and the mostcommon modifiers in my xmonad control keymap, while also
- insuring that dvorak is active for the xmonad command key
- Single tap = ESC
- tap and hold = dvorak with L_GUI
- double tap = One shot dvorak layer with LSFT LGUI mods
- double hold = dvorak with LCTL LGUI
- double single tap = esc.
-*/
-int get_xmonad_layer(){
- int qwerty = on_qwerty();
-
- if (qwerty)
- return(XMONAD);
- else
- return(XMONAD_FR);
-}
-
-
-void x_finished (qk_tap_dance_state_t *state, void *user_data) {
- int xmonad_layer = get_xmonad_layer();
- xtap_state.state = cur_dance(state);
- switch (xtap_state.state) {
- case SINGLE_TAP:
- register_code(KC_ESC);
- break;
- case SINGLE_HOLD:
- layer_on(xmonad_layer);
- set_oneshot_mods (MOD_LGUI);
- //set_oneshot_layer (DVORAK, ONESHOT_START);
- break;
- case DOUBLE_TAP:
- set_oneshot_mods ((MOD_LCTL | MOD_LGUI));
- layer_on (xmonad_layer);
- set_oneshot_layer (xmonad_layer, ONESHOT_START);
- break;
- case DOUBLE_HOLD:
- set_oneshot_mods (MOD_LSFT | MOD_LGUI);
- if (xmonad_layer != -1)
- layer_on(xmonad_layer);
- break;
- case DOUBLE_SINGLE_TAP:
- register_code(KC_ESC);
- unregister_code(KC_ESC);
- register_code(KC_ESC);
- //Last case is for fast typing. Assuming your key is `f`:
- //For example, when typing the word `buffer`, and you want to make sure that you send `ff` and not `Esc`.
- //In order to type `ff` when typing fast, the next character will have to be hit within the `TAPPING_TERM`, which by default is 200ms.
- }
-}
-
-void x_reset (qk_tap_dance_state_t *state, void *user_data) {
- int xmonad_layer = get_xmonad_layer();
- switch (xtap_state.state) {
- case SINGLE_TAP:
- unregister_code(KC_ESC);
- break;
- case SINGLE_HOLD:
- layer_off(xmonad_layer);
- break;
- case DOUBLE_TAP:
- set_oneshot_layer (xmonad_layer, ONESHOT_PRESSED);
- break;
- case DOUBLE_HOLD:
- layer_off(xmonad_layer);
- break;
- case DOUBLE_SINGLE_TAP:
- unregister_code(KC_ESC);
- }
- xtap_state.state = 0;
-}
-
-//Tap Dance Definitions
-qk_tap_dance_action_t tap_dance_actions[] = {
- //Tap once for Esc, twice for Caps Lock
- [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS),
- [TD_TAB_BKTAB] = ACTION_TAP_DANCE_DOUBLE(KC_TAB, LSFT(KC_TAB)),
- [TD_MDIA_SYMB] = ACTION_TAP_DANCE_FN(tap_dance_layer_switch),
- [TD_DVORAK_BEPO] = ACTION_TAP_DANCE_FN(tap_dance_df_bepo_layers_switch),
- [TD_DEF_LAYER_SW] = ACTION_TAP_DANCE_FN(tap_dance_default_layer_switch),
- [TD_DEF_OS_LAYER_SW] = ACTION_TAP_DANCE_FN(tap_dance_default_os_layer_switch),
- [TD_HOME_END] = ACTION_TAP_DANCE_DOUBLE(KC_HOME, KC_END),
- [TD_XMONAD_ESC] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, x_finished, x_reset),
- [TD_MOUSE_BTNS] = ACTION_TAP_DANCE_FN(tap_dance_mouse_btns)
-};
diff --git a/users/ericgebhart/ericgebhart.h b/users/ericgebhart/ericgebhart.h
index ad66a636ea..92f8f22d29 100644..100755
--- a/users/ericgebhart/ericgebhart.h
+++ b/users/ericgebhart/ericgebhart.h
@@ -1,32 +1,72 @@
#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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/>.
+*/
#ifndef ericgebhart
#define ericgebhart
#include QMK_KEYBOARD_H
-#include "base_layers.h"
+#include "core_keysets.h"
+#include "layouts.h"
+#include "layers.h"
+#if defined(OLED_ENABLE)
+# include "oled_stuff.h"
+#endif
//#define ONESHOT_TAP_TOGGLE 2 /* Tapping this number of times holds the key until tapped once again. */
+/* Define layer names */
+enum userspace_layers {
+ _DVORAK = 0,
+ _QWERTY,
+ _COLEMAK,
+ _BEAKL,
+ //_WORKMAN,
+ //_NORMAN,
+ //_MALTRON,
+ //_EUCALYN,
+ //_CARPLAX,
+ _DVORAK_BP, // beginning of Bepo
+ _BEAKL_BP,
+ _BEPO,
+ _LAYERS,
+ _NAV, // transient layers
+ _SYMB,
+ _SYMB_BP,
+ _KEYPAD,
+ _KEYPAD_BP,
+ _TOPROWS,
+ _TOPROWS_BP,
+ _RGB,
+ _ADJUST,
+};
-#define DVORAK 0 // dvorak layout (default)
-#define QWERTY 1
-#define COLEMAK 2
-#define WORKMAN 3
-#define NORMAN 4
-// bepo layers
-#define DVORAK_ON_BEPO 6 // dvorak layout (default)
-#define BEPO 7 // Bepo
-// non-default layers
-#define SYMB 8 // symbols and numbers
-#define SYMB_ON_BEPO 9 // symbols and numbers
-#define MDIA 10 // mouse knd media eys
-#define LAYERS 11 // layers and right mousekeys.
-#define XMONAD 12 // xmonad ie. dvorak.
-#define XMONAD_FR 13 // xmonad ie. dvorak.
-#define KEYPAD 14 // number and Fkey pads
-#define KEYPAD_ON_BEPO 15 // number and Fkey pads.
-#define _RGB 16 // RGB stuff.
-
+// clang-format off
+typedef union {
+ uint32_t raw;
+ struct {
+ bool rgb_layer_change :1;
+ bool is_overwatch :1;
+ bool nuke_switch :1;
+ bool swapped_numbers :1;
+ bool rgb_matrix_idle_anim :1;
+ };
+} userspace_config_t;
+// clang-format on
+extern userspace_config_t userspace_config;
#endif
diff --git a/users/ericgebhart/layers.h b/users/ericgebhart/layers.h
new file mode 100755
index 0000000000..5faaf01736
--- /dev/null
+++ b/users/ericgebhart/layers.h
@@ -0,0 +1,677 @@
+#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "core_keys.h"
+/*********************************************************************/
+/* Non-Base Layer Definitions. */
+/* */
+/* Keypads, sympads, funcpads, symbols, RGB, Layers, Controls, etc. */
+/* Qwerty and Bepo versions exist as needed. */
+/* */
+/* This file defines every auxillary layer I use on every keyboard */
+/* Ergodox, keebio/viterbi, xd75, rebound, crkbd, morpho, dactyl,.. */
+/*********************************************************************/
+/********************************************************************************/
+/* The following Transient/Non-Base Layers are provided within. */
+/* Each layer is named with the size of Keymatrix it has entries for. */
+/* 3x12 or 4x12 are usual for these. Splitting is managed in the macros as */
+/* needed. BP indicates the Bepo equivalent to the Qwerty layer when needed. */
+/********************************************************************************/
+/* */
+/* Explore below to see what they all are. */
+/* Naming gives the sizes of things, a prefix number is the length. */
+/* BP is the bepo version of things. */
+/* BKL is the beakl 15 version of a layout or chunk. */
+/* C on the end of a name means its a compact version of something. */
+/* Compact meaning for use on a 3 row layout. */
+/* */
+/* TOPROWS - numbers, symbols, functions, all on one layer. */
+/* ___TOPROWS_3x12___ */
+/* ___TOPROWS_BP_3x12___ */
+/* // just numbers on the home row */
+/* ___NUM_HOME_BEAKL_3x12___ */
+/* ___NUM_HOME_BEAKL_BP_3x12___ */
+/* ___NUM_HOME_3x12___ */
+/* ___NUM_HOME_BP_3x12___ */
+/* */
+/* KEYPADS/FUNCPADS. */
+/* ___KEY_BKL_FUNC_4x12___ -- The BEAKL15 Keypad with a Funcpad on the right */
+/* ___KEY_BKL_FUNC_BP_4x12___ */
+/* ___FUNC_KEYPAD_4x12___ -- A Funcpad and a keypad */
+/* ___FUNC_KEYPAD_BP_4x12___ -- For Bepo */
+/* */
+/* // Compact Funcpad and keypad, 3x12 */
+/* ___KP_C_3x12___ */
+/* ___KP_C_BP_3x12___ */
+/* ___KP_C_BKL_FUNC_3x12___ -- BEAKL key/func pads. */
+/* ___KP_C_BKL_FUNC_BP_3x12___ */
+/* */
+/* SYMBOLS -Beakl or Beakl extended */
+/* ___SYMB_BEAKL_3x12___ */
+/* ___SYMB_BEAKL_BP_3x12___ */
+/* */
+/* Beakl extended symbol layer with additional corner symbols. */
+/* For use with non-beakl base layers. */
+/* ___SYMB_BEAKLA_3x12___ */
+/* ___SYMB_BEAKLA_BP_3x12___ */
+/* For use with vi bindings optimized */
+/* ___SYMB_BEAKLB_3x12___ */
+/* ___SYMB_BEAKLB_BP_3x12___ */
+/* */
+/* NAVIGATION */
+/* ___NAV_3x12___ */
+/* ___NAV_4x12___ */
+/* */
+/* CONTROLS */
+/* ___RGB_3x12___ */
+/* ___ADJUST_3x12___ */
+/* ___LAYERS_3x12___ */
+/********************************************************************************/
+/*********************************************************************/
+/* XXXXXX Layer chunk -- These are the final layers. */
+/* */
+/* Each section defines the necessary pieces to create a layer. */
+/* It builds them up into consistently shaped lists for the layout */
+/* wrapper. */
+/* */
+/* Each Section ends with a _Layer Chunk_. This is so the */
+/* layer can be easily given to the Layout Wrapper macros which */
+/* takes a list of keys in lengths of 2x3x5, 2x3x6, 2x4x5, or 2x4x6. */
+/* */
+/* All of my keyboard definitions use these same chunks with similar */
+/* macros. The differences between keyboards are all managed in the */
+/* macro. Here we just have nice rectangular sets of keys to */
+/* complete a layout. */
+/*********************************************************************/
+
+
+/*******************************************************************/
+/* A Top Rows layer. Pick your parts. Bepo and Qwerty */
+/* */
+/* This is, to me, a stop gap layer. If I need symbols, numbers or */
+/* function keys these rows are nicely predictable to most people. */
+/* I currently use the beakl number row with regular symbols. */
+/* I never use function keys for anything. */
+/*******************************************************************/
+#define ___12_SYMB___ ___, ___SYMS___, ___
+#define ___12_SYMB_BP___ ___12_SYMS_BEPO___,
+
+#define ___12_NUM___ ___, ___NUMS___, ___
+#define ___12_NUM_BP___ ___, ___NUMS_BP___, ___
+#define ___12_NUM_BEAKL___ ___, ___BKLNUMS___, ___
+#define ___12_NUM_BEAKL_BP___ ___, ___BKLNUMS_BP___, ___
+
+#define ___12_FUNC___ ___FUNC_1_6___, ___FUNC_7_12___
+#define ___12_SYMS_BEPO___ ___6SYMBOL_BEPO_L___, ___6SYMBOL_BEPO_R___
+#define ___12_SYMS_FR___ ___SYMB_L_FR___, ___SYMB_R_FR___
+
+// Kinesis function key row. I don't use them. but might as well define them.
+#define ___KINTFUNC_L___ KC_ESC, ___FUNC_1_6___, KC_F7, KC_F8
+// #define ___KINTFUNC_RIGHT___ KC_F9, KC_F10, KC_F11, KC_F12, KC_PSCR, KC_SLCK, KC_PAUS, KC_FN0, RESET
+#define ___KINTFUNC_R___ KC_F9, KC_F10, KC_F11, KC_F12, XXX, XXX, XXX, XXX, RESET
+
+// A TOPROWS Layer.
+// set it how you like it, if you like it.
+#define ___TOPROW_1___ ___12_SYMB___
+#define ___TOPROW_2___ ___12_NUM_BEAKL___
+#define ___TOPROW_3___ ___12_FUNC___
+
+#define ___TOPROW_1_BP___ ___12_SYMS_BEPO___
+#define ___TOPROW_2_BP___ ___12_NUM_BEAKL_BP___
+#define ___TOPROW_3_BP___ ___12_FUNC___
+
+/********************************************************************************/
+/* TOPROWS Layer chunk */
+/********************************************************************************/
+// altogether in a chunk.
+#define ___TOPROWS_3x12___ ___TOPROW_1___, ___TOPROW_2___, ___TOPROW_3___
+#define ___TOPROWS_BP_3x12___ ___TOPROW_1_BP___, ___TOPROW_2_BP___, ___TOPROW_3_BP___
+
+// Some layers with just a home row of numbers.
+// The beakl ones, r the usual ones.
+#define ___NUM_HOME_BEAKL_3x12___ ___12___, ___12_NUM_BEAKL___, ___12___
+#define ___NUM_HOME_BEAKL_BP_3x12___ ___12___, ___12_NUM_BEAKL_BP___, ___12___
+#define ___NUM_HOME_3x12___ ___12___, ___12_NUM___, ___12___
+#define ___NUM_HOME_BP_3x12___ ___12___, ___12_NUM_BP___, ___12___
+
+
+/********************************************************************************/
+/* KEYPADS. Mostly all in Bepo and Qwerty versions */
+/* 4 row Pads: */
+/* * The BEAKL 15 Number pad, for the left hand. */
+/* * Regular Number pad, for the right hand. */
+/* * 12 Function pad. */
+/* 3 row pads: */
+/* keypad */
+/* function pad */
+/* */
+/* LAYERS: */
+/* 4 Row: */
+/* * BEAKL with a compact FuncPad on the right. */
+/* * Funcpad on the left, keypad on the right. */
+/* 3 Row: */
+/* * Funcpad on the left, keypad on the right. */
+/* * BEAKL with a compact FuncPad on the right. */
+/* */
+/********************************************************************************/
+
+// BEAKL 15 (numpad layer):
+/* +=* ^%~ */
+/* ↹523: */
+/* - 7.104 */
+/* /698, */
+
+// Keypads
+#define ___6KEYPAD_BEAKL_L1___ ___, _X_, KC_PLUS, KC_PEQL, KC_ASTR, _X_
+#define ___6KEYPAD_BEAKL_L2___ ___, TAB_BKTAB, KC_5, KC_2, KC_3, KC_COLON
+#define ___6KEYPAD_BEAKL_L3___ KC_MINS, KC_7, KC_DOT, KC_1, KC_0, KC_4
+#define ___6KEYPAD_BEAKL_L4___ ___, KC_SLASH, KC_6, KC_9, KC_8, KC_COMM
+
+#define ___5KEYPAD_BEAKL_R1___ ___, KC_CIRC, KC_PERC, KC_TILD, ___
+
+#define ___6KEYPAD_BEAKL_L1_BP___ ___, _X_, BP_PLUS, BP_EQL, BP_ASTR, _X_
+#define ___6KEYPAD_BEAKL_L2_BP___ ___, TAB_BKTAB, BP_5, BP_2, BP_3, BP_COLN
+#define ___6KEYPAD_BEAKL_L3_BP___ BP_MINS, BP_7, BP_DOT, BP_1, BP_0, BP_4
+#define ___6KEYPAD_BEAKL_L4_BP___ ___, BP_SLSH, BP_6, BP_9, BP_8, BP_COMM
+
+#define ___5KEYPAD_BEAKL_R1_BP___ ___, BP_CIRC, BP_PERC, BP_TILD, ___
+
+#define ___5KEYPAD_1___ _X_, KC_7, KC_8, KC_9, KC_PSLS
+#define ___5KEYPAD_2___ _X_, KC_4, KC_5, KC_6, KC_PAST
+#define ___5KEYPAD_3___ _X_, KC_1, KC_2, KC_3, KC_PMNS
+#define ___5KEYPAD_4___ _X_, KC_0, KC_DOT, KC_PEQL, KC_PPLS
+// For Bepo
+#define ___5KEYPAD_1_BP___ _X_, DB_7, DB_8, DB_9, BP_SLSH
+#define ___5KEYPAD_2_BP___ _X_, DB_4, DB_5, DB_6, BP_ASTR
+#define ___5KEYPAD_3_BP___ _X_, DB_1, DB_2, DB_3, DB_MINUS
+#define ___5KEYPAD_4_BP___ _X_, DB_0, DB_DOT, DB_EQL, BP_PLUS
+
+// Keypad from the default keymap.c of the xd75
+#define ___4KEYPAD_1_ALT___ _X_, KC_P7, KC_P8, KC_P9, KC_MINS
+#define ___4KEYPAD_2_ALT___ _X_, KC_P4, KC_P5, KC_P6, KC_PLUS
+#define ___4KEYPAD_3_ALT___ _X_, KC_P1, KC_P2, KC_P3, KC_PENT
+#define ___4KEYPAD_4_ALT___ _X_, KC_P0, KC_DOT, KC_PENT, KC_PENT
+
+// Function pad. Same idea as above, but for function keys.
+// For the left side.
+#define ___5FUNCPAD_T___ _X_, KC_F10, KC_F11, KC_F12, _X_
+#define ___5FUNCPAD_1___ _X_, KC_F7, KC_F8, KC_F9, _X_
+#define ___5FUNCPAD_2___ _X_, KC_F4, KC_F5, KC_F6, _X_
+#define ___5FUNCPAD_3___ _X_, KC_F1, KC_F2, KC_F3, _X_
+
+
+// Put them together for complete left and right layers.
+// Beakl keypad with a funcpad
+#define ___12_KEYPAD_BKL_FUNCPAD_1___ ___6KEYPAD_BEAKL_L1___, _X_, ___5KEYPAD_BEAKL_R1___
+#define ___12_KEYPAD_BKL_FUNCPAD_2___ ___6KEYPAD_BEAKL_L2___, _X_, ___5_FUNCPADC_1___
+#define ___12_KEYPAD_BKL_FUNCPAD_3___ ___6KEYPAD_BEAKL_L3___, _X_, ___5_FUNCPADC_2___
+#define ___12_KEYPAD_BKL_FUNCPAD_4___ ___6KEYPAD_BEAKL_L4___, _X_, ___5_FUNCPADC_3___
+
+#define ___12_KEYPAD_BKL_FUNCPAD_1_BP___ ___6KEYPAD_BEAKL_L1_BP___, _X_, ___5KEYPAD_BEAKL_R1_BP___
+#define ___12_KEYPAD_BKL_FUNCPAD_2_BP___ ___6KEYPAD_BEAKL_L2_BP___, _X_, ___5_FUNCPADC_1___
+#define ___12_KEYPAD_BKL_FUNCPAD_3_BP___ ___6KEYPAD_BEAKL_L3_BP___, _X_, ___5_FUNCPADC_2___
+#define ___12_KEYPAD_BKL_FUNCPAD_4_BP___ ___6KEYPAD_BEAKL_L4_BP___, _X_, ___5_FUNCPADC_3___
+
+// Funcpad and keypad layer for Qwerty based layers.
+#define ___12_FUNCPAD_KEYPAD_1___ ___, ___5FUNCPAD_T___, ___5KEYPAD_1___, ___
+#define ___12_FUNCPAD_KEYPAD_2___ ___, ___5FUNCPAD_1___, ___5KEYPAD_2___, ___
+#define ___12_FUNCPAD_KEYPAD_3___ ___, ___5FUNCPAD_2___, ___5KEYPAD_3___, KC_PENT
+#define ___12_FUNCPAD_KEYPAD_4___ ___, ___5FUNCPAD_3___, ___5KEYPAD_4___, ___
+
+// Funcpad and keypad layer for BEPO
+#define ___12_FUNCPAD_KEYPAD_BP_1___ ___, ___5FUNCPAD_T_BP___, ___5KEYPAD_1_BP___, ___
+#define ___12_FUNCPAD_KEYPAD_BP_2___ ___, ___5FUNCPAD_1_BP___, ___5KEYPAD_2_BP___, ___
+#define ___12_FUNCPAD_KEYPAD_BP_3___ ___, ___5FUNCPAD_2_BP___, ___5KEYPAD_3_BP___, KC_PENT
+#define ___12_FUNCPAD_KEYPAD_BP_4___ ___, ___5FUNCPAD_3_BP___, ___5KEYPAD_4_BP___, ___
+
+/********************************************************************************/
+/* COMPACT - KEYPAD and FUNCPAD. 3 Rows. */
+/********************************************************************************/
+// Compact versions of each. 3 rows.
+//Compact keypad, 3 rows.
+#define ___6KEYPADC_1___ ___, KC_7, KC_8, KC_9, KC_PSLS, ___
+#define ___6KEYPADC_2___ KC_DOT, KC_4, KC_5, KC_6, KC_PAST, KC_PEQL
+#define ___6KEYPADC_3___ KC_0, KC_1, KC_2, KC_3, KC_PMNS, KC_PPLS
+// For Bepo
+#define ___6KEYPADC_1_BP___ ___, DB_7, DB_8, DB_9, BP_SLSH
+#define ___6KEYPADC_2_BP___ DB_DOT, DB_4, DB_5, DB_6, BP_ASTR, DB_EQL
+#define ___6KEYPADC_3_BP___ DB_0, DB_1, DB_2, DB_3, DB_MINUS, DB_PLUS
+
+// compact 1-12 funcpad for 3 row keyboards.
+#define ___5_FUNCPADC_1___ KC_F9, KC_F10, KC_F11, KC_F12, ___
+#define ___5_FUNCPADC_2___ KC_F5, KC_F6, KC_F7, KC_F8, ___
+#define ___5_FUNCPADC_3___ KC_F1, KC_F2, KC_F3, KC_F4, ___
+
+// Compact funcpads/keypad Layer
+#define ___12_KP_1C___ ___, ___5_FUNCPADC_1___, ___5KEYPAD_1___, ___
+#define ___12_KP_2C___ ___, ___5_FUNCPADC_2___, ___5KEYPAD_2___, ___
+#define ___12_KP_3C___ ___, ___5_FUNCPADC_3___, ___5KEYPAD_3___, ___
+// Reversed
+#define ___12_KP_FP_1C___ ___, ___5KEYPAD_1___, ___5_FUNCPADC_1___, ___
+#define ___12_KP_FP_2C___ ___, ___5KEYPAD_2___, ___5_FUNCPADC_2___, ___
+#define ___12_KP_FP_3C___ ___, ___5KEYPAD_3___, ___5_FUNCPADC_3___, ___
+
+//Bepo funcpad and keypad Layer
+#define ___12_KP_1_BP___ ___, ___5_FUNCPADC_1___, ___5KEYPAD_1_BP___, ___
+#define ___12_KP_2_BP___ ___, ___5_FUNCPADC_2___, ___5KEYPAD_2_BP___, ___
+#define ___12_KP_3_BP___ ___, ___5_FUNCPADC_3___, ___5KEYPAD_3_BP___, ___
+
+/********************************************************************************/
+/* FUNCPAD and Keypad Layer chunks */
+/********************************************************************************/
+// Full size, 4x12
+#define ___KEYPAD_BKL_FUNC_4x12___ \
+ ___12_KEYPAD_BKL_FUNCPAD_1___, \
+ ___12_KEYPAD_BKL_FUNCPAD_2___, \
+ ___12_KEYPAD_BKL_FUNCPAD_3___, \
+ ___12_KEYPAD_BKL_FUNCPAD_4___
+#define ___KEYPAD_BKL_FUNC_BP_4x12___ \
+ ___12_KEYPAD_BKL_FUNCPAD_1_BP___, \
+ ___12_KEYPAD_BKL_FUNCPAD_2_BP___, \
+ ___12_KEYPAD_BKL_FUNCPAD_3_BP___, \
+ ___12_KEYPAD_BKL_FUNCPAD_4_BP___
+#define ___FUNC_KEYPAD_4x12___ \
+ ___12_FUNCPAD_KEYPAD_1___, \
+ ___12_FUNCPAD_KEYPAD_2___, \
+ ___12_FUNCPAD_KEYPAD_3___, \
+ ___12_FUNCPAD_KEYPAD_4___
+#define ___FUNC_KEYPAD_BP_4x12___ \
+ ___12_FUNCPAD_KEYPAD_BP_1___, \
+ ___12_FUNCPAD_KEYPAD_BP_2___, \
+ ___12_FUNCPAD_KEYPAD_BP_3___, \
+ ___12_FUNCPAD_KEYPAD_BP_4___
+
+// Compact, 3x12
+#define ___KP_C_BKL_FUNC_3x12___ \
+ ___12_KEYPAD_BKL_FUNCPAD_2___, \
+ ___12_KEYPAD_BKL_FUNCPAD_3___, \
+ ___12_KEYPAD_BKL_FUNCPAD_4___
+#define ___KP_C_BKL_FUNC_BP_3x12___ \
+ ___12_KEYPAD_BKL_FUNCPAD_2_BP___, \
+ ___12_KEYPAD_BKL_FUNCPAD_3_BP___, \
+ ___12_KEYPAD_BKL_FUNCPAD_4_BP___
+
+#define ___KP_C_3x12___ ___12_KP_1C___, ___12_KP_2C___, ___12_KP_3C___
+#define ___KP_FP_C_3x12___ ___12_KP_FP_1C___, ___12_KP_FP_2C___, ___12_KP_FP_3C___
+#define ___KP_C_BP_3x12___ ___12_KP_1_BP___, ___12_KP_2_BP___, ___12_KP_3_BP___
+
+
+
+/********************************************************************************/
+/* SYMBOLS. The BEAKL15 Symbol layer with or without additions. */
+/* */
+/* Symbol layers: */
+/* */
+/* BEAKL symbol layer */
+/* <$> [_] */
+/* - \(")# %{=}| ; */
+/* :*+ &^~ */
+/* */
+/* BEAKL Extended symbol layer */
+/* `<$>' ?[_] */
+/* - \(")# %{=}| ; */
+/* @:*+; !&^~/ */
+/* */
+/* This layer has replaced my former Symbol pad and Symbols */
+/* layer. The Sympad was nice, But this incorporates the matching */
+/* (){}[] that I had and at the same time provides an easily */
+/* Learnable layer that makes sense. It was also easy to */
+/* Supplement with new keys that other layouts might need. */
+/* */
+/* The first Layer defined is the "Official" version. */
+/* The second Layer defined only adds to the original by */
+/* Placing 8 keys in the pinky and index corners */
+/* at the edges of the, 3x3, BEAKL home Region. */
+/* */
+/* Namely these: !?@`'/-; */
+/* */
+/* Beakl has these keys in it's base layer which isn't the case */
+/* for other layouts like dvorak, colemak, etc. */
+/* */
+/******************************************************************/
+
+/******************************************************************/
+/* Official BEAKL15 Symbol layer. */
+/* BEAKL 15 (punctuation layer): */
+/* */
+/* <$> [_] */
+/* - \(")# %{=}| ; */
+/* :*+ &^~ */
+/******************************************************************/
+/********************************************************************************/
+/* The expanded Beakl Symbol Layer */
+/* */
+/* Expanded with: !?@`'/-; */
+/* */
+/* This insures access to all common symbols, regardless of availabilily on */
+/* other layers. All the extra characters are added to the pinky and index */
+/* corners which are empty in the BEAKL symbol layer. */
+/* */
+/* Both ; and ' could find their dvorak positions. */
+/* Analysis showed that only caused pinky overuse. Rotating the symbols around */
+/* Put better keys on the index finger which showed a huge improvement */
+/* in efficiency. The same is true of the exclamation point. */
+/* */
+/* A: */
+/* `<$>' ?[_] */
+/* - \(")# %{=}| ; */
+/* @:*+; !&^~/ */
+/* */
+/* B: */
+/* With vi bindings /:? and a leader key for vi/emacs.*/
+/* ; is popular, I use , it's easy in dvorak.: */
+/* */
+/* `<$>' ?[_]- */
+/* - \(")# !{:}/ ; */
+/* @=*+; %&^~| */
+/********************************************************************************/
+// Left
+#define ___SB_L1___ KC_OCLTGT, KC_DLR, KC_GT
+#define ___SB_L2___ KC_BACKSLASH, KC_OCPRN, KC_OCDQUO, KC_RPRN, KC_HASH
+#define ___SB_L3___ KC_COLON, KC_ASTR, KC_PLUS
+#define ___SB_L3b___ KC_EQL, KC_ASTR, KC_PLUS
+
+// Bepo
+#define ___SB_L1_BP___ BP_OCLTGT, BP_DLR, DB_GRTR
+#define ___SB_L2_BP___ DB_BACKSLASH, DB_LPRN, BP_OCDQUO, DB_RPRN, DB_HASH
+#define ___SB_L3_BP___ KC_COLON, BP_ASTR, BP_PLUS
+#define ___SB_L3b_BP___ BP_EQL, BP_ASTR, BP_PLUS
+
+// Right
+#define ___SB_R1___ KC_OCBRC, KC_UNDS, KC_RBRC
+#define ___SB_R2___ KC_PERC, KC_OCCBR, KC_EQL, KC_RCBR, KC_PIPE
+#define ___SB_R3___ KC_AMPR, KC_CIRC, KC_TILD
+
+#define ___SB_R2a___ KC_PERC, KC_OCCBR, KC_EXLM, KC_RCBR, KC_PIPE
+#define ___SB_R2b___ KC_EXLM, KC_OCCBR, KC_COLN, KC_RCBR, KC_SLASH
+
+// Bepo
+#define ___SB_R1_BP___ BP_OCBRC, BP_UNDS, DB_RBRC
+#define ___SB_R2_BP___ BP_PERC, BP_OCCBR, BP_EQL, DB_RCBR, DB_PIPE
+#define ___SB_R3_BP___ BP_AMPR, DB_CIRC, DB_TILD
+
+#define ___SB_R2a_BP___ BP_PERC, BP_OCCBR, BP_EXLM, DB_RCBR, DB_PIPE
+#define ___SB_R2b_BP___ BP_EXLM, BP_OCCBR, KC_COLON, DB_RCBR, DB_SLASH
+
+// ---------------------------
+// ---------------------------
+
+// Square it to 6, Add in the - and ;.
+#define ___6SYMBOLS_BEAKL_L1___ ___, ___, ___SB_L1___, ___
+#define ___6SYMBOLS_BEAKL_L2___ KC_MINS, ___SB_L2___
+#define ___6SYMBOLS_BEAKL_L3___ ___, ___, ___SB_L3___, ___
+
+#define ___6SYMBOLS_BEAKL_R1___ ___, ___SB_R1___, ___, ___
+#define ___6SYMBOLS_BEAKL_R2___ ___SB_R2___, KC_SCLN
+#define ___6SYMBOLS_BEAKL_R3___ ___, ___SB_R3___, ___, ___
+// ---------------------------
+#define ___6SYMBOLS_BEAKL_L1a___ ___, KC_OCGRV, ___SB_L1___, KC_OCQUOT
+#define ___6SYMBOLS_BEAKL_L2a___ ___6SYMBOLS_BEAKL_L2___
+#define ___6SYMBOLS_BEAKL_L3a___ ___, KC_AT, ___SB_L3___, KC_SCLN
+
+#define ___6SYMBOLS_BEAKL_R1a___ LSFT(KC_SLASH), ___SB_R1___, KC_MINS, ___
+#define ___6SYMBOLS_BEAKL_R2a___ ___SB_R2a___, KC_SCLN
+#define ___6SYMBOLS_BEAKL_R3a___ KC_EXLM, ___SB_R3___, KC_SLASH, ___
+// ---------------------------
+#define ___6SYMBOLS_BEAKL_L1b___ ___, KC_OCGRV, ___SB_L1___, KC_OCQUOT
+#define ___6SYMBOLS_BEAKL_L2b___ ___6SYMBOLS_BEAKL_L2___
+#define ___6SYMBOLS_BEAKL_L3b___ ___, KC_AT, ___SB_L3b___, KC_SCLN
+
+#define ___6SYMBOLS_BEAKL_R1b___ ___6SYMBOLS_BEAKL_R1a___
+#define ___6SYMBOLS_BEAKL_R2b___ ___SB_R2b___, KC_SCLN
+#define ___6SYMBOLS_BEAKL_R3b___ KC_PERC, ___SB_R3___, KC_PIPE, ___
+
+// ---------------------------
+// ---------------------------
+// Bepo
+#define ___6SYMBOLS_BEAKL_L1_BP___ ___, ___, ___SB_L1_BP___, ___
+#define ___6SYMBOLS_BEAKL_L2_BP___ BP_MINS, ___SB_L2_BP___
+#define ___6SYMBOLS_BEAKL_L3_BP___ ___, ___, ___SB_L3_BP___, ___
+
+#define ___6SYMBOLS_BEAKL_R1_BP___ ___, ___SB_R1_BP___, ___, ___
+#define ___6SYMBOLS_BEAKL_R2_BP___ ___SB_R2_BP___, BP_SCLN
+#define ___6SYMBOLS_BEAKL_R3_BP___ ___, ___SB_R3_BP___, ___, ___
+// ---------------------------
+#define ___6SYMBOLS_BEAKL_L1a_BP___ ___, BP_GRV, ___SB_L1_BP___, BP_AT
+#define ___6SYMBOLS_BEAKL_L2a_BP___ ___6SYMBOLS_BEAKL_L2_BP___
+#define ___6SYMBOLS_BEAKL_L3a_BP___ ___, BP_AT, ___SB_L3_BP___, BP_SCLN
+
+#define ___6SYMBOLS_BEAKL_R1a_BP___ BP_QUES, ___SB_R1_BP___, BP_MINS, ___
+#define ___6SYMBOLS_BEAKL_R2a_BP___ ___SB_R2a_BP___, BP_SCLN
+#define ___6SYMBOLS_BEAKL_R3a_BP___ BP_EXLM, ___SB_R3_BP___, BP_SLSH, ___
+// ---------------------------
+#define ___6SYMBOLS_BEAKL_L1b_BP___ ___, BP_GRV, ___SB_L1___, BP_OCQUOT
+#define ___6SYMBOLS_BEAKL_L2b_BP___ ___6SYMBOLS_BEAKL_L2_BP___
+#define ___6SYMBOLS_BEAKL_L3b_BP___ ___, BP_AT, ___SB_L3b_BP___, BP_SCLN
+
+#define ___6SYMBOLS_BEAKL_R1b_BP___ ___, ___SB_R1_BP___, BP_MINS, ___
+#define ___6SYMBOLS_BEAKL_R2b_BP___ ___SB_R2b_BP___, BP_SCLN
+#define ___6SYMBOLS_BEAKL_R3b_BP___ BP_PERC, ___SB_R3_BP___, BP_PIPE, ___
+// ---------------------------
+
+// Some 12 column rows.
+#define ___12_SYM_BKL_1_BP___ ___6SYMBOLS_BEAKL_L1_BP___, ___6SYMBOLS_BEAKL_R1_BP___
+#define ___12_SYM_BKL_2_BP___ ___6SYMBOLS_BEAKL_L2_BP___, ___6SYMBOLS_BEAKL_R2_BP___
+#define ___12_SYM_BKL_3_BP___ ___6SYMBOLS_BEAKL_L3_BP___, ___6SYMBOLS_BEAKL_R3_BP___
+
+#define ___12_SYM_BKL_1___ ___6SYMBOLS_BEAKL_L1___, ___6SYMBOLS_BEAKL_R1___
+#define ___12_SYM_BKL_2___ ___6SYMBOLS_BEAKL_L2___, ___6SYMBOLS_BEAKL_R2___
+#define ___12_SYM_BKL_3___ ___6SYMBOLS_BEAKL_L3___, ___6SYMBOLS_BEAKL_R3___
+
+// Some 12 column rows.
+#define ___12_SYM_BKL_A1_BP___ ___6SYMBOLS_BEAKL_L1a_BP___, ___6SYMBOLS_BEAKL_R1a_BP___
+#define ___12_SYM_BKL_A2_BP___ ___6SYMBOLS_BEAKL_L2a_BP___, ___6SYMBOLS_BEAKL_R2a_BP___
+#define ___12_SYM_BKL_A3_BP___ ___6SYMBOLS_BEAKL_L3a_BP___, ___6SYMBOLS_BEAKL_R3a_BP___
+
+#define ___12_SYM_BKL_A1___ ___6SYMBOLS_BEAKL_L1a___, ___6SYMBOLS_BEAKL_R1a___
+#define ___12_SYM_BKL_A2___ ___6SYMBOLS_BEAKL_L2a___, ___6SYMBOLS_BEAKL_R2a___
+#define ___12_SYM_BKL_A3___ ___6SYMBOLS_BEAKL_L3a___, ___6SYMBOLS_BEAKL_R3a___
+
+#define ___12_SYM_BKL_B1_BP___ ___6SYMBOLS_BEAKL_L1b_BP___, ___6SYMBOLS_BEAKL_R1b_BP___
+#define ___12_SYM_BKL_B2_BP___ ___6SYMBOLS_BEAKL_L2b_BP___, ___6SYMBOLS_BEAKL_R2b_BP___
+#define ___12_SYM_BKL_B3_BP___ ___6SYMBOLS_BEAKL_L3b_BP___, ___6SYMBOLS_BEAKL_R3b_BP___
+
+#define ___12_SYM_BKL_B1___ ___6SYMBOLS_BEAKL_L1b___, ___6SYMBOLS_BEAKL_R1b___
+#define ___12_SYM_BKL_B2___ ___6SYMBOLS_BEAKL_L2b___, ___6SYMBOLS_BEAKL_R2b___
+#define ___12_SYM_BKL_B3___ ___6SYMBOLS_BEAKL_L3b___, ___6SYMBOLS_BEAKL_R3b___
+
+/********************************************************************************/
+/* The BEAKL and BEAKL-A SYMBOL LAYER Chunks */
+/********************************************************************************/
+// The Official beakl symbol layer as a chunk, Bepo and Qwerty
+#define ___SYMB_BEAKL_BP_3x12___ ___12_SYM_BKL_1_BP___, \
+ ___12_SYM_BKL_2_BP___, \
+ ___12_SYM_BKL_3_BP___
+
+#define ___SYMB_BEAKL_3x12___ ___12_SYM_BKL_1___, \
+ ___12_SYM_BKL_2___, \
+ ___12_SYM_BKL_3___
+
+// Alternate Beakle symbol layer with additional corner symbols.
+#define ___SYMB_BEAKLA_BP_3x12___ ___12_SYM_BKL_A1_BP___, \
+ ___12_SYM_BKL_A2_BP___, \
+ ___12_SYM_BKL_A3_BP___
+
+#define ___SYMB_BEAKLA_3x12___ ___12_SYM_BKL_A1___, \
+ ___12_SYM_BKL_A2___, \
+ ___12_SYM_BKL_A3___
+
+#define ___SYMB_BEAKLB_BP_3x12___ ___12_SYM_BKL_B1_BP___, \
+ ___12_SYM_BKL_B2_BP___, \
+ ___12_SYM_BKL_B3_BP___
+
+#define ___SYMB_BEAKLB_3x12___ ___12_SYM_BKL_B1___, \
+ ___12_SYM_BKL_B2___, \
+ ___12_SYM_BKL_B3___
+
+/********************************************************************************/
+/* NAVIGATION - MOUSE, Scroll, Buttons, Arrows, Tab, Home, page up/down, End */
+/* Navigation layers: */
+/* 3 row Layer */
+/* 4 Row Layer with repeated and swapped VI arrows, and Scroll wheel. */
+/********************************************************************************/
+/* */
+/* Navigation layer with optional 4th Row.... */
+/* */
+/* M = Mouse */
+/* B = Button */
+/* W = Wheel */
+/* AC = Acceleration */
+/* CCCV = Tap -> Ctrl-C, hold for double tap duration -> Ctrl-V */
+/* CTCN = Tap -> Ctrl-T, hold for double tap duration -> Ctrl-N */
+/* CWCQ = Tap -> Ctrl-W, hold for double tap duration -> Ctrl-Q */
+/* TAB = Tap -> Tab, Double-tap -> Back Tab */
+/* HOME = Tap -> Home, Double-tap -> End */
+/* */
+/* MB5 MB4 MB3 MB2 MB1 MAC0 | CTCN MB1 MB2 MB3 MB4 MB5 */
+/* TAB MLeft MDown MUp MRight MAC1 | CCCV Left Down UP Right TAB */
+/* WLeft WDown WUp WRight MAC2 | CWCQ HOME PGDN PGUP END */
+/* */
+/* Left Down Up Right CCCV | CCCV MLeft MDown MUp MRight */
+/* */
+/********************************************************************************/
+
+#define ___MOUSE_LDUR___ KC_MS_L, KC_MS_D, KC_MS_U, KC_MS_R
+#define ___MWHEEL_LDUR___ KC_WH_L, KC_WH_D, KC_WH_U, KC_WH_R
+// really BTN 1, 2, 3, 8, 9 - according to xev.
+#define ___MOUSE_BTNS_R___ KC_BTN1, KC_BTN3, KC_BTN2, KC_BTN4, KC_BTN5
+// really BTN 9, 8, 3, 2, 1 - according to xev
+#define ___MOUSE_BTNS_L___ KC_BTN5, KC_BTN4, KC_BTN2, KC_BTN3, KC_BTN1
+#define ___MOUSE_ACCL_012___ KC_ACL0, KC_ACL1, KC_ACL2
+#define ___MACCL___ ___MOUSE_ACCL_012___
+
+
+#define ___VI_ARROWS___ KC_LEFT, KC_DOWN, KC_UP, KC_RIGHT
+#define ___HOME_PGDN_PGUP_END___ KC_HOME, KC_PGDN, KC_PGUP, KC_END
+
+#define ___6NAV_L_1___ ___MOUSE_BTNS_L___, KC_ACL0
+#define ___6NAV_L_2___ TAB_BKTAB, ___MOUSE_LDUR___, KC_ACL1
+#define ___6NAV_L_3___ ___, ___MWHEEL_LDUR___, KC_ACL2
+#define ___6NAV_L_4___ ___, ___VI_ARROWS___, KC_CCCV
+
+#define ___6NAV_R_1___ KC_CTCN, ___MOUSE_BTNS_R___
+#define ___6NAV_R_2___ KC_CCCV, ___VI_ARROWS___, TAB_BKTAB
+#define ___6NAV_R_3___ KC_CWCQ, ___HOME_PGDN_PGUP_END___, ___
+#define ___6NAV_R_4___ KC_CCCV, ___MOUSE_LDUR___, ___
+
+ // compact. Initially for corne. So 3x12 per layer.
+#define ___12_NAV_1___ ___6NAV_L_1___, ___6NAV_R_1___
+#define ___12_NAV_2___ ___6NAV_L_2___, ___6NAV_R_2___
+#define ___12_NAV_3___ ___6NAV_L_3___, ___6NAV_R_3___
+
+#define ___12_NAV_4___ ___6NAV_L_4___, ___6NAV_R_4___
+
+/********************************************************************************/
+/* The Navigation LAYER Chunks */
+/********************************************************************************/
+// A Navigation Layer
+#define ___NAV_3x12___ ___12_NAV_1___, ___12_NAV_2___, ___12_NAV_3___
+#define ___NAV_4x12___ ___NAV_3x12___, ___12_NAV_4___
+
+
+/********************************************************************************/
+/* MEDIA - Mute, Vol, play, pause, stop, next, prev, etc. */
+/********************************************************************************/
+#define ___PRV_PLAY_NXT_STOP___ KC_MPRV, KC_MPLY, KC_MNXT, KC_MSTP
+#define ___VDN_MUTE_VUP___ KC_VOLD, KC_MUTE, KC_VOLU
+
+#define ___MUTE_PRV_PLAY_NXT_STOP___ KC_MUTE, KC_MPRV, KC_MPLY, KC_MNXT, KC_MSTP
+#define ___MUTE_PLAY_STOP___ KC_MUTE, KC_MPLY, KC_MSTP
+
+
+/********************************************************************************/
+/* RGB - Control those lights. */
+
+/* ___, HUE SAT_INT MOD (UP), | */
+/* ___, HUE SAT INT MOD (DOWN), RGB_TOG | P_B_R_SW_SN___, ___ */
+/* ___6___, | ___, ___RGB_KXGT___, ___ */
+/********************************************************************************/
+// RGB FUNCTION Keysets
+// RGB row for the _FN layer from the redo of the default keymap.c
+#define ___RGB_HUE_SAT_INT_UP___ RGB_HUI, RGB_SAI, RGB_VAI, RGB_RMOD
+#define ___RGB_HUE_SAT_INT_DN___ RGB_HUD, RGB_SAD, RGB_VAD, RGB_MOD
+#define ___RGB_MODE_PRV_NXT___ RGB_RMOD, RGB_MOD
+#define ___RGB_TOGGLE___ RGB_TOG
+#define ___RGB_P_B_R_SW_SN___ RGB_M_P, RGB_M_B, RGB_M_R, RGB_M_SW, RGB_M_SN
+#define ___RGB_KXGT___ RGB_M_K, RGB_M_X, RGB_M_G, RGB_M_T
+
+/// An RGB Layer
+#define ___12_RGB_1___ ___, ___RGB_HUE_SAT_INT_UP___, ___, ___6___
+#define ___12_RGB_2___ ___, ___RGB_HUE_SAT_INT_DN___, RGB_TOG, ___RGB_P_B_R_SW_SN___, ___
+#define ___12_RGB_3___ ___6___, ___, ___RGB_KXGT___, ___
+
+/********************************************************************************/
+/* The RGB LAYER Chunk */
+/********************************************************************************/
+#define ___RGB_3x12___ ___12_RGB_1___, ___12_RGB_2___, ___12_RGB_3___
+
+
+/********************************************************************************/
+/* ADJUST - Miscellaneous Melange. */
+/********************************************************************************/
+// For an Adjust layer. Like RBB with audio, flash, etc.
+#define ___6_ADJUST_L1___ KC_MAKE, ___RGB_HUE_SAT_INT_UP___, RGB_TOG
+#define ___6_ADJUST_L2___ VRSN, MU_TOG, CK_TOGG, AU_ON, AU_OFF, CG_NORM
+#define ___6_ADJUST_L3___ MG_NKRO, ___RGB_HUE_SAT_INT_DN___, KC_RGB_T
+
+#define ___6_ADJUST_R1___ ___5___, KC_RESET
+#define ___6_ADJUST_R2___ ___, ___PRV_PLAY_NXT_STOP___, EEP_RST
+#define ___6_ADJUST_R3___ MG_NKRO, ___VDN_MUTE_VUP___, ___, RGB_IDL
+
+/********************************************************************************/
+/* The Adjust LAYER Chunks */
+/********************************************************************************/
+#define ___ADJUST_3x12___ ___6_ADJUST_L1___, ___6_ADJUST_R1___, \
+ ___6_ADJUST_L2___, ___6_ADJUST_R2___, \
+ ___6_ADJUST_L3___, ___6_ADJUST_R3___
+
+
+/********************************************************************************/
+/* LAYERS - Define a base layer, switch to any layer. Get around. Experiment. */
+/* */
+/* Base Layers on the left hand, */
+/* transient layers on the right. Centered on the home region. */
+/* A good place to attach an experimental layer. */
+/* */
+/********************************************************************************/
+// Base Layers
+#define ___5_LAYERS_B1___ ___, KC_BEPO, KC_DVORAK_BP, KC_BEAKL_BP, ___
+#define ___5_LAYERS_B2___ KC_QWERTY, KC_COLEMAK, KC_DVORAK, KC_BEAKL, ___
+
+#define ___5_LAYERS_B3___ ___, KC_QWERTY, KC_NORMAN, KC_WORKMAN, ___
+#define ___5_LAYERS_B4___ ___, DF(_MALTRON), DF(_EUCALYN), DF(_CARPLAX), ___
+
+#define ___5_LAYERS_B1b___ DF(_NORMAN), DF(_MALTRON), DF(_CARPLAX), DF(_COLEMAK), ___
+#define ___5_LAYERS_B2b___ DF(_EUCALYN), DF(_WORKMAN), DF(_QWERTY), DF(_DVORAK), ___
+#define ___5_LAYERS_B3b___ ___, DF(_BEAKL), DF(_BEPO), DF(_DVORAK_BP), ___
+
+// transient layers.
+#define ___5_LAYERS_T___ ___, MO(_NAV), MO(_SYMB), MO(_KEYPAD), MO(_TOPROWS)
+#define ___5_LAYERS_T_BP___ ___, MO(_NAV), MO(_SYMB_BP), MO(_KEYPAD_BP), MO(_TOPROWS_BP)
+#define ___5_LAYERS_T_CTL___ ___, MO(_RGB), ___, ___, MO(_ADJUST)
+
+
+/// A Layers Layer
+#define ___12_LAYERS_1___ ___, ___5_LAYERS_B1___, ___5_LAYERS_T_BP___, ___
+#define ___12_LAYERS_2___ ___, ___5_LAYERS_B2___, ___5_LAYERS_T___, ___
+#define ___12_LAYERS_3___ KC_SPACETEST, ___5___, ___5_LAYERS_T_CTL___, ___
+
+/********************************************************************************/
+/* The LAYERS LAYER Chunk */
+/********************************************************************************/
+#define ___LAYERS_3x12___ ___12_LAYERS_1___, ___12_LAYERS_2___, ___12_LAYERS_3___
diff --git a/users/ericgebhart/layouts.h b/users/ericgebhart/layouts.h
new file mode 100644
index 0000000000..5ca9b00e6e
--- /dev/null
+++ b/users/ericgebhart/layouts.h
@@ -0,0 +1,720 @@
+#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "core_keysets.h"
+#include "mod_layer.h"
+#include "edge_keys.h"
+
+/******************************************************************/
+/* This is where I put my Keyboard layouts. */
+/* The mod layer can be modified in mod_layer.h */
+/* can be applied here. The physical shape of the keyboard is */
+/* also accounted for here. This makes it very simple to add a */
+/* new keyboard and reuse all of my layouts and layers */
+/* */
+/* With all of that in hand, we then create a LAYOUT wrapper */
+/* macro that takes a list of keys, to create a keyboard matrix */
+/* that fits the keyboard. Simple. */
+/* */
+/* The thumb keys, the bottom rows, etc. */
+/* */
+/* An attempt has been made to adapt the kinesis and ergodox */
+/* Thumb keys to the rectangular shapes of the xd75, viterbi, */
+/* and rebound. */
+/******************************************************************/
+
+/******************************************************************/
+/* * The XD75 is a 5x15 Ortholinear matrix which means it has 3 */
+/* keys inbetween the usual left and right hand keys */
+/* * The Viterbi is a split 5x14 Ortholinear with 2 middle keys. */
+/* * The Ergodox is a split 5x14 Ortholinear with 2 middle keys, */
+/* thumbkeys. It is missing middle keys on (home) row 3. */
+/* * The Corne is a split 3x12 with 6 thumb keys. It has no */
+/* extra middle keys */
+/* */
+/******************************************************************/
+
+
+/******************************************************************/
+/* In all cases these keyboards are defined in a matrix which is */
+/* a set of rows. Maybe like so, or not. */
+/* */
+/* -------------------------|------------------------ */
+/* | Left0 | Numbers L | mid|dle0 | numbers R | Right0 | */
+/* | Left1 | keys0-5 | mid|dle1 | Keys6-10 | Right1 | */
+/* | Left2 | keys11-15 | mid|dle2 | Keys16-20 | Right2 | */
+/* | Left3 | keys20-25 | mid|dle3 | Keys25-30 | Right3 | */
+/* | Row5L | Row5R | */
+/* | ThumbsL | ThumbsR | */
+/* -------------------------|------------------------ */
+
+/* Generally speaking, the keys on the right and left don't change. */
+/* Neither does the bottom row or the thumbs. Frequently the numbers */
+/* row is identical across layers. Mostly, we want our Base layers to */
+/* be predctable. */
+
+
+// Since our quirky block definitions are basically a list of comma separated
+// arguments, we need a wrapper in order for these definitions to be
+// expanded before being used as arguments to the LAYOUT_xxx macro.
+#if (!defined(LAYOUT) && defined(KEYMAP))
+#define LAYOUT KEYMAP
+#endif
+
+// every keyboard has it's Layout. We start there and make a var args
+// out of it.
+
+#define LVARG_ergodox(...) LAYOUT_ergodox(__VA_ARGS__)
+#define LVARG_edox(...) LAYOUT_ergodox_pretty(__VA_ARGS__)
+#define LAYOUT_VARG(...) LAYOUT(__VA_ARGS__)
+#define LAYOUT_PVARG(...) LAYOUT_pretty(__VA_ARGS__)
+
+#define LVARG_4x12(...) LAYOUT_ortho_4x12(__VA_ARGS__)
+#define LVARG_5x12(...) LAYOUT_ortho_5x12(__VA_ARGS__)
+#define LVARG_5x14(...) LAYOUT_ortho_5x14(__VA_ARGS__)
+#define LVARG_5x15(...) LAYOUT_ortho_5x15(__VA_ARGS__)
+
+/*
+ | Left | Numbers L | middle | numbers R | Right |
+ | Left | keys0-5 | middle | Keys6-10 | Right |
+ | Left | keys11-15 | middle | Keys16-20 | Right |
+ | Left | keys20-25 | middle | Keys25-30 | Right |
+ |Row5L Row5R |
+ |ThumbsL ThumbsR |
+*/
+
+/* Assuming that left, midddle, right, row5, and thumbs stay the same, */
+/* numbers, no numbers, numbers never change, whatever. */
+/* we can have a layout macro that takes a nice rectangle of keys. */
+
+/* Actually, because of Bepo, each keyboard currently requires four of */
+/* these macros. One for Qwerty, One for foreign layouts on bepo like */
+/* dvorak and beakl on bepo instead of on Qwerty. Then another for the Bepo */
+/* layout because unlike the rest of the layouts Bepo doesn't fit in */
+/* 3x10. It wants 3x12. So there are potentially 4 macros per keyboard here. */
+/* XXXX_base, XXXX_base_bepo, XXXX_base_bepo6, The 4th macro */
+/* is XXXXX_transient and generally works for all other */
+/* non base layers. */
+/* The base and transient versions are all that is necessary, if bepo is */
+/* not needed. */
+
+
+/* All layouts are relatively simple to make. */
+/* The ROW macros add a universal mod layer so that mods can be defined once */
+/* and used everywhere. No matter the keymap or layer. this allows actual maps */
+/* like dvorak, qwerty, colemak, beakl, etc., to be defined simply. */
+
+
+/* Additional, more complicated layouts can be found here.*/
+/* examples can be found in crkbd/keymaps/ericgebhart */
+/* examples can be found in kinesis/keymaps/ericgebhart */
+/* examples can be found in ergodox/keymaps/ericgebhart */
+/* examples can be found in montsinger/rebound/rev4/keymaps/ericgebhart */
+
+
+
+/********************************************************************/
+/* xiudi/xd75 - Ortholinear 5x15 */
+/********************************************************************/
+/// These first two base layout templates take sets of 5 keys, left and right.
+// Using 4 sets allows for changing the number row if you have one.
+// if you never change the number row, then use 3 sets of left and right.
+// and define the number row here.
+#define LAYOUT_5x15_base( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A, \
+ K31, K32, K33, K34, K35, \
+ K36, K37, K38, K39, K3A) \
+ LVARG_5x15( \
+ ROW0_LEFT(K01, K02, K03, K04, K05), \
+ ___3_MIDDLE_T___, \
+ ROW0_RIGHT(K06, K07, K08, K09, K0A), \
+ \
+ ROW1_LEFT(K11, K12, K13, K14, K15), \
+ ___3_MIDDLE_1___, \
+ ROW1_RIGHT(K16, K17, K18, K19, K1A), \
+ \
+ ROW2_LEFT(K21, K22, K23, K24, K25), \
+ ___3_MIDDLE_2___, \
+ ROW2_RIGHT(K26, K27, K28, K29, K2A), \
+ \
+ ROW3_LEFT(K31, K32, K33, K34, K35), \
+ ___3_MIDDLE_3___, \
+ ROW3_RIGHT(K36, K37, K38, K39, K3A), \
+ ___15_BOTTOM___ \
+ )
+
+#define LAYOUT_5x15_base_bepo( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A, \
+ K31, K32, K33, K34, K35, \
+ K36, K37, K38, K39, K3A) \
+ LVARG_5x15( \
+ ROW0_LEFT_BP(K01, K02, K03, K04, K05), \
+ ___3_MIDDLE_T___, \
+ ROW0_RIGHT_BP(K06, K07, K08, K09, K0A), \
+ \
+ ROW1_LEFT_BP(K11, K12, K13, K14, K15), \
+ ___3_MIDDLE_1_BP___, \
+ ROW1_RIGHT_BP(K16, K17, K18, K19, K1A), \
+ \
+ ROW2_LEFT_BP(K21, K22, K23, K24, K25), \
+ ___3_MIDDLE_2_BP___, \
+ ROW2_RIGHT_BP(K26, K27, K28, K29, K2A), \
+ \
+ ROW3_LEFT_BP(K31, K32, K33, K34, K35), \
+ ___3_MIDDLE_3_BP___, \
+ ROW3_RIGHT_BP(K36, K37, K38, K39, K3A), \
+ ___15_BOTTOM_BP___ \
+ )
+
+// Just for bepo because it's a 3x6 matrix on each side.
+// So 3 pairs of 6 keys, left and right.
+#define Layout_5x15_base_bepo6( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LVARG_5x15( \
+ ___15_B_SYMB___, \
+ ROW1_LEFT_BP6(K01, K02, K03, K04, K05, K06), \
+ ___3_MIDDLE_1_BP___, \
+ ROW1_RIGHT_BP6(K07, K08, K09, K0A, K0B, K0C), \
+ \
+ ROW2_LEFT_BP6(K11, K12, K13, K14, K15, K16), \
+ ___3_MIDDLE_2___, \
+ ROW2_RIGHT_BP6(K17, K18, K19, K1A, K1B, K1C), \
+ \
+ ROW3_LEFT_BP6(K21, K22, K23, K24, K25, K26), \
+ ___3_MIDDLE_3___, \
+ ROW3_RIGHT_BP6(K27, K28, K29, K2A, K2B, K2C), \
+ ___15_BOTTOM_BP___ \
+ )
+
+ // 4 rows of 12. 3 columns transparent in the middle.
+#define LAYOUT_5x15_transient( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ K31, K32, K33, K34, K35, K36, \
+ K37, K38, K39, K3A, K3B, K3C \
+ ) \
+ LVARG_5x15( \
+ K01, K02, K03, K04, K05, K06, \
+ ___3___, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ ___3___, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ ___3___, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ K31, K32, K33, K34, K35, K36, \
+ ___3___, \
+ K37, K38, K39, K3A, K3B, K3C, \
+ ___15___) \
+
+#define BASE_5x15(...) LAYOUT_5x15_base(__VA_ARGS__)
+#define BASE_5x15_bepo(...) LAYOUT_5x15_base_bepo(__VA_ARGS__)
+#define BASE_5x15_bepo6(...) LAYOUT_5x15_base_bepo6(__VA_ARGS__)
+#define TRANSIENT_5x15(...) LAYOUT_5x15_transient(__VA_ARGS__)
+
+/********************************************************************/
+
+
+/********************************************************************/
+/* viterbi - Ortholinear 5x14 */
+/********************************************************************/
+#define LAYOUT_5x14_base( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A, \
+ K31, K32, K33, K34, K35, \
+ K36, K37, K38, K39, K3A) \
+ LVARG_5x14( \
+ ROW0_LEFT(K01, K02, K03, K04, K05), \
+ ___2_MIDDLE_T___, \
+ ROW0_RIGHT(K06, K07, K08, K09, K0A), \
+ \
+ ROW1_LEFT(K11, K12, K13, K14, K15), \
+ ___2_MIDDLE_1___, \
+ ROW1_RIGHT(K16, K17, K18, K19, K1A), \
+ \
+ ROW2_LEFT(K21, K22, K23, K24, K25), \
+ ___2_MIDDLE_2___, \
+ ROW2_RIGHT(K26, K27, K28, K29, K2A), \
+ \
+ ROW3_LEFT(K31, K32, K33, K34, K35), \
+ ___2_MIDDLE_3___, \
+ ROW3_RIGHT(K36, K37, K38, K39, K3A), \
+ ___14_BOTTOM___ \
+ )
+
+#define LAYOUT_5x14_base_bepo( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A, \
+ K31, K32, K33, K34, K35, \
+ K36, K37, K38, K39, K3A) \
+ LVARG_5x14( \
+ ROW0_LEFT_BP(K01, K02, K03, K04, K05), \
+ ___2_MIDDLE_T___, \
+ ROW0_RIGHT_BP(K06, K07, K08, K09, K0A), \
+ \
+ ROW1_LEFT_BP(K11, K12, K13, K14, K15), \
+ ___2_MIDDLE_1_BP___, \
+ ROW1_RIGHT_BP(K16, K17, K18, K19, K1A), \
+ \
+ ROW2_LEFT_BP(K21, K22, K23, K24, K25), \
+ ___2_MIDDLE_2_BP___, \
+ ROW2_RIGHT_BP(K26, K27, K28, K29, K2A), \
+ \
+ ROW3_LEFT_BP(K31, K32, K33, K34, K35), \
+ ___2_MIDDLE_3_BP___, \
+ ROW3_RIGHT_BP(K36, K37, K38, K39, K3A), \
+ ___14_BOTTOM_BP___ \
+ )
+
+ // Just for bepo because it's a 3x6 matrix on each side.
+// So 3 pairs of 6 keys, left and right.
+#define LAYOUT_5x14_base_bepo6( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LVARG_5x14( \
+ ___14_B_SYMB___, \
+ ROW1_LEFT_BP6(K01, K02, K03, K04, K05, K06), \
+ ___2_MIDDLE_1_BP___, \
+ ROW1_RIGHT_BP6(K07, K08, K09, K0A, K0B, K0C), \
+ \
+ ROW2_LEFT_BP6(K11, K12, K13, K14, K15, K16), \
+ ___2_MIDDLE_2___, \
+ ROW2_RIGHT_BP6(K17, K18, K19, K1A, K1B, K1C), \
+ \
+ ROW3_LEFT_BP6(K21, K22, K23, K24, K25, K26), \
+ ___2_MIDDLE_3___, \
+ ROW3_RIGHT_BP6(K27, K28, K29, K2A, K2B, K2C), \
+ ___14_BOTTOM_BP___ \
+ )
+
+// 4 rows of 12. 2 columns transparent in the middle.
+#define LAYOUT_5x14_transient( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ K31, K32, K33, K34, K35, K36, \
+ K37, K38, K39, K3A, K3B, K3C \
+ ) \
+ LVARG_5x14( \
+ K01, K02, K03, K04, K05, K06, \
+ ___2___, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ ___2___, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ ___2___, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ K31, K32, K33, K34, K35, K36, \
+ ___2___, \
+ K37, K38, K39, K3A, K3B, K3C, \
+ ___14___ \
+ ) \
+
+#define BASE_5x14(...) LAYOUT_5x14_base(__VA_ARGS__)
+#define BASE_5x14_bepo(...) LAYOUT_5x14_base_bepo(__VA_ARGS__)
+#define BASE_5x14_bepo6(...) LAYOUT_5x14_base_bepo6(__VA_ARGS__)
+#define TRANSIENT_5x14(...) LAYOUT_5x14_transient(__VA_ARGS__)
+
+/********************************************************************/
+/* Ortholinear 4x12 */
+/********************************************************************/
+#define LAYOUT_4x12_base( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A \
+ ) \
+ LVARG_4x12( \
+ ROW1_LEFT(K01, K02, K03, K04, K05), \
+ ROW1_RIGHT(K06, K07, K08, K09, K0A), \
+ \
+ ROW2_LEFT(K11, K12, K13, K14, K15), \
+ ROW2_RIGHT(K16, K17, K18, K19, K1A), \
+ \
+ ROW3_LEFT(K21, K22, K23, K24, K25), \
+ ROW3_RIGHT(K26, K27, K28, K29, K2A), \
+ \
+ ___12_BOTTOM___ \
+ )
+
+#define LAYOUT_4x12_base_bepo( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A \
+ ) \
+ LVARG_4x12( \
+ ROW1_LEFT_BP(K01, K02, K03, K04, K05), \
+ ROW1_RIGHT_BP(K06, K07, K08, K09, K0A), \
+ \
+ ROW2_LEFT_BP(K11, K12, K13, K14, K15), \
+ ROW2_RIGHT_BP(K16, K17, K18, K19, K1A), \
+ \
+ ROW3_LEFT_BP(K21, K22, K23, K24, K25), \
+ ROW3_RIGHT_BP(K26, K27, K28, K29, K2A), \
+ \
+ ___12_BOTTOM_BP___ \
+ )
+
+ // Just for bepo because it's a 3x6 matrix on each side.
+ // So 3 pairs of 6 keys, left and right.
+#define Layout_4x12_base_bepo6( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LVARG_4x12( \
+ ROW1_LEFT_BP6(K01, K02, K03, K04, K05, K06), \
+ ROW1_RIGHT_BP6(K07, K08, K09, K0A, K0B, K0C), \
+ \
+ ROW2_LEFT_BP6(K11, K12, K13, K14, K15, K16), \
+ ROW2_RIGHT_BP6(K17, K18, K19, K1A, K1B, K1C), \
+ \
+ ROW3_LEFT_BP6(K21, K22, K23, K24, K25, K26), \
+ ROW3_RIGHT_BP6(K27, K28, K29, K2A, K2B, K2C), \
+ ___12_BOTTOM_BP___ \
+ )
+
+// takes 3 makes 4 rows of 12.
+#define LAYOUT_4x12_transient( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LVARG_4x12( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ ___12___) \
+
+#define BASE_4x12(...) LAYOUT_4x12_base(__VA_ARGS__)
+#define BASE_4x12_bepo(...) LAYOUT_4x12_base_bepo(__VA_ARGS__)
+#define BASE_4x12_bepo6(...) LAYOUT_4x12_base_bepo6(__VA_ARGS__)
+#define TRANSIENT_4x12(...) LAYOUT_4x12_transient(__VA_ARGS__)
+
+/********************************************************************/
+/* CRKBD Corne */
+/* The Corne has 3x6 matrix on both sides with 6 thumbs total */
+/* This Macro takes 2x3x5 and gives it pinkies, and thumbs. */
+/* Arg chunks are in the middle with the passthrough modifiers as */
+/* needed. Sama Sama apres cette fois. */
+/********************************************************************/
+#define Base_3x6_3( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A) \
+ LAYOUT_VARG( \
+ ROW1_LEFT(K01, K02, K03, K04, K05), \
+ ROW1_RIGHT(K06, K07, K08, K09, K0A), \
+ \
+ ROW2_LEFT(K11, K12, K13, K14, K15), \
+ ROW2_RIGHT(K16, K17, K18, K19, K1A), \
+ \
+ ROW3_LEFT(K21, K22, K23, K24, K25), \
+ ROW3_RIGHT(K26, K27, K28, K29, K2A), \
+ ___6_ERGO_THUMBS___ \
+ )
+
+// So we can have different transient layers for symbols and numbers on bepo.
+// for layouts like dvorak on bepo.
+#define Base_bepo_3x6_3( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A \
+ ) \
+ LAYOUT_VARG( \
+ ROW1_LEFT_BP(K01, K02, K03, K04, K05), \
+ ROW1_RIGHT_BP(K06, K07, K08, K09, K0A), \
+ \
+ ROW2_LEFT_BP(K11, K12, K13, K14, K15), \
+ ROW2_RIGHT_BP(K16, K17, K18, K19, K1A), \
+ \
+ ROW3_LEFT_BP(K21, K22, K23, K24, K25), \
+ ROW3_RIGHT_BP(K26, K27, K28, K29, K2A), \
+ ___6_ERGO_THUMBS_BP___ \
+ )
+
+// No room for pinkies.
+// Just for bepo because it's a 3x6 matrix on each side.
+// So 3 pairs of 6 keys, And we lose our left and right.
+// Except it keeps the layer toggles along with the keycode
+// on the bottom.
+#define Base_bepo6_3x6_3( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LAYOUT_VARG( \
+ ROW1_LEFT_BP6(K01, K02, K03, K04, K05, K06), \
+ ROW1_RIGHT_BP6(K07, K08, K09, K0A, K0B, K0C), \
+ \
+ ROW2_LEFT_BP6(K11, K12, K13, K14, K15, K16), \
+ ROW2_RIGHT_BP6(K17, K18, K19, K1A, K1B, K1C), \
+ \
+ ROW3_LEFT_BP6(K21, K22, K23, K24, K25, K26), \
+ ROW3_RIGHT_BP6(K27, K28, K29, K2A, K2B, K2C), \
+ ___6_ERGO_THUMBS_BP___ \
+ )
+
+// All we really need is to add the see through thumbs to the end.
+#define Transient6_3x6_3( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LAYOUT_VARG( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ ___6___)
+
+//---------------------------------------------------------
+// 3x5
+#define Base_3x5_3( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A) \
+ LAYOUT_VARG( \
+ ROW1_LEFT5(K01, K02, K03, K04, K05), \
+ ROW1_RIGHT5(K06, K07, K08, K09, K0A), \
+ \
+ ROW2_LEFT5(K11, K12, K13, K14, K15), \
+ ROW2_RIGHT5(K16, K17, K18, K19, K1A), \
+ \
+ ROW3_LEFT5(K21, K22, K23, K24, K25), \
+ ROW3_RIGHT5(K26, K27, K28, K29, K2A), \
+ ___6_ERGO_THUMBS___ \
+ )
+
+// So we can have different transient layers for symbols and numbers on bepo.
+// for layouts like dvorak on bepo.
+#define Base_bepo_3x5_3( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A \
+ ) \
+ LAYOUT_VARG( \
+ ROW1_LEFT5_BP(K01, K02, K03, K04, K05), \
+ ROW1_RIGHT5_BP(K06, K07, K08, K09, K0A), \
+ \
+ ROW2_LEFT5_BP(K11, K12, K13, K14, K15), \
+ ROW2_RIGHT5_BP(K16, K17, K18, K19, K1A), \
+ \
+ ROW3_LEFT5_BP(K21, K22, K23, K24, K25), \
+ ROW3_RIGHT5_BP(K26, K27, K28, K29, K2A), \
+ ___6_ERGO_THUMBS_BP___ \
+ )
+
+// All we really need is to add the see through thumbs to the end.
+#define Transient5_3x5_3( \
+ K01, K02, K03, K04, K05, \
+ K07, K08, K09, K0A, K0B, \
+ K11, K12, K13, K14, K15, \
+ K17, K18, K19, K1A, K1B, \
+ K21, K22, K23, K24, K25, \
+ K27, K28, K29, K2A, K2B \
+ ) \
+ LAYOUT_VARG( \
+ K01, K02, K03, K04, K05, \
+ K07, K08, K09, K0A, K0B, \
+ K11, K12, K13, K14, K15, \
+ K17, K18, K19, K1A, K1B, \
+ K21, K22, K23, K24, K25, \
+ K27, K28, K29, K2A, K2B, \
+ ___6___)
+
+/********************************************************************/
+/* Kinesis*/
+/********************************************************************/
+// Basically an ergodox ez without the 3 pairs of middle keys.
+// Left, right, bottom, and thumbs all stay the same.
+#define Base_4x6_4_6( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A, \
+ K31, K32, K33, K34, K35, \
+ K36, K37, K38, K39, K3A \
+ ) \
+ LAYOUT_PVARG( \
+ ___KINTFUNC_L___, ___KINTFUNC_R___, \
+ ROW0_LEFT(K01, K02, K03, K04, K05), \
+ ROW0_RIGHT(K06, K07, K08, K09, K0A), \
+ \
+ ROW1_LEFT(K11, K12, K13, K14, K15), \
+ ROW1_RIGHT(K16, K17, K18, K19, K1A), \
+ \
+ ROW2_LEFT(K21, K22, K23, K24, K25), \
+ ROW2_RIGHT(K26, K27, K28, K29, K2A), \
+ \
+ ROW3_LEFT(K31, K32, K33, K34, K35), \
+ ROW3_RIGHT(K36, K37, K38, K39, K3A), \
+ ___4_BOTTOM_LEFT___, ___4_BOTTOM_RIGHT___, \
+ ___12_DOX_ALL_THUMBS___ \
+ )
+
+#define Base_bepo_4x6_4_6( \
+ K01, K02, K03, K04, K05, \
+ K06, K07, K08, K09, K0A, \
+ K11, K12, K13, K14, K15, \
+ K16, K17, K18, K19, K1A, \
+ K21, K22, K23, K24, K25, \
+ K26, K27, K28, K29, K2A, \
+ K31, K32, K33, K34, K35, \
+ K36, K37, K38, K39, K3A \
+ ) \
+ LAYOUT_PVARG( \
+ ___KINTFUNC_L___, ___KINTFUNC_R___, \
+ ROW0_LEFT(K01, K02, K03, K04, K05), \
+ ROW0_RIGHT(K06, K07, K08, K09, K0A), \
+ \
+ ROW1_LEFT(K11, K12, K13, K14, K15), \
+ ROW1_RIGHT(K16, K17, K18, K19, K1A), \
+ \
+ ROW2_LEFT(K21, K22, K23, K24, K25), \
+ ROW2_RIGHT(K26, K27, K28, K29, K2A), \
+ \
+ ROW3_LEFT(K31, K32, K33, K34, K35), \
+ ROW3_RIGHT(K36, K37, K38, K39, K3A), \
+ ___4_BOTTOM_LEFT___, ___4_BOTTOM_RIGHT___, \
+ ___12_DOX_ALL_THUMBS_BP___ \
+ )
+
+
+// So 3 pairs of 6 keys, left and right.
+#define Base_bepo6_4x6_4_6( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C \
+ ) \
+ LAYOUT_PVARG( \
+ ___KINTFUNC_L___, ___KINTFUNC_R___, \
+ ___6SYMBOL_BEPO_L___, \
+ ___6SYMBOL_BEPO_R___, \
+ ROW1_LEFT_BP6(K01, K02, K03, K04, K05, K06), \
+ ROW1_RIGHT_BP6(K07, K08, K09, K0A, K0B, K0C), \
+ \
+ ROW2_LEFT_BP6(K11, K12, K13, K14, K15, K16), \
+ ROW2_RIGHT_BP6(K17, K18, K19, K1A, K1B, K1C), \
+ \
+ ROW3_LEFT_BP6(K21, K22, K23, K24, K25, K26), \
+ ROW3_RIGHT_BP6(K27, K28, K29, K2A, K2B, K2C), \
+ ___4_BOTTOM_LEFT_BP___, ___4_BOTTOM_RIGHT_BP___, \
+ ___12_DOX_ALL_THUMBS_BP___ \
+ )
+
+#define Transient6_4x6_4_6( \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ K31, K32, K33, K34, K35, K36, \
+ K37, K38, K39, K3A, K3B, K3C \
+ ) \
+ LAYOUT_PVARG( \
+ ___KINTFUNC_L___, ___KINTFUNC_R___, \
+ K01, K02, K03, K04, K05, K06, \
+ K07, K08, K09, K0A, K0B, K0C, \
+ K11, K12, K13, K14, K15, K16, \
+ K17, K18, K19, K1A, K1B, K1C, \
+ K21, K22, K23, K24, K25, K26, \
+ K27, K28, K29, K2A, K2B, K2C, \
+ K31, K32, K33, K34, K35, K36, \
+ K37, K38, K39, K3A, K3B, K3C, \
+ ___4___, ___4___, \
+ ___12___ \
+ )
diff --git a/users/ericgebhart/mod_layer.h b/users/ericgebhart/mod_layer.h
new file mode 100644
index 0000000000..a3c64b0bf7
--- /dev/null
+++ b/users/ericgebhart/mod_layer.h
@@ -0,0 +1,178 @@
+#pragma once
+
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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/>.
+*/
+// define our rows for the mod layer
+// takes 5 keycodes, adds mods, and left and right
+// so we get keycodes in groups of 6.
+// There are 3 sets of 4 rows.
+// 1 for normal 6 columns, qwerty, dvorak etc.
+// 1 for bepo/normal 6 columns, qwerty, dvorak etc. on bepo.
+// 1 for bepo 6 columns provided instead of a 5, for bepo which needs 3x12.
+// A 5 column keyboard would need another set of MACROS.
+
+// These macros are used in the layout wrapper macros to introduce a mod
+// layer. HomeRow mods and other things like that go here.
+
+
+#include "core_keys.h"
+
+//number row.
+#define ROW0_LEFT(K01, K02, K03, K04, K05) \
+ LEFT0, K01, K02, K03, K04, K05
+
+#define ROW0_RIGHT(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05, RIGHT0
+
+#define ROW1_LEFT(K01, K02, K03, K04, K05) \
+ LEFT1, K01, K02, K03, LT(_NAV, K04), K05
+
+#define ROW1_RIGHT(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05, RIGHT1
+
+// home row, shift, alt, ctl, gui - gui, ctl, alt, shift.
+// using MT so we can specify left and right.
+// caps_word needs left and right shift.
+#define ROW2_LEFT(K01, K02, K03, K04, K05) \
+ LEFT2, MT(MOD_LSFT, K01), MT(MOD_LALT, K02), MT(MOD_LCTL, K03), MT(MOD_LGUI, K04), K05
+
+#define ROW2_RIGHT(K01, K02, K03, K04, K05) \
+ K01, MT(MOD_RGUI, K02), MT(MOD_RCTL, K03), MT(MOD_RALT, K04), MT(MOD_RSFT, K05), RIGHT2 \
+
+#define ROW3_LEFT(K01, K02, K03, K04, K05) \
+ LEFT3, K01, LT(_TOPROWS, K02), K03, LT(_SYMB, K04), K05
+
+#define ROW3_RIGHT(K01, K02, K03, K04, K05) \
+ K01, LT(_SYMB, K02), LT(_NAV, K03), LT(_TOPROWS, K04), K05, RIGHT3
+
+
+//-----------------------------------------------y
+// For a 5 column keyboard - no edges added.
+//number row.
+#define ROW0_LEFT5(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05
+
+#define ROW0_RIGHT5(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05
+
+#define ROW1_LEFT5(K01, K02, K03, K04, K05) \
+ LT(_LAYERS, K01), K02, LT(_KEYPAD, K03), K04, K05
+
+#define ROW1_RIGHT5(K01, K02, K03, K04, K05) \
+ K01, K02, LT(_KEYPAD, K03), K04, LT(_LAYERS, K05)
+
+// home row, shift, alt, ctl, gui - gui, ctl, alt, shift.
+// using MT so we can specify left and right.
+// caps_word needs left and right shift.
+#define ROW2_LEFT5(K01, K02, K03, K04, K05) \
+ MT(MOD_LSFT, K01), MT(MOD_LALT, K02), MT(MOD_LCTL, K03), MT(MOD_LGUI, K04), K05
+
+#define ROW2_RIGHT5(K01, K02, K03, K04, K05) \
+ K01, MT(MOD_RGUI, K02), MT(MOD_RCTL, K03), MT(MOD_RALT, K04), MT(MOD_RSFT, K05)
+
+#define ROW3_LEFT5(K01, K02, K03, K04, K05) \
+ K01, LT(_TOPROWS, K02), LT(_NAV, K03), LT(_SYMB, K04), K05
+
+#define ROW3_RIGHT5(K01, K02, K03, K04, K05) \
+ K01, LT(_SYMB, K02), LT(_NAV, K03), LT(_TOPROWS, K04), K05
+
+
+//--------------------------------------------
+//bepo
+#define ROW0_LEFT_BP(K01, K02, K03, K04, K05) \
+ LEFT0_BP, K01, K02, K03, K04, K05
+
+#define ROW0_RIGHT_BP(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05, RIGHT0_BP
+
+#define ROW1_LEFT_BP(K01, K02, K03, K04, K05) \
+ LEFT1_BP, K01, K02, K03, LT(_KEYPAD, K04), K05
+
+#define ROW1_RIGHT_BP(K01, K02, K03, K04, K05) \
+ K01, K02, LT(_KEYPAD, K03), K04, K05, RIGHT1_BP
+
+#define ROW2_LEFT_BP(K01, K02, K03, K04, K05) \
+ LEFT2_BP, MT(MOD_RSFT, K01), MT(MOD_LALT,K02), MT(MOD_RCTL, K03), \
+ MT(MOD_LGUI, K04), K05
+
+#define ROW2_RIGHT_BP(K01, K02, K03, K04, K05) \
+ K01, MT(MOD_RGUI, K02), MT(MOD_RCTL, K03), MT(MOD_RALT, K04), \
+ MT(MOD_RSFT, K05), RIGHT2_BP \
+
+#define ROW3_LEFT_BP(K01, K02, K03, K04, K05) \
+ LEFT3_BP, K01, LT(_SYMB_BP, K02), LT(_NAV, K03), LT(_TOPROWS_BP, K04), K05
+
+#define ROW3_RIGHT_BP(K01, K02, K03, K04, K05) \
+ K01, LT(_SYMB_BP, K02), LT(_NAV, K03), LT(_TOPROWS_BP, K04), K05, RIGHT3_BP
+
+
+//-------------------------------------------------
+//bepo - 6 args, no left or right added.
+#define ROW0_LEFT_BP6(K01, K02, K03, K04, K05, K06) \
+ K01, K02, K03, K04, K05, K06
+
+#define ROW0_RIGHT_BP6(K01, K02, K03, K04, K05, K06 ) \
+ K01, K02, K03, K04, K05, K06
+
+#define ROW1_LEFT_BP6(K01, K02, K03, K04, K05, K06) \
+ K01, K02, K03, K04, K05, K06
+
+#define ROW1_RIGHT_BP6(K01, K02, K03, K04, K05, K06 ) \
+ K01, K02, K03, K04, K05, K06
+
+#define ROW2_LEFT_BP6(K01, K02, K03, K04, K05, K06) \
+ K01, SFT_T(K02), ALT_T(K03), CTL_T(K04), GUI_T(K05), K06
+
+#define ROW2_RIGHT_BP6(K01, K02, K03, K04, K05, K06) \
+ K01, GUI_T(K02), RCTL_T(K03), RALT_T(K04), RSFT_T(K05), K06
+
+#define ROW3_LEFT_BP6(K01, K02, K03, K04, K05, K06) \
+ K01, K02, K03, K04, K05, K06
+
+#define ROW3_RIGHT_BP6(K01, K02, K03, K04, K05, K06 ) \
+ K01, K02, K03, K04, K05, K06
+
+
+//-------------------------------------------------
+// For a 5 column keyboard - no edges added.
+//number row.
+#define ROW0_LEFT5_BP(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05
+
+#define ROW0_RIGHT5_BP(K01, K02, K03, K04, K05) \
+ K01, K02, K03, K04, K05
+
+#define ROW1_LEFT5_BP(K01, K02, K03, K04, K05) \
+ LT(_LAYERS, K01), K02, K03, LT(_KEYPAD_BP, K04), K05
+
+#define ROW1_RIGHT5_BP(K01, K02, K03, K04, K05) \
+ K01, LT(_KEYPAD_BP, K02), K03, K04, K05
+
+// home row, shift, alt, ctl, gui - gui, ctl, alt, shift.
+// using MT so we can specify left and right.
+// caps_word needs left and right shift.
+#define ROW2_LEFT5_BP(K01, K02, K03, K04, K05) \
+ MT(MOD_LSFT, K01), MT(MOD_LALT, K02), MT(MOD_LCTL, K03), MT(MOD_LGUI, K04), K05
+
+#define ROW2_RIGHT5_BP(K01, K02, K03, K04, K05) \
+ K01, MT(MOD_RGUI, K02), MT(MOD_RCTL, K03), MT(MOD_RALT, K04), MT(MOD_RSFT, K05)
+
+#define ROW3_LEFT5_BP(K01, K02, K03, K04, K05) \
+ K01, LT(_TOPROWS_BP, K02), LT(_NAV, K03), LT(_SYMB_BP, K04), K05
+
+#define ROW3_RIGHT5_BP(K01, K02, K03, K04, K05) \
+ K01, LT(_SYMB_BP, K02), LT(_NAV, K03), LT(_TOPROWS_BP, K04), K05
diff --git a/users/ericgebhart/oled_stuff.c b/users/ericgebhart/oled_stuff.c
new file mode 100755
index 0000000000..99a752ec2f
--- /dev/null
+++ b/users/ericgebhart/oled_stuff.c
@@ -0,0 +1,303 @@
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "ericgebhart.h"
+#include <string.h>
+#include <stdio.h>
+
+void oled_render_default_layer_state(void) {
+ oled_write_P(PSTR("Layout: "), false);
+ switch (get_highest_layer(default_layer_state)) {
+ case _QWERTY:
+ oled_write_ln_P(PSTR("Qwerty"), false);
+ break;
+ case _COLEMAK:
+ oled_write_ln_P(PSTR("Colemak"), false);
+ break;
+ case _DVORAK_BP:
+ case _DVORAK:
+ oled_write_ln_P(PSTR("Dvorak"), false);
+ break;
+
+
+ /* case _WORKMAN: */
+ // oled_write_ln_P(PSTR("Workman\n"), false);
+ /* break; */
+ /* case _NORMAN: */
+ // oled_write_ln_P(PSTR("Norman\n"), false);
+ /* break; */
+ /* case _MALTRON: */
+ // oled_write_ln_P(PSTR("Maltron\n"), false);
+ /* break; */
+
+ /* case _EUCALYN: */
+ // oled_write_ln_P(PSTR("Eucalyn\n"), false);
+ /* break; */
+ /* case _CARPLAX: */
+ // oled_write_ln_P(PSTR("Carplax\n"), false);
+ /* break; */
+
+ case _BEAKL:
+ case _BEAKL_BP:
+ oled_write_ln_P(PSTR("Beakl"), false);
+ break;
+ case _BEPO:
+ oled_write_ln_P(PSTR("Bepo"), false);
+ break;
+ }
+}
+
+void oled_render_layer_state(void) {
+ oled_write_P(PSTR("Layer: "), false);
+ switch (get_highest_layer(layer_state)) {
+ case _NAV:
+ oled_write_P(PSTR("Navigation"), false);
+ break;
+ case _LAYERS:
+ oled_write_P(PSTR("Layers"), false);
+ break;
+ case _RGB:
+ oled_write_P(PSTR("RGB"), false);
+ break;
+ case _TOPROWS:
+ case _TOPROWS_BP:
+ oled_write_P(PSTR("TopRows"), false);
+ break;
+ case _SYMB:
+ case _SYMB_BP:
+ oled_write_P(PSTR("Symbols"), false);
+ break;
+ case _KEYPAD:
+ case _KEYPAD_BP:
+ oled_write_P(PSTR("Keypad"), false);
+ break;
+ case _ADJUST:
+ oled_write_P(PSTR("Adjust"), false);
+ break;
+ }
+ oled_write_ln_P(PSTR(" "), false);
+}
+
+// this is part of my answer to a challenge.
+// My friend Ross thinks that the only use of an oled
+// is to say which layer.
+// I think there is more. this is just a beginning.
+void oled_render_layer_map(void) {
+ uint8_t lyr = get_highest_layer(layer_state);
+ if (lyr <= _BEPO) {
+ switch (get_highest_layer(default_layer_state)) {
+ case _QWERTY:
+ oled_write_ln_P(PSTR(" qwert yuiop"), false);
+ oled_write_ln_P(PSTR(" asdfg hjkl;"), false);
+ oled_write_ln_P(PSTR(" zxcvb nm,./"), false);
+ break;
+ case _COLEMAK:
+ oled_write_ln_P(PSTR(" qwfpb jluy;"), false);
+ oled_write_ln_P(PSTR(" arstg mneio"), false);
+ oled_write_ln_P(PSTR(" zxcdv kh,./"), false);
+ break;
+ case _DVORAK_BP:
+ case _DVORAK:
+ oled_write_ln_P(PSTR(" \",.py fgcrl"), false);
+ oled_write_ln_P(PSTR(" aoeui dhtns"), false);
+ oled_write_ln_P(PSTR(" ;qjkx bmwvz "), false);
+ break;
+
+ case _BEAKL:
+ case _BEAKL_BP:
+ oled_write_ln_P(PSTR(" qhoux gcrfz"), false);
+ oled_write_ln_P(PSTR(" yiea. dstnb"), false);
+ oled_write_ln_P(PSTR(" j/,k' wmlpv"), false);
+ break;
+
+ case _BEPO:
+ oled_write_P(PSTR(" cbe'po`e vdljz %"), false);
+ oled_write_P(PSTR(" auie, tsrnmc"), false);
+ oled_write_P(PSTR(" e^a'yx.k 'qghfw"), false);
+ break;
+ }
+
+ } else {
+
+ switch (lyr) {
+ case _TOPROWS:
+ case _TOPROWS_BP:
+ oled_write_ln_P(PSTR(" !@#$% ^&*()"), false);
+ oled_write_ln_P(PSTR(" 40123 76598"), false);
+ oled_write_ln_P(PSTR(" F1- -- -F12"), false);
+ break;
+
+ case _SYMB:
+ case _SYMB_BP:
+ oled_write_ln_P(PSTR(" `<$>' ?[_]-"), false);
+ oled_write_ln_P(PSTR(" -\\(\")# !{:}/;"), false);
+ oled_write_ln_P(PSTR(" @=*+; %&^~|"), false);
+ break;
+
+ case _NAV:
+ oled_write_ln_P(PSTR("54321 0 ctn 12345"), false);
+ oled_write_ln_P(PSTR(" ldur 1 ccv ldur"), false);
+ oled_write_ln_P(PSTR(" ldur 2 cwq hdue"), false);
+ break;
+
+ case _KEYPAD:
+ oled_write_ln_P(PSTR(" 523: F9-F12"), false);
+ oled_write_ln_P(PSTR(" -7.104 F5-F8"), false);
+ oled_write_ln_P(PSTR(" /698, F1-F4"), false);
+ break;
+
+ case _LAYERS:
+ oled_write_ln_P(PSTR(" Bp Dv Bk|Nv S K TR"), false);
+ oled_write_ln_P(PSTR("Q Cl Dv Bk|Nv S K TR"), false);
+ oled_write_P(PSTR(" "), false);
+ //oled_write_ln_P(PSTR("Ctrls?-> RGB ___ ___ Adjust"), false);
+ break;
+ }
+ }
+}
+
+void oled_render_keylock_status(uint8_t led_usb_state) {
+ oled_write_P(PSTR(" Lock:"), false);
+ oled_write_P(PSTR(" "), false);
+ oled_write_P(PSTR("N"), led_usb_state & (1 << USB_LED_NUM_LOCK));
+ oled_write_P(PSTR("C"), led_usb_state & (1 << USB_LED_CAPS_LOCK));
+ oled_write_ln_P(PSTR("S"), led_usb_state & (1 << USB_LED_SCROLL_LOCK));
+}
+
+void oled_render_mod_status(uint8_t modifiers) {
+ oled_write_P(PSTR("Mods:"), false);
+ oled_write_P(PSTR("S"), (modifiers & MOD_MASK_SHIFT));
+ oled_write_P(PSTR("C"), (modifiers & MOD_MASK_CTRL));
+ oled_write_P(PSTR("A"), (modifiers & MOD_MASK_ALT));
+ oled_write_P(PSTR("G"), (modifiers & MOD_MASK_GUI));
+}
+
+void oled_render_mod_lock_status(){
+ oled_render_mod_status(get_mods() | get_oneshot_mods());
+ oled_render_keylock_status(host_keyboard_leds());
+}
+
+
+char mkeylog_str[22] = {};
+
+const char mcode_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 oled_render_keylog(void) {
+ oled_write_ln(mkeylog_str, false);
+ // sometimes there's an extra row. this is because sometimes it drops
+ // to the last line. and this clears it.
+ oled_write_ln_P(PSTR(" "), false);
+}
+
+
+void add_keylog(uint16_t keycode, keyrecord_t *record) {
+ char name = ' ';
+ if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) ||
+ (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
+ keycode = keycode & 0xFF;
+ }
+ if (keycode < 60) {
+ name = mcode_to_name[keycode];
+ }
+
+ // update keylog
+ memset(mkeylog_str, ' ', sizeof(mkeylog_str) - 1);
+ snprintf(mkeylog_str, sizeof(mkeylog_str), "%dx%d, k%2d : %c",
+ record->event.key.row, record->event.key.col,
+ keycode, name);
+}
+
+__attribute__((weak)) oled_rotation_t oled_init_keymap(oled_rotation_t rotation) { return rotation; }
+
+oled_rotation_t oled_init_user(oled_rotation_t rotation) {
+
+ // for the big screen.
+#ifdef OLED_DISPLAY_128X64
+ return OLED_ROTATION_180;
+#endif
+
+ return oled_init_keymap(rotation);
+}
+
+/* oled_rotation_t oled_init_user(oled_rotation_t rotation) { */
+/* memset(mkeylog_str, ' ', sizeof(mkeylog_str) - 1); */
+/* if (is_keyboard_master()) { */
+/* return OLED_ROTATION_270; */
+/* } else { */
+/* return OLED_ROTATION_180; */
+/* } */
+/* } */
+
+bool process_record_user_oled(uint16_t keycode, keyrecord_t *record) {
+ if (record->event.pressed) {
+ //oled_timer = timer_read32();
+ add_keylog(keycode, record);
+ //add_keylog(keycode);
+ }
+ return true;
+}
+
+void render_bootmagic_status(bool status) {
+ /* Show Ctrl-Gui Swap options */
+ static const char PROGMEM logo[][2][3] = {
+ {{0x97, 0x98, 0}, {0xb7, 0xb8, 0}},
+ {{0x95, 0x96, 0}, {0xb5, 0xb6, 0}},
+ };
+ if (status) {
+ oled_write_ln_P(logo[0][0], false);
+ oled_write_ln_P(logo[0][1], false);
+ } else {
+ oled_write_ln_P(logo[1][0], false);
+ oled_write_ln_P(logo[1][1], false);
+ }
+}
+
+
+__attribute__((weak)) void oled_render_logo(void) {
+ // clang-format off
+ static const char PROGMEM qmk_logo[] = {
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94,
+ 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,0xb0,0xb1,0xb2,0xb3,0xb4,
+ 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,0xd0,0xd1,0xd2,0xd3,0xd4,0};
+ // clang-format on
+ oled_write_P(qmk_logo, false);
+}
+
+bool oled_task_user(void) {
+ if (is_keyboard_master()) {
+ oled_render_mod_lock_status();
+ oled_render_default_layer_state();
+ oled_render_layer_state();
+#ifdef OLED_DISPLAY_128X64
+ oled_render_layer_map();
+#endif
+ oled_render_keylog();
+ } else {
+ oled_render_logo();
+ oled_render_default_layer_state();
+ }
+ return(true);
+
+}
+/* oled_render_keylock_status(host_keyboard_leds()); */
+/* oled_render_mod_status(get_mods() | get_oneshot_mods()); */
diff --git a/users/ericgebhart/oled_stuff.h b/users/ericgebhart/oled_stuff.h
new file mode 100755
index 0000000000..df1f50985f
--- /dev/null
+++ b/users/ericgebhart/oled_stuff.h
@@ -0,0 +1,24 @@
+#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "quantum.h"
+#include "oled_driver.h"
+
+void oled_render_mod_lock_status(void);
+void oled_driver_render_logo(void);
+bool process_record_user_oled(uint16_t keycode, keyrecord_t *record);
diff --git a/users/ericgebhart/process_records.c b/users/ericgebhart/process_records.c
new file mode 100755
index 0000000000..c1036c7f07
--- /dev/null
+++ b/users/ericgebhart/process_records.c
@@ -0,0 +1,255 @@
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "ericgebhart.h"
+#include "caps_word.h"
+#include "g/keymap_combo.h"
+
+__attribute__((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; }
+
+__attribute__((weak)) bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { return true; }
+
+
+uint16_t tap_taplong_timer;
+
+inline void tap_taplong(uint16_t kc1, uint16_t kc2, keyrecord_t *record) {
+ if (record->event.pressed) {
+ tap_taplong_timer = timer_read();
+ } else {
+ if (timer_elapsed(tap_taplong_timer) > TAPPING_TERM) {
+ tap_code16(kc2);
+ } else {
+ tap_code16(kc1);
+ }
+ }
+}
+
+/* for (){}[]""''<>``. tap for open. Hold for open and close, ending inbetween. */
+/* Assumes a one character length. */
+inline void open_openclose(uint16_t kc1, uint16_t kc2, keyrecord_t *record) {
+ if (record->event.pressed) {
+ tap_taplong_timer = timer_read();
+ }else{
+ if (timer_elapsed(tap_taplong_timer) > TAPPING_TERM) {
+ tap_code16(kc1);
+ tap_code16(kc2);
+ tap_code16(KC_LEFT);
+ } else {
+ tap_code16(kc1);
+ }
+ }
+}
+
+// Defines actions for my global custom keycodes. Defined in ericgebhart.h file
+// Then runs the _keymap's record handier if not processed here
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ // If console is enabled, it will print the matrix position and status of each key pressed
+
+#ifdef OLED_ENABLE
+ process_record_user_oled(keycode, record);
+#endif // OLED
+
+ if (!process_caps_word(keycode, record)) { return false; }
+
+ if (process_record_keymap(keycode, record) && process_record_secrets(keycode, record)) {
+ switch (keycode) {
+
+ // Handle the key translations for Dvorak on bepo. It's best if these are the first
+ // enums after SAFE_RANGE.
+ case DB_1 ... BB_QUOT:
+ if(record->event.pressed)
+ send_keycode(keycode);
+ unregister_code(keycode);
+ break;
+
+ // Set the default layer. eeprom if shifted.
+ case KC_DVORAK ... KC_BEPO:
+ if (record->event.pressed) {
+ uint8_t mods = mod_config(get_mods() | get_oneshot_mods());
+ if (!mods) {
+ default_layer_set(1UL << (keycode - KC_DVORAK));
+ } else if (mods & MOD_MASK_SHIFT) {
+ set_single_persistent_default_layer(1UL << (keycode - KC_DVORAK));
+ }
+ }
+ break;
+
+
+ case KC_RESET: // Custom RESET code
+ if (!record->event.pressed) {
+ reset_keyboard();
+ }
+ return false;
+ break;
+
+ case KC_SPACETEST: // test something.
+ // default_layer_set(1UL << _BEAKL);
+ // tap_code16(LSFT(KC_SPACE));
+ break;
+
+
+ // tap or long tap for different key.
+ case KC_CCCV: // One key copy/paste
+ tap_taplong(LCTL(KC_C), LCTL(KC_V), record);
+ break;
+
+ case BP_CCCV: // One key copy/paste
+ tap_taplong(LCTL(BP_C), LCTL(BP_V), record);
+ break;
+
+ case KC_CTCN: // New TaB/Window
+ tap_taplong(LCTL(KC_T), LCTL(KC_N), record);
+ break;
+
+ case BP_CTCN: // New TaB/Window
+ tap_taplong(LCTL(BP_T), LCTL(BP_N), record);
+ break;
+
+ case KC_CWCQ: // Close Tab-window/Quit
+ tap_taplong(LCTL(KC_W), LCTL(KC_Q), record);
+ break;
+
+ case BP_CWCQ: // Close Tab-window/Quit
+ tap_taplong(LCTL(BP_W), LCTL(BP_Q), record);
+ break;
+
+ case KC_XM_PORD: // Xmonad scratch pads or desktop
+ tap_taplong(LGUI(KC_E), LGUI(KC_T), record);
+ break;
+
+ case BP_XM_PORD: // Xmonad scratch pads or desktop
+ tap_taplong(LGUI(BP_E), LGUI(BP_T), record);
+ break;
+
+
+ // Open on tap and Open with close and back arrow on hold.
+ case KC_OCPRN:
+ open_openclose(KC_LPRN, KC_RPRN, record);
+ break;
+
+ case BP_OCPRN:
+ open_openclose(DB_LPRN, DB_RPRN, record);
+ break;
+
+ case KC_OCBRC:
+ open_openclose(KC_LBRC, KC_RBRC, record);
+ break;
+
+ case BP_OCBRC:
+ open_openclose(KC_RBRC, KC_LBRC, record);
+ break;
+
+ case KC_OCCBR:
+ open_openclose(KC_LCBR, KC_RCBR, record);
+ break;
+
+ case BP_OCCBR:
+ open_openclose(BP_LCBR, BP_RCBR, record);
+ break;
+
+ case KC_OCDQUO:
+ open_openclose(KC_DQUO, KC_DQUO, record);
+ break;
+
+ case BP_OCDQUO:
+ open_openclose(BP_DQUO, BP_DQUO, record);
+ break;
+
+ case KC_OCQUOT:
+ open_openclose(KC_QUOT, KC_QUOT, record);
+ break;
+
+ case BP_OCQUOT:
+ open_openclose(BP_QUOT, BP_QUOT, record);
+ break;
+
+ case KC_OCGRV:
+ open_openclose(KC_GRAVE, KC_GRAVE, record);
+ break;
+
+ case BP_OCGRV:
+ open_openclose(BP_GRV, BP_GRV, record);
+ break;
+
+ case KC_OCLTGT:
+ open_openclose(KC_LT, KC_GT, record);
+ break;
+
+ case BP_OCLTGT:
+ open_openclose(BP_LDAQ, BP_RDAQ, record);
+ break;
+
+
+ //Turn shift backspace into delete.
+ /* case KC_BSPC: */
+ /* { */
+ /* // Initialize a boolean variable that keeps track */
+ /* // of the delete key status: registered or not? */
+ /* static bool delkey_registered; */
+ /* if (record->event.pressed) { */
+ /* uint8_t mod_state = get_mods(); */
+ /* // Detect the activation of either shift keys */
+ /* if (mod_state & MOD_MASK_SHIFT) { */
+ /* // First temporarily canceling both shifts so that */
+ /* // shift isn't applied to the KC_DEL keycode */
+ /* del_mods(MOD_MASK_SHIFT); */
+ /* register_code(KC_DEL); */
+ /* // Update the boolean variable to reflect the status of KC_DEL */
+ /* delkey_registered = true; */
+ /* // Reapplying modifier state so that the held shift key(s) */
+ /* // still work even after having tapped the Backspace/Delete key. */
+ /* set_mods(mod_state); */
+ /* return false; */
+ /* } */
+ /* } else { // on release of KC_BSPC */
+ /* // In case KC_DEL is still being sent even after the release of KC_BSPC */
+ /* if (delkey_registered) { */
+ /* unregister_code(KC_DEL); */
+ /* delkey_registered = false; */
+ /* return false; */
+ /* } */
+ /* } */
+ /* // Let QMK process the KC_BSPC keycode as usual outside of shift */
+ /* return true; */
+ /* } */
+
+
+#ifdef UNICODE_ENABLE
+ case UC_FLIP: // (ノಠ痊ಠ)ノ彡┻━┻
+ if (record->event.pressed) {
+ send_unicode_string("(ノಠ痊ಠ)ノ彡┻━┻");
+ }
+ break;
+ case UC_TABL: // ┬─┬ノ( º _ ºノ)
+ if (record->event.pressed) {
+ send_unicode_string("┬─┬ノ( º _ ºノ)");
+ }
+ break;
+ case UC_SHRG: // ¯\_(ツ)_/¯
+ if (record->event.pressed) {
+ send_unicode_string("¯\\_(ツ)_/¯");
+ }
+ break;
+ case UC_DISA: // ಠ_ಠ
+ if (record->event.pressed) {
+ send_unicode_string("ಠ_ಠ");
+ }
+ break;
+#endif
+ }
+ }
+ return true;
+}
diff --git a/users/ericgebhart/readme.md b/users/ericgebhart/readme.md
index cd57735c2c..4a081bd344 100644..100755
--- a/users/ericgebhart/readme.md
+++ b/users/ericgebhart/readme.md
@@ -1,124 +1,212 @@
Overview
========
-This is my personal userspace. Most of my code exists here. I only have one keymap, and that
-is for an ergodox_ez. There are a lot of layers, 7 of them are default layers. I primarily use
-dvorak and Bepo. I've been using emacs in vi mode for over 23 years. I also us Xmonad as my
-window manager, additionally I've been using a Kinesis advantage keyboard in dvorak for over 20
-years. All of those things tend to color the layouts I have.
-
-The Bepo layer needs some love. It is true to the layout at Bepo.fr, but I find it a little
-cumbersome, and I miss some of my favorite keys.
-
-There are 2 dvorak layers, one for a qwerty OS keyboard, and one for a Bepo OS keyboard.
-There is a symbol/keypad layer for bepo and qwerty. And of course there is a mouse/media layer.
-There are 2 Xmonad layers one for qwerty and one for Bepo. Layer selection happens automatically
-based on your current default layer. I use 2 tap dance keys for layer selection.
-
-There are also Qwerty, Colemak, Workman and Norman layers for qwerty.
-
-
-Keyboard Layout Templates
--------------------------
-
-I borrowed the idea for the keyboard defines and some of the definitions from @drashna.
-I think it is an awesome idea, It makes consistency between layout definitions so much easier.
-@drashna had this to say about it.
-
-
-This borrows from @jola5's "Not quite neo" code. This allows me to maintain blocks of keymaps in the userspace, so that I can modify the userspace, and this is reflected in all of the keyboards that use it, at once.
-
-This makes adding tap/hold mods, or other special keycodes or functions to all keyboards super easy, as it's done to all of them at once.
-
-The caveat here is that the keymap needs a processor/wrapper, as it doesn't like the substitutions. However, this is as simple as just pushing it through a define. For instance:
-
-`#define LAYOUT_ergodox_wrapper(...) LAYOUT_ergodox(__VA_ARGS__)`
-
-Once that's been done and you've switched the keymaps to use the "wrapper", it will read the substitution blocks just fine.
-
-Credit goes to @jola5 for first implementing this awesome idea.
-
-
-Custom Keycodes
----------------
-
-Keycodes are defined in the ericgebhart.h file and need to be included in the keymap.c files, so that they can be used there. The keymap.c file has very little in it, the most important thing to see there are the keys that are at the ends of each row, ie. the 1st and last key on each row is defined there.
-Everything else is in ericgebhart.h.
-
-Layer Indication
-----------------
-
-The ergodox_ez only has 3 leds, layer indication is pretty lame.
-Currently the first led lights up if the default layer is not qwerty. The symbol and media layers get
-the other 2 leds, and all the leds light up if you are on the "layers" layer.
-I hope I can figure out how to make it better, but I just don't see a way with 3 leds and 11 layers.
-
-
-BEPO vs Qwerty Layers
+Warning: dvorak touch typist, that uses qwerty and bepo locales on my
+computer. 40+ years of vi, 30 years of vi in Emacs.
+
+Recent years I have gone minimal, I don't use most of the keys on my ergodox,
+or original edition dactyl. These maps work great on large and small keyboards,
+my preference seems to be 40% split ergo keyboards like the corne.
+
+I think that what is special here is the layouts. I don't worry too
+much about leds, or RGB, although I do like oled. But really its mod_layer.h,
+all the simple layer chunks and definitions, and the ability to apply that
+to any keyboard with minimal effort. The other thing is the example it
+provides for defining keymaps based on different OS locales. I use both
+dvorak on Qwerty, and bepo/dvorak on bepo. That means I must change my
+locale on my OS to match my keyboard which can do qwerty or bepo locales.
+
+It is possible, as I do, to send a keycode invoking xmonad, to execute my
+qwerty - bepo switch on my computer.
+
+Besides using dvorak, another thing that colors my keyboard code is that I
+have used the kinesis
+advantage for for more than 2 decades. I have used the ergodox ez for several years
+as well, so the evolution of my keymaps starts there with space, enter, backspace
+and delete keys on the thumbs.
+
+Layouts
+-----------
+This evolved from the old layout...wrapper code. Calling everything a wrapper seems
+silly. So I took a step back.
+
+Also, with all these layers it was a real pain to apply mods consistently and
+easily. So I changed the way I use keymap macro wrappers and added in my own
+mod layer. The only thing it has is the mods to apply. No more editing keymaps
+to apply mods. I do it once, and it works everywhere I want.
+
+All layouts, almost, boil down to a 3x5 x 2 matrix. Bepo is 3x6. Mostly, I want
+my controls to stay the same. As we have been conditioned, these are the keys on
+the edges, or middle. Not that they can't change but I don't usually change them
+much, except the side edges, - the extra pinky columns.
+the F keys, the columns to the left and right and the row on the bottom.
+Thumb keys if you have them. Even the number row is practically the same.
+
+With that in mind, reducing my layouts to 3x10 or 12 matrices would be great.
+At the same time extracting my mods so they are easy to apply to any matrix.
+So that's what is here.
+
+At the bottom is the LAYOUT, needed by the keeb you have. Then I have my Layouts
+to feed it with my ROWS macros which are my MOD layer. At the end of it all,
+I give a 3x10 or 12 to a layout and I have a complete keyboard definition.
+Creating a new keyboard map is super simple.
+
+ * mod_layer.h is the place for home row mods or any other mods.
+ * layouts.h is where I define a new matrix using the ROW macros when I need one.
+ * core_keys.h - where I define my custom keys. Ya know, the big enum.
+ * altlocal_keys.c - Alternate key/shift keys for emulation on other locales.
+ * core_keysets.h - Base layers; qwerty, dvorak, beakl, colemak, norman, carplax...
+ * edge_keys.h - defines the edges and bottom/thumb keys of a keyboard.
+ * layers.h - defines actual layers for navigation, symbols, keypad, layers, top rows, etc.
+
+Process_records.c
+--------------------
+This is where the keycodes are processed...
+
+Custom keys
+-------------------
+I have a lot of custom keys because of bepo. It is somewhat confusing this interaction
+between a keyboard and the software that receives it.
+
+A lot of my pain is invoked by my desire to have dvorak on bepo. Which works just fine,
+although an english/cyrillic situation may not work so well. Currently I have
+dvorak and beakl on bepo in addition to bepo it's self.
+
+Alternate keycodes for emulating a layout on another locale/language.
+-----------------------------
+Because of wanting dvorak and beakl on bepo there was the necessity to create keys
+from keycodes which were not combined. For this I have a special function that
+takes a keycode and gives a proper shifted character for it. It is only a 2 keycode
+definition, but it does the basic non-shifted and shifted characters as you define them.
+
+Combos/Chords
+----------------------------
+This is recently new to me. I'm using them on my thumb keys which are all LT's.
+the combos allow for layer locking for the Nav layer, and a oneshot for symbols
+among other things.
+
+I followed the simple example at the end of the doc than uses the
+combos.def file to define the combos.
+
+Tap-mods
+-------------------------------------
+I had been using MT on my thumbs for GUI,CTRL,ALT on hold along with
+Escape, Enter, space and backspace, my thumb keys. I then added shift to my home row pinky key.
+I had layer shifts to symbols, numbers, navigation all on the home row of both hands.
+It worked nicely but choppy I think, switching hands for the holder of the layer is
+a little like having no caps lock. It was a lot of work adding them to all my maps.
+This is what prompted my mod_layer. So much easier. No maps to modify.
+
+Then I moved to all home row mods with layers on my thumb keys.
+
+This does allow for more rolls, and I have found chord/rolls simply from having my
+xmonad controls be GUI-some-home-row-key-or-close. When Gui is your index finger,
+everything gets easier.
+
+Somewhere along the way I got a corne, and everything had to be small. and I realized
+that everything really was small. My layers are blending back, with LTs near the
+home row, and all the thumbs. On my dactyl I currently have 8 thumb keys per thumb,
+I don't know what to do with them all. Remembering a time I thought that would be
+awesome.
+
+### tap_taplong and open_openclose
+In process_records.c I have a nice couple of functions,
+tap_taplong(), and open_openclose() for my non MT/LT functionality.
+
+ * I have home row mods for Shift, Ctrl, Alt, and Gui on both hands.
+ * I have a number of LT mods to raise layers nearby. Nav, toprows, symbol, keypad
+ are on both hands on the first and third rows around home row.
+ * Xmonad tap_taplong to pull up desktops or terminals with tap or hold.
+ * C-c/C-v, C-t/C-n, C-w/C-q are all on my Navigation layer as custom keys with tap_taplong.
+ * My thumbs are Enter/space and Esc/backspace which are also Navigation and toprows and symbol layers. They used to be GUI,CTRL,ALT,SFT. but all that's on the home row now.
+ * All of the paired characters on my symbol layer have a hold which closes them, and moves the cursor back between.
+
+### caps word
+Holding both pinkies on home row for double tapping term, is effectively
+right-shift and left-shift, invokes caps-word. The next word will be capitalized.
+It continues until it shouldn't.
+
+BEPO vs Qwerty Locale/language/Layers
---------------------
+Essentially they are different keycode sets. So anything that needs them, causes a layer.
+So there are two symbol layers, two toprows layers, two keypad layers.
+One for Qwerty and one for bepo. The Navigation layer is not affected.
-There are 7 base layers. Dvorak, qwerty, Colemak, Workman, and Norman work on a Qwerty software layer on the OS. Dvorak_on_bepo and Bepo both work on a Bepo software layer on the os.
-Dvorak on qwerty is the default. There is a function in ericgebhart.c which will allow the keyboard
-to persist it's default layer through power down. It is currently commented out.
-
-I don't actually use Qwerty, but it seemed like I should have it,
-@drashna had it along with Colemak, Workman and Norman so I added them
-to my existing dvorak and bepo definitions.
-
-There are two tap dance functions that allow switching the default layers
-and the overlay layers.
+I only have bepo, dvorak and beakl on bepo. There are a bunch for Qwerty.
+I have a ton of basic layers. I'm most interested in beakl at the moment, but I've used Dvorak for more than 20 years. There is also qwerty, colemak, norman, carplax, etc.
-The default layers switch according to the current OS keyboard of the current Default layer.
-Shifting the key, causes the selection to use the other OS keyboard selections. ie,
-if you are on qwerty, you get dvorak, qwerty, colemak, workman and norman. If you shift it you get
-dvorak on bepo and bepo. If you are not on qwerty the unshifted taps get dvorak and bepo on bepo.
+The navigation/mouse layer is not affected by bepo/qwerty, but symbols and numbers are.
+There are bepo versions of everything that needs it.
-The other tap dance for layers is for the symbol, mouse and layers layers. The layers layer is just a
-safety layer, knowing I can get to if I screw something up...
+Navigation Layer
+-----------------------
+I do not use a mouse. I use Xmonad as my window manager, and I have
+practically no use for one. They are necessary however. So I have
+a Navigation layer which is all mouse, arrows, home, end, tab, page
+up, down, 5 mouse buttons and so on.
+This layer is not affected by bepo/qwerty, but symbols and numbers are.
+There are bepo versions of everything that needs it.
+
+Arrow combos work just fine, in emacs I use SFT(arrows) to move between windows.
+To do this; shift is my left pinky home, Nav is right thumb Enter, and one of the four
+home keys of my left hand are the arrows. Home row mods allow this to work well.
+
+I don't use the arrows on the dactyl and kinesis, even though they are there.
+
+Symbol Layer
+-------------------
+The symbol layer is based on the Beakl15 symbol layer.
+The beakl symbol layer is intuitive and fairly easy to remember. There are 3 versions.
+The original, an extended called A, and an extended and enhanced for vi, called B.
+The primary purpose of the extension was to provide keys which might not be available
+elsewhere on the default layer. B, takes this further and moves :/? to better places.
+
+TopRows Layer
+--------------------
+I think, truly this is the layer that makes tiny keyboards accessible in the beginning.
+This is basically the number row, the shifted number row and the function key row.
+I have them so it is numbers on the home row, shifted keys above and functions below.
+There are multiple choices, I currently use the beakl number row, with everything
+else as you would expect.
+
+Keypad Layer
+--------------
+There are several variations of keypads and function key pads in various sizes.
+Currently I am using a Beakl Keypad on the left hand and 3x4 funcpad on the right.
+
+OLED
+--------------------
+It shows the basic stuff I could find in most places. The
+default layer, the current layer, the mods, the locks, the last key pressed, and
+a map of the current layer as simply as possible. I'm sure there is more that could
+be done. @Drashna has some fancy stuff. If the display is big enough, there is even
+a display of the current layer's keymap.
XMonad
---------------------
+I use xmonad. Gui is my hot key for that. With home row mods I have home
+row chords which give me access to my desktops, my scratchpads/terminals,
+custom key KC_XM_PORD, among others. It sometimes feels that I am playing
+an instrument when I invoke xmonad to do something.
+
+I had an xmonad layer at one time, it was basically dvorak, I would invoke it
+with a GUI mod, so that even on bepo, or colemak, my xmonad commands remain the same.
-Additionally there is an advanced tap dance called XMONAD_ESC. One tap is Escape, tap and hold is
-LGUI with the proper XMONAD layer, it is essentially dvorak, for the
-given OS layer. 2 taps is Shift lgui with xmonad, and 2 taps and hold
-is Control LGUI with Xmonad. This allows for the finger patterns for
-Xmonad to remain the same regarless of the keyboard in use. The hold
-versions allow for secondary menu selection in Xmonad, the 2 tap function
-must be for a key that is in the top level keymap of Xmonad. This is how
-many people use xmonad so it's not a real problem. There are plenty of
-keys combinations to choose from with these choices. The function can
-be expanded to 3 taps and 3 tap and hold, and on and on....
+I'm going to need to revisit that, as things are, all the commands move when I change
+to a different default layer from dvorak.
-I have a few other special keys, for momentary symbols or shift on the home row of each hand.
+Combo's can alleviate some of this pain. More to play with.
-Also, after using a kinesis for many years I'm very accustomed to the
-space, enter, backspace and delete keys on the thumbs. I've added control
-and alt as a secondary function. These are also the Control and Alt keys
-if held down.
Tap Dance
--------------------
-
-Additionally there are other tap dance functions, tab-backtab, home-end as well as I few I'm not actually using.
-
-Building and flashing
------------------------
-
-```make ergodox_z:ericgebhart``` will compile the code.
-
-I use the teensy-loader cli so that's all I know. There is a script here called flash_ergodox
-
-Use it like this,
-
-```flash-ergodox <path to your hex file>```
-
-then use a paperclip to push the reset button on your keyboard.
+I have a lot of tap dance, It's turned off. It's big. tap-hold works pretty well most of the time, instead.
+My favorites were tab-backtab, home-end.
Switching the OS keyboard
-------------------------
-
This varies from system to system. I use Arch Linux, so I use ```setxkbmap```.
I've included a helper script which makes it easy to switch between EN and FR Bepo,
-called switch-kbd.
+called switch-kbd. In xmonad I invoke this with a keystroke. so, same deal. just map
+the keystroke to a key.
diff --git a/users/ericgebhart/rules.mk b/users/ericgebhart/rules.mk
index 698f6131ed..8afaeb7808 100755
--- a/users/ericgebhart/rules.mk
+++ b/users/ericgebhart/rules.mk
@@ -1,14 +1,34 @@
SRC += ericgebhart.c
+SRC += tap_dances.c
+SRC += process_records.c
+SRC += caps_word.c
+SRC += altlocal_keys.c
+
+VPATH += keyboards/gboards
+
+OLED_ENABLE = yes
+
+ifeq ($(strip $(OLED_ENABLE)), yes)
+ SRC += $(USER_PATH)/oled_stuff.c
+endif
+
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
COMMAND_ENABLE = no # Commands for debug and configuration
-NKRO_ENABLE = no # USB Nkey Rollover - for issues, see github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
+NKRO_ENABLE = no # Enable N-Key Rollover
SWAP_HANDS_ENABLE= no # Allow swapping hands of keyboard
-KEY_LOCK_ENABLE = yes # Enable the KC_LOCK key
-TAP_DANCE_ENABLE = yes # Enable the tap dance feature.
+KEY_LOCK_ENABLE = no # Enable the KC_LOCK key
+TAP_DANCE_ENABLE = no # Enable the tap dance feature.
CONSOLE_ENABLE = no # Console for debug
-BOOTMAGIC_ENABLE = no # Enable Bootmagic Lite
+BOOTMAGIC_ENABLE = no # Enable Bootmagic Lite
UNICODE_ENABLE = no
SLEEP_LED_ENABLE = no
+
+LTO_ENABLE = yes
+
+SPACE_CADET_ENABLE = no
+GRAVE_ESC_ENABLE = no
+MAGIC_ENABLE = no
+COMBO_ENABLE = yes
diff --git a/users/ericgebhart/tap_dances.c b/users/ericgebhart/tap_dances.c
new file mode 100755
index 0000000000..9f344986aa
--- /dev/null
+++ b/users/ericgebhart/tap_dances.c
@@ -0,0 +1,269 @@
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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/>.
+*/
+#ifdef TAP_DANCES_ENABLE
+
+#include "tap_dances.h"
+
+#include "action.h"
+#include "action_layer.h"
+#include "process_keycode/process_tap_dance.h"
+
+void tap_dance_mouse_btns (qk_tap_dance_state_t *state, void *user_data) {
+ switch(state->count){
+ case 1:
+ register_code(KC_BTN1);
+ break;
+ case 2:
+ register_code(KC_BTN2);
+ break;
+ case 3:
+ register_code(KC_BTN3);
+ break;
+ case 4:
+ register_code(KC_BTN4);
+ break;
+ case 5:
+ register_code(KC_BTN5);
+ break;
+ default:
+ break;
+ }
+ reset_tap_dance(state);
+}
+
+// counting on all the qwerty layers to be less than dvorak_on_bepo
+int on_qwerty(){
+ uint8_t deflayer = (biton32(default_layer_state));
+ return (deflayer < _DVORAK_BP);
+}
+
+static void switch_default_layer(uint8_t layer) {
+ default_layer_set(1UL<<layer);
+ clear_keyboard();
+}
+
+// so the keyboard remembers which layer it's in after power disconnect.
+/*
+ uint32_t default_layer_state_set_kb(uint32_t state) {
+ eeconfig_update_default_layer(state);
+ return state;
+ }
+*/
+
+void tap_dance_df_bepo_layers_switch (qk_tap_dance_state_t *state, void *user_data) {
+ switch(state->count){
+ case 1:
+ switch_default_layer(_DVORAK_BP);
+ break;
+ case 2:
+ switch_default_layer(_BEPO);
+ break;
+ case 3:
+ layer_invert(_LAYERS);
+ break;
+ default:
+ break;
+ }
+ reset_tap_dance(state);
+}
+
+void tap_dance_layer_switch (qk_tap_dance_state_t *state, void *user_data) {
+ switch(state->count){
+ case 1:
+ if(on_qwerty())
+ layer_invert(_SYMB);
+ else
+ layer_invert(_SYMB_BP);
+ break;
+ case 2:
+ layer_invert(_NAV);
+ break;
+ case 3:
+ layer_invert(_LAYERS);
+ break;
+ case 4:
+ if(on_qwerty())
+ layer_invert(_KEYPAD);
+ else
+ layer_invert(_KEYPAD_BP);
+ break;
+ default:
+ break;
+ }
+ reset_tap_dance(state);
+}
+
+void tap_dance_default_layer_switch (qk_tap_dance_state_t *state, void *user_data) {
+ switch(state->count){
+ case 1:
+ switch_default_layer(_DVORAK);
+ break;
+ case 2:
+ switch_default_layer(_DVORAK_BP);
+ break;
+ case 3:
+ switch_default_layer(_BEPO);
+ break;
+ default:
+ break;
+ }
+ reset_tap_dance(state);
+}
+
+// switch the default layer to another qwerty based layer.
+void switch_default_layer_on_qwerty(int count) {
+ switch(count){
+ case 1:
+ switch_default_layer(_DVORAK);
+ break;
+ case 2:
+ switch_default_layer(_QWERTY);
+ break;
+ case 3:
+ switch_default_layer(_COLEMAK);
+ break;
+
+ /* case 4: */
+ /* switch_default_layer(_WORKMAN); */
+ /* break; */
+ /* case 5: */
+ /* switch_default_layer(_NORMAN); */
+ /* break; */
+
+ default:
+ switch_default_layer(_DVORAK);
+ break;
+ }
+}
+
+// switch the default layer to another bepo based layer.
+void switch_default_layer_on_bepo(int count) {
+ switch(count){
+ case 1:
+ switch_default_layer(_DVORAK_BP);
+ break;
+ case 2:
+ switch_default_layer(_BEPO);
+ break;
+ default:
+ switch_default_layer(_DVORAK_BP);
+ break;
+ }
+}
+
+
+// tap to change the default layer. Distinguishes between layers that are based on
+// a qwerty software keyboard and a bepo software keyboard.
+// if shifted, choose layers based on the other software keyboard, otherwise choose only
+// layers that work on the current software keyboard.
+void tap_dance_default_os_layer_switch (qk_tap_dance_state_t *state, void *user_data) {
+ //uint8_t shifted = (get_mods() & MOD_BIT(KC_LSFT|KC_RSFT));
+ bool shifted = ( keyboard_report->mods & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)) );
+ int qwerty = on_qwerty();
+
+
+ // shifted, choose between layers on the other software keyboard
+ if(shifted){
+ if (qwerty)
+ switch_default_layer_on_bepo(state->count);
+ else
+ switch_default_layer_on_qwerty(state->count);
+
+ // not shifted, choose between layers on the same software keyboard
+ } else {
+ if (qwerty)
+ switch_default_layer_on_qwerty(state->count);
+ else
+ switch_default_layer_on_bepo(state->count);
+ }
+
+ reset_tap_dance(state);
+}
+
+
+/* Return an integer that corresponds to what kind of tap dance should be executed.
+ *
+ * How to figure out tap dance state: interrupted and pressed.
+ *
+ * Interrupted: If the state of a dance dance is "interrupted", that means that another key has been hit
+ * under the tapping term. This is typically indicitive that you are trying to "tap" the key.
+ *
+ * Pressed: Whether or not the key is still being pressed. If this value is true, that means the tapping term
+ * has ended, but the key is still being pressed down. This generally means the key is being "held".
+ *
+ * One thing that is currenlty not possible with qmk software in regards to tap dance is to mimic the "permissive hold"
+ * feature. In general, advanced tap dances do not work well if they are used with commonly typed letters.
+ * For example "A". Tap dances are best used on non-letter keys that are not hit while typing letters.
+ *
+ * Good places to put an advanced tap dance:
+ * z,q,x,j,k,v,b, any function key, home/end, comma, semi-colon
+ *
+ * Criteria for "good placement" of a tap dance key:
+ * Not a key that is hit frequently in a sentence
+ * Not a key that is used frequently to double tap, for example 'tab' is often double tapped in a terminal, or
+ * in a web form. So 'tab' would be a poor choice for a tap dance.
+ * Letters used in common words as a double. For example 'p' in 'pepper'. If a tap dance function existed on the
+ * letter 'p', the word 'pepper' would be quite frustating to type.
+ *
+ * For the third point, there does exist the 'DOUBLE_SINGLE_TAP', however this is not fully tested
+ *
+ */
+int cur_dance (qk_tap_dance_state_t *state) {
+ if (state->count == 1) {
+ if (state->interrupted || !state->pressed) return SINGLE_TAP;
+ //key has not been interrupted, but they key is still held. Means you want to send a 'HOLD'.
+ else return SINGLE_HOLD;
+ }
+ else if (state->count == 2) {
+ /*
+ * DOUBLE_SINGLE_TAP is to distinguish between typing "pepper", and actually wanting a double tap
+ * action when hitting 'pp'. Suggested use case for this return value is when you want to send two
+ * keystrokes of the key, and not the 'double tap' action/macro.
+ */
+ if (state->interrupted) return DOUBLE_SINGLE_TAP;
+ else if (state->pressed) return DOUBLE_HOLD;
+ else return DOUBLE_TAP;
+ }
+ //Assumes no one is trying to type the same letter three times (at least not quickly).
+ //If your tap dance key is 'KC_W', and you want to type "www." quickly - then you will need to add
+ //an exception here to return a 'TRIPLE_SINGLE_TAP', and define that enum just like 'DOUBLE_SINGLE_TAP'
+ if (state->count == 3) {
+ if (state->interrupted || !state->pressed) return TRIPLE_TAP;
+ else return TRIPLE_HOLD;
+ }
+ else return 8; //magic number. At some point this method will expand to work for more presses
+}
+
+//Tap Dance Definitions
+qk_tap_dance_action_t tap_dance_actions[] = {
+ //Tap once for Esc, twice for Caps Lock
+ [TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS),
+ [TD_TAB_BKTAB] = ACTION_TAP_DANCE_DOUBLE(KC_TAB, LSFT(KC_TAB)),
+ [TD_RIGHT_TAB] = ACTION_TAP_DANCE_DOUBLE(KC_RIGHT, KC_TAB),
+ [TD_LEFT_BACKTAB] = ACTION_TAP_DANCE_DOUBLE(KC_LEFT, LSFT(KC_TAB)),
+ [TD_UP_HOME] = ACTION_TAP_DANCE_DOUBLE(KC_UP, KC_HOME),
+ [TD_DOWN_END] = ACTION_TAP_DANCE_DOUBLE(KC_DOWN, KC_END),
+ [TD_MDIA_SYMB] = ACTION_TAP_DANCE_FN(tap_dance_layer_switch),
+ [TD_DVORAK_BEPO] = ACTION_TAP_DANCE_FN(tap_dance_df_bepo_layers_switch),
+ [TD_DEF_LAYER_SW] = ACTION_TAP_DANCE_FN(tap_dance_default_layer_switch),
+ [TD_DEF_OS_LAYER_SW] = ACTION_TAP_DANCE_FN(tap_dance_default_os_layer_switch),
+ [TD_HOME_END] = ACTION_TAP_DANCE_DOUBLE(KC_HOME, KC_END),
+ [TD_MOUSE_BTNS] = ACTION_TAP_DANCE_FN(tap_dance_mouse_btns)
+
+};
+
+#endif
diff --git a/users/ericgebhart/tap_dances.h b/users/ericgebhart/tap_dances.h
new file mode 100755
index 0000000000..11978467a7
--- /dev/null
+++ b/users/ericgebhart/tap_dances.h
@@ -0,0 +1,19 @@
+#pragma once
+/*
+ Copyright 2018 Eric Gebhart <e.a.gebhart@gmail.com>
+
+ 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 "ericgebhart.h"
diff --git a/users/jonavin/config.h b/users/jonavin/config.h
index 7b6e335e3c..d694bc5371 100644
--- a/users/jonavin/config.h
+++ b/users/jonavin/config.h
@@ -26,6 +26,9 @@
#define TAPPING_TERM_PER_KEY
#ifdef RGB_MATRIX_ENABLE
+ #ifdef RGB_MATRIX_STARTUP_MODE
+ #undef RGB_MATRIX_STARTUP_MODE
+ #endif
#define RGB_MATRIX_STARTUP_MODE RGB_MATRIX_SOLID_COLOR
-# define RGB_DISABLE_WHEN_USB_SUSPENDED
+ #define RGB_DISABLE_WHEN_USB_SUSPENDED
#endif
diff --git a/users/jonavin/readme.md b/users/jonavin/readme.md
index 8ec0e0ea16..204032ae1a 100644
--- a/users/jonavin/readme.md
+++ b/users/jonavin/readme.md
@@ -119,6 +119,6 @@ LIST OF COMPATIBLE KEYMAPS
- mechwild/mercutio
- mechwild/murphpad
- mechwild/OBE
-- nopunin10did/kastenwagen (*)
+- kbdfans/kdb67
+- nopunin10did/kastenwagen48
- (*) coming soon
diff --git a/users/mnil/mnil.c b/users/mnil/mnil.c
index 11d5ee28df..d5bd0ef0bb 100644
--- a/users/mnil/mnil.c
+++ b/users/mnil/mnil.c
@@ -86,7 +86,7 @@ void ae_finished(qk_tap_dance_state_t *state, void *user_data) {
register_code(KC_A);
break;
case SINGLE_HOLD:
- tap_code(SE_AE);
+ tap_code(SE_ADIA);
break;
case DOUBLE_SINGLE_TAP:
tap_code(KC_A);
@@ -113,15 +113,15 @@ void aa_finished(qk_tap_dance_state_t *state, void *user_data) {
aa_tap_state.state = cur_dance(state);
switch (aa_tap_state.state) {
case SINGLE_TAP:
- register_code(SE_OSLH);
+ register_code(SE_ODIA);
break;
case SINGLE_HOLD:
- register_code(SE_AA);
- unregister_code(SE_AA);
+ register_code(SE_ARNG);
+ unregister_code(SE_ARNG);
break;
case DOUBLE_SINGLE_TAP:
- tap_code(SE_OSLH);
- register_code(SE_OSLH);
+ tap_code(SE_ODIA);
+ register_code(SE_ODIA);
break;
}
}
@@ -129,10 +129,10 @@ void aa_finished(qk_tap_dance_state_t *state, void *user_data) {
void aa_reset(qk_tap_dance_state_t *state, void *user_data) {
switch (aa_tap_state.state) {
case SINGLE_TAP:
- unregister_code(SE_OSLH);
+ unregister_code(SE_ODIA);
break;
case DOUBLE_SINGLE_TAP:
- unregister_code(SE_OSLH);
+ unregister_code(SE_ODIA);
break;
}
aa_tap_state.state = 0;
diff --git a/users/noroadsleft/noroadsleft.c b/users/noroadsleft/noroadsleft.c
index 82b0b0568f..28bfa9e6c6 100644
--- a/users/noroadsleft/noroadsleft.c
+++ b/users/noroadsleft/noroadsleft.c
@@ -17,11 +17,6 @@
#include "noroadsleft.h"
#include "version.h"
-/*******************
-** MODIFIER MASKS **
-*******************/
-bool macroMode = 0;
-
__attribute__((weak))
bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; };
@@ -73,60 +68,35 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
return false;
case M_SALL:
if (record->event.pressed) {
- if ( macroMode == 1 ) {
- SEND_STRING(SS_LGUI("a"));
- } else {
- SEND_STRING(SS_LCTL("a"));
- }
+ tap_code16(C(KC_A));
}
return false;
case M_UNDO:
if (record->event.pressed) {
- if ( macroMode == 1 ) {
- if ( get_mods() & MOD_MASK_SHIFT ) {
- SEND_STRING(SS_LSFT(SS_LGUI("z")));
- } else {
- SEND_STRING(SS_LGUI("z"));
- }
- } else {
- SEND_STRING(SS_LCTL("z"));
- }
+ register_code(KC_LCTL);
+ register_code(KC_Z);
+ } else {
+ unregister_code(KC_Z);
+ unregister_code(KC_LCTL);
}
return false;
case M_CUT:
if (record->event.pressed) {
- if ( macroMode == 1 ) {
- SEND_STRING(SS_LGUI("x"));
- } else {
- SEND_STRING(SS_LCTL("x"));
- }
+ tap_code16(C(KC_X));
}
return false;
case M_COPY:
if (record->event.pressed) {
- if ( macroMode == 1 ) {
- SEND_STRING(SS_LGUI("c"));
- } else {
- SEND_STRING(SS_LCTL("c"));
- }
+ tap_code16(C(KC_C));
}
return false;
case M_PASTE:
if (record->event.pressed) {
- if ( macroMode == 1 ) {
- if ( get_mods() & MOD_MASK_SHIFT ) {
- SEND_STRING(SS_LSFT(SS_LALT(SS_LGUI("v"))));
- } else {
- SEND_STRING(SS_LGUI("v"));
- }
- } else {
- SEND_STRING(SS_LCTL("v"));
- }
- }
- return false;
- case M_MDSWP:
- if (record->event.pressed) {
- macroMode ^= 1;
+ register_code(KC_LCTL);
+ register_code(KC_V);
+ } else {
+ unregister_code(KC_V);
+ unregister_code(KC_LCTL);
}
return false;
case KC_1 ... KC_0:
@@ -159,33 +129,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
}
return false;
- case KC_PSCR:
- if (record->event.pressed) {
- if ( macroMode == 1 ) {
- tap_code16(G(S(KC_3)));
- } else {
- tap_code(KC_PSCR);
- }
- }
- return false;
- case KC_HOME:
- if (record->event.pressed) {
- if ( macroMode == 1 ) {
- tap_code16(G(KC_LEFT));
- } else {
- tap_code(KC_HOME);
- }
- }
- return false;
- case KC_END:
- if (record->event.pressed) {
- if ( macroMode == 1 ) {
- tap_code16(G(KC_RGHT));
- } else {
- tap_code(KC_END);
- }
- }
- return false;
} // switch()
return true;
};
diff --git a/users/noroadsleft/noroadsleft.h b/users/noroadsleft/noroadsleft.h
index 52bcec0abd..12bb5b465a 100644
--- a/users/noroadsleft/noroadsleft.h
+++ b/users/noroadsleft/noroadsleft.h
@@ -19,7 +19,6 @@
#include QMK_KEYBOARD_H
#define MOD_MASK_RALT (MOD_BIT(KC_RALT))
-extern bool macroMode;
enum userspace_keycodes {
VRSN = SAFE_RANGE,
@@ -31,7 +30,6 @@ enum userspace_keycodes {
M_CUT,
M_COPY,
M_PASTE,
- M_MDSWP,
KEYMAP_SAFE_RANGE
};
diff --git a/users/noroadsleft/readme.md b/users/noroadsleft/readme.md
index 1173d15ec1..e8279c0333 100644
--- a/users/noroadsleft/readme.md
+++ b/users/noroadsleft/readme.md
@@ -13,7 +13,7 @@ This directory holds the code that's the same for every keyboard I use in QMK, w
Outputs a string that tells me the Git commit from which my flashed firmware was built. Looks something like:
- kc60:noroadsleft @ 0.6.326-6-gae6d7b-dirty
+ kc60:noroadsleft # @ 0.6.326-6-gae6d7b-dirty
### Git Macros
@@ -21,40 +21,37 @@ Some frequently used Git commands.
| Keycode | Output | Output with <kbd>Shift</kbd> |
| :---------------------------------- | :--------------------- | :--------------------------- |
-| [`G_PUSH`](./noroadsleft.c#L49-L53) | `git push origin ` | `git push origin ` |
-| [`G_FTCH`](./noroadsleft.c#L54-L63) | `git fetch upstream ` | `git pull upstream ` |
-| [`G_BRCH`](./noroadsleft.c#L64-L73) | `master` | `$(git branch-name)` |
+| [`G_PUSH`](./noroadsleft.c#L44-L48) | `git push origin ` | `git push origin ` |
+| [`G_FTCH`](./noroadsleft.c#L49-L58) | `git fetch upstream ` | `git pull upstream ` |
+| [`G_BRCH`](./noroadsleft.c#L59-L68) | `master` | `$(git branch-name)` |
`$(git branch-name)` is an alias for `git rev-parse --abbrev-ref HEAD`, which normally returns the name of the current branch.
-### "Macro Mode" Macros and Customized Keycodes
+### Customized Keycodes
-Some of my macros and keycodes do different things depending on the value of the [`macroMode` variable](./noroadsleft.c#L23), which is [toggled between `0` and `1`](./noroadsleft.c#L127-L131) by the `M_MDSWP` custom keycode.[<sup>1</sup>](#footnotes) This is mainly at attempt to make various shortcuts use the same physical key combinations between Windows/Linux and MacOS (which I use at home and work, respectively).
+I used to have a boolean variable that changed the functionality of these keycodes, but I no longer work in the environment that I wrote the functionality for, so I took it out. The keycodes still exist because all my `keymap.c` files reference the custom keycodes I defined.
-| Keycode | `macroMode == 0` | `macroMode == 1` | `macroMode == 1` with <kbd>Shift</kbd> |
-| :------------------------------------- | :--------------- | :--------------- | :------------------------------------- |
-| [`M_SALL`](./noroadsleft.c#L74-L82) | `Ctrl+A` | `Cmd+A` | `Cmd+A` |
-| [`M_UNDO`](./noroadsleft.c#L83-L95) | `Ctrl+Z` | `Cmd+Z` | `Cmd+Shift+Z` |
-| [`M_CUT`](./noroadsleft.c#L96-L104) | `Ctrl+X` | `Cmd+X` | `Cmd+X` |
-| [`M_COPY`](./noroadsleft.c#L105-L113) | `Ctrl+C` | `Cmd+C` | `Cmd+C` |
-| [`M_PASTE`](./noroadsleft.c#L114-L126) | `Ctrl+V` | `Cmd+V` | `Cmd+Shift+Opt+V` |
-| [`KC_PSCR`](./noroadsleft.c#L162-L170) | `KC_PSCR` | `Cmd+Shift+3` | `Cmd+Shift+3` |
-| [`KC_HOME`](./noroadsleft.c#L171-L179) | `KC_HOME` | `Cmd+Left` | `Cmd+Left` |
-| [`KC_END`](./noroadsleft.c#L180-L188) | `KC_END` | `Cmd+Right` | `Cmd+Right` |
+| Keycode | Action |
+| :------------------------------------ | :-------- |
+| [`M_SALL`](./noroadsleft.c#L69-L73) | `Ctrl+A` |
+| [`M_UNDO`](./noroadsleft.c#L74-L82) | `Ctrl+Z` |
+| [`M_CUT`](./noroadsleft.c#L83-L87) | `Ctrl+X` |
+| [`M_COPY`](./noroadsleft.c#L88-L92) | `Ctrl+C` |
+| [`M_PASTE`](./noroadsleft.c#L93-L101) | `Ctrl+V` |
-### [Emulated Non-US Backslash](./noroadsleft.c#L32-L42)
+### [Emulated Non-US Backslash](./noroadsleft.c#L27-L37)
Sometimes I type in languages from countries that use ISO layout, but my keyboards are all ANSI layout, so I have one key fewer than necessary.
This macro simulates the Non-US Backslash key if I hold Right Alt and tap the key to the right of Left Shift.
-Requires defining `ANSI_NUBS_ROW` and `ANSI_NUBS_COL` in `config.h` at the keymap level.[<sup>2</sup>](#footnotes)
+Requires defining `ANSI_NUBS_ROW` and `ANSI_NUBS_COL` in `config.h` at the keymap level.[<sup>1</sup>](#footnotes)
-### [Emulated Numeric Keypad](./noroadsleft.c#L132-L146)
+### [Emulated Numeric Keypad](./noroadsleft.c#L102-L116)
If I hold the Right Alt key, the number row (`KC_1` through `KC_0`) will output numpad keycodes instead of number row keycodes, enabling quicker access to characters like ™ and °.
-### [Emulated Extended Function Keys](./noroadsleft.c#L147-L161)
+### [Emulated Extended Function Keys](./noroadsleft.c#L117-L131)
Similar to the emulated numpad, if I hold the Right Alt key with the Fn key, the function row (`KC_F1` through `KC_F12`) will output keycodes `KC_F13` throught `KC_F24`.
@@ -79,11 +76,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
## Footnotes
-- 1: [^](#macro-mode-macros-and-customized-keycodes) The `M_MDSWP` keycode is used in my keymaps in the following locations:
- - [KC60](../../keyboards/kc60/keymaps/noroadsleft/keymap.c#L111)
- - [KBDfans KBD75 rev1](../../keyboards/kbdfans/kbd75/keymaps/noroadsleft/keymap.c#L93)
- - [CoseyFannitutti Discipline](../../keyboards/coseyfannitutti/discipline/keymaps/noroadsleft/keymap.c#L66)
-- 2: [^](#emulated-non-us-backslash) `ANSI_NUBS_ROW` and `ANSI_NUBS_COL` are in the following locations:
+- 1: [^](#emulated-non-us-backslash) `ANSI_NUBS_ROW` and `ANSI_NUBS_COL` are in the following locations:
- [KC60](../../keyboards/kc60/keymaps/noroadsleft/config.h#L35-L36)
- [KBDfans KBD75 rev1](../../keyboards/kbdfans/kbd75/keymaps/noroadsleft/config.h#L26-L27)
- [CoseyFannitutti Discipline](../../keyboards/coseyfannitutti/discipline/keymaps/noroadsleft/config.h#L19-L20)
diff --git a/users/riblee/riblee.c b/users/riblee/riblee.c
index 307c697204..02ba246f60 100644
--- a/users/riblee/riblee.c
+++ b/users/riblee/riblee.c
@@ -18,15 +18,13 @@
#include "raw_hid.h"
#include <string.h>
-const uint8_t shift = MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT);
-
// Tap Dance functions
void dance_key_a (qk_tap_dance_state_t *state, void *user_data) {
if (state->count == 1) {
SEND_STRING("a");
reset_tap_dance(state);
} else if (state->count == 2) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("á");
} else {
send_unicode_string("Á");
@@ -41,7 +39,7 @@ void dance_key_e (qk_tap_dance_state_t *state, void *user_data) {
SEND_STRING("e");
reset_tap_dance(state);
} else if (state->count == 2) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("é");
} else {
send_unicode_string("É");
@@ -56,7 +54,7 @@ void dance_key_i (qk_tap_dance_state_t *state, void *user_data) {
SEND_STRING("i");
reset_tap_dance(state);
} else if (state->count == 2) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("í");
} else {
send_unicode_string("Í");
@@ -71,7 +69,7 @@ void dance_key_o (qk_tap_dance_state_t *state, void *user_data) {
SEND_STRING("o");
reset_tap_dance(state);
} else if (state->count == 2) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("ó");
} else {
send_unicode_string("Ó");
@@ -79,7 +77,7 @@ void dance_key_o (qk_tap_dance_state_t *state, void *user_data) {
reset_tap_dance(state);
} else if (state->count == 3) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("ö");
} else {
send_unicode_string("Ö");
@@ -87,7 +85,7 @@ void dance_key_o (qk_tap_dance_state_t *state, void *user_data) {
reset_tap_dance(state);
} else if (state->count == 4) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("ő");
} else {
send_unicode_string("Ő");
@@ -102,7 +100,7 @@ void dance_key_u (qk_tap_dance_state_t *state, void *user_data) {
SEND_STRING("u");
reset_tap_dance(state);
} else if (state->count == 2) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("ú");
} else {
send_unicode_string("Ú");
@@ -110,7 +108,7 @@ void dance_key_u (qk_tap_dance_state_t *state, void *user_data) {
reset_tap_dance(state);
} else if (state->count == 3) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("ü");
} else {
send_unicode_string("Ü");
@@ -118,7 +116,7 @@ void dance_key_u (qk_tap_dance_state_t *state, void *user_data) {
reset_tap_dance(state);
} else if (state->count == 4) {
- if (!(keyboard_report->mods & shift)) {
+ if (!(keyboard_report->mods & MOD_MASK_SHIFT)) {
send_unicode_string("ű");
} else {
send_unicode_string("Ű");
@@ -164,23 +162,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
return false;
break;
- case BACKLIT:
- if (record->event.pressed) {
- register_code(keycode_config(KC_LGUI));
-#ifdef BACKLIGHT_ENABLE
- backlight_step();
-#endif
- } else {
- unregister_code(keycode_config(KC_LGUI));
- }
- return false;
- break;
- case CG_NORM:
- set_unicode_input_mode(UC_MAC);
- break;
- case CG_SWAP:
- set_unicode_input_mode(UC_LNX);
- break;
}
return true;
};
@@ -287,3 +268,11 @@ void raw_hid_receive(uint8_t *data, uint8_t length) {
#endif
#endif
+
+void keyboard_pre_init_user(void) {
+ // Set C13 pin as output
+ setPinOutput(C13);
+
+ // Turn off the LED
+ writePinHigh(C13);
+} \ No newline at end of file
diff --git a/users/riblee/riblee.h b/users/riblee/riblee.h
index f7340d50b2..786e4c31ab 100644
--- a/users/riblee/riblee.h
+++ b/users/riblee/riblee.h
@@ -35,7 +35,6 @@ enum custom_keycodes {
COLEMAK,
DVORAK,
WORKMAN,
- BACKLIT
};
#define LOWER MO(_LOWER)
diff --git a/users/scheiklp/koy_keys_on_quertz_de_latin1.h b/users/scheiklp/koy_keys_on_quertz_de_latin1.h
index 4f39b7631c..e098e75dfc 100644
--- a/users/scheiklp/koy_keys_on_quertz_de_latin1.h
+++ b/users/scheiklp/koy_keys_on_quertz_de_latin1.h
@@ -61,3 +61,4 @@ Additionally, there are some common chars that we dit not yet define:
#define N_COPY LCTL(KC_C) // CTRL+C
#define N_CUT LCTL(KC_X) // CTRL+X
#define N_UNDO LCTL(N_Z) // CTRL+Z
+#define N_ACUT KC_EQL // ´
diff --git a/users/stanrc85/config.h b/users/stanrc85/config.h
index 60592c3c6b..b883a21dd2 100644
--- a/users/stanrc85/config.h
+++ b/users/stanrc85/config.h
@@ -12,9 +12,15 @@
#ifdef KEYBOARD_sneakbox_aliceclone
#define INDICATOR_PIN_0 D7
#define INDICATOR_PIN_1 D6
- #define INDICATOR_PIN_2 D4
+ #define INDICATOR_PIN_2 D4
#endif
#ifdef KEYBOARD_boardsource_the_mark
#define RGB_MATRIX_KEYPRESSES
-#endif \ No newline at end of file
+#endif
+
+#ifdef KEYBOARD_jacky_studio_bear_65
+ #define ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
+ #define ENABLE_RGB_MATRIX_MULTISPLASH
+ #define ENABLE_RGB_MATRIX_TYPING_HEATMAP
+#endif
diff --git a/users/uqs/config.h b/users/uqs/config.h
new file mode 100644
index 0000000000..b8a140fe87
--- /dev/null
+++ b/users/uqs/config.h
@@ -0,0 +1,40 @@
+// Copyright 2022 Ulrich Spörlein (@uqs)
+// SPDX-License-Identifier: GPL-2.0-or-later
+#pragma once
+
+#ifdef RGBLIGHT_ENABLE
+# define RGBLIGHT_SLEEP
+//# define RGBLIGHT_ANIMATIONS // disabled to save space
+# define RGBLIGHT_LAYERS
+# define RGBLIGHT_MAX_LAYERS 8 // default is 16
+# define RGBLIGHT_DISABLE_KEYCODES // RGB_foo keys no longer work, saves 600 bytes
+# define RGBLIGHT_DEFAULT_HUE 15
+#endif
+
+#define DYNAMIC_KEYMAP_LAYER_COUNT 6 // default is 4 for VIA builds
+
+#define TAPPING_TOGGLE 2 // number of taps for a toggle-on-tap
+#define TAPPING_TERM 170 // ms to trigger tap
+// https://precondition.github.io/home-row-mods
+#define TAPPING_FORCE_HOLD // make tap-then-hold _not_ do key auto repeat
+#define IGNORE_MOD_TAP_INTERRUPT
+#define PERMISSIVE_HOLD // I don't think this works for me, hence I rolled my own implementation.
+
+#define LEADER_TIMEOUT 400
+#define LEADER_PER_KEY_TIMING
+
+#define UNICODE_SELECTED_MODES UC_LNX
+
+// make KC_ACL0 et al work when held.
+#define MK_COMBINED
+#define MOUSEKEY_WHEEL_INTERVAL 40 // default is 50, lower means more scroll events, 40 works ok.
+
+// From https://michael.stapelberg.ch/posts/2021-05-08-keyboard-input-latency-qmk-kinesis/
+#define USB_POLLING_INTERVAL_MS 1
+
+#ifdef KEYBOARD_preonic_rev3
+// Some games seem to not register Esc otherwise when tapped, maybe try with this delay?
+# define TAP_CODE_DELAY 30
+#else
+# define TAP_CODE_DELAY 10
+#endif
diff --git a/users/uqs/rules.mk b/users/uqs/rules.mk
new file mode 100644
index 0000000000..6050362952
--- /dev/null
+++ b/users/uqs/rules.mk
@@ -0,0 +1,24 @@
+# don't include for keyboards/ploopyco/mouse/keymaps/uqs
+ifeq ($(filter $(strip $(KEYBOARD)),ploopyco/mouse),)
+ SRC += uqs.c
+
+ RGBLIGHT_ENABLE ?= yes # Enable keyboard RGB underglow
+ LTO_ENABLE ?= yes # disables the legacy TMK Macros and Functions features
+
+ UCIS_ENABLE = yes
+ LEADER_ENABLE = yes
+ COMBO_ENABLE = yes
+ MOUSEKEY_ENABLE = yes
+
+ # Disable all the unused stuff.
+ SPACE_CADET_ENABLE = no
+ COMMAND_ENABLE = no
+ MAGIC_ENABLE = no
+endif
+
+# From https://michael.stapelberg.ch/posts/2021-05-08-keyboard-input-latency-qmk-kinesis/
+# adds about 900 bytes! Don't use it on puny AVR though.
+# ifeq (,$(filter $(MCU), atmega16u2 atmega32u2 at90usb162)) # doesn't work MCU not set yet
+ifneq (,$(filter $(KEYBOARD),ploopyco/mouse preonic/rev3))
+ DEBOUNCE_TYPE = asym_eager_defer_pk
+endif
diff --git a/users/uqs/uqs.c b/users/uqs/uqs.c
new file mode 100644
index 0000000000..72284143c6
--- /dev/null
+++ b/users/uqs/uqs.c
@@ -0,0 +1,584 @@
+// Copyright 2022 Ulrich Spörlein (@uqs)
+// SPDX-License-Identifier: GPL-2.0-or-later
+// vi:et sw=4:
+
+#include "uqs.h"
+
+// LOG:
+// late Jan 2020, got Ohkeycaps Dactyl Manuform 5x6
+// https://play.typeracer.com shows about 75-80wpm (en) or ~400cpm (de) on my classic keeb.
+// Never did proper touch typing, basically didn't use ring finger much, mostly index/middle and pinky (only to hold down modifiers, really).
+// Feb 2020, switching to Colemak DH after 30 years of Qwerty, uh oh...
+// mid Feb, 20wpm/87% on monkeytype.com (no punct, numbers)
+// early March, 28wpm/90% on MT (plus punct./numbers from here on); 25wpm on typeracer
+// early April, 35wpm/92% on MT; 41wpm on typeracer
+// early May, 45wpm/96% on MT; 46wpm on typeracer; my qwerty is deteriorating, I need to look at the keys more and more o_O
+// early June, 49wpm/95% on MT (sigh ...); 50wpm on typeracer;
+// early July, 50wpm/96% on MT (...); 52wpm/96% on typeracer;
+// early August, 55wpm/96% on MT; 55wpm/98% on typeracer;
+// early September, 57wpm/97% on MT; 58wpm/97% on typeracer;
+// early October, 59wpm/96% on MT; 61wpm/97% on typeracer;
+// November, 56wpm/97% on MT; 62wpm/98% on typeracer;
+// December, 62wpm/96% on MT; 66wpm/98% on typeracer;
+// January, 61wpm/97% on MT; 65wpm/98% on typeracer;
+// February, 64wpm/97% on MT; 67wpm/98% on typeracer; my qwerty on the laptop is still fine, but I miss my shortcuts badly.
+//
+// So that's one year on Colemak. Was it worth the switch? Probably not, though
+// I also had to first learn proper technique, but that was actually swift, as
+// the keyboard nicely forces that on you. I really like home row mods though,
+// they are so comfy. Need to rethink my combos some more, still.
+
+
+#ifdef RGBLIGHT_LAYERS
+layer_state_t default_layer_state_set_user(layer_state_t state) {
+ rgblight_set_layer_state(L_QWER, layer_state_cmp(state, L_QWER));
+ rgblight_set_layer_state(L_WASD, layer_state_cmp(state, L_WASD));
+ rgblight_set_layer_state(L_COLM, layer_state_cmp(state, L_COLM));
+ return state;
+}
+#endif
+
+layer_state_t layer_state_set_user(layer_state_t state) {
+#if 0
+ // defining layer L_FUNC when both keys are pressed
+ state = update_tri_layer_state(state, L_EXTD, L_NUM, L_FUNC);
+#endif
+#ifdef RGBLIGHT_LAYERS
+ rgblight_set_layer_state(L_EXTD, layer_state_cmp(state, L_EXTD));
+ rgblight_set_layer_state(L_NUM, layer_state_cmp(state, L_NUM));
+ rgblight_set_layer_state(L_FUNC, layer_state_cmp(state, L_FUNC));
+ rgblight_set_layer_state(L_MOUSE, layer_state_cmp(state, L_MOUSE));
+#else
+#endif
+ return state;
+}
+
+#ifdef RGBLIGHT_LAYERS
+// NOTE: at most 2 elements, last one needs to be RGBLIGHT_END_SEGMENTS
+typedef rgblight_segment_t rgblight_layer_t[3];
+
+const rgblight_layer_t PROGMEM my_rgb_segments[] = {
+ [L_QWER] = {{0, RGBLED_NUM, HSV_WHITE}, RGBLIGHT_END_SEGMENTS},
+ [L_WASD] = {{0, RGBLED_NUM/2, HSV_RED}, {RGBLED_NUM/2, RGBLED_NUM/2, HSV_OFF}, RGBLIGHT_END_SEGMENTS},
+ [L_COLM] = {{0, RGBLED_NUM, HSV_GREEN}, RGBLIGHT_END_SEGMENTS},
+ [L_EXTD] = {{0, RGBLED_NUM, HSV_BLUE}, RGBLIGHT_END_SEGMENTS},
+ [L_NUM] = {{0, RGBLED_NUM, HSV_ORANGE}, RGBLIGHT_END_SEGMENTS},
+ [L_FUNC] = {{0, RGBLED_NUM, HSV_YELLOW}, RGBLIGHT_END_SEGMENTS},
+ [L_MOUSE]= {{0, RGBLED_NUM, HSV_PURPLE}, RGBLIGHT_END_SEGMENTS},
+};
+
+// This array needs pointers, :/
+const rgblight_segment_t* const PROGMEM my_rgb_layers[] = {
+ my_rgb_segments[L_QWER],
+ my_rgb_segments[L_WASD],
+ my_rgb_segments[L_COLM],
+ my_rgb_segments[L_EXTD],
+ my_rgb_segments[L_NUM],
+ my_rgb_segments[L_FUNC],
+ my_rgb_segments[L_MOUSE],
+};
+
+_Static_assert(sizeof(my_rgb_layers) / sizeof(my_rgb_layers[0]) ==
+ sizeof(my_rgb_segments) / sizeof(my_rgb_segments[0]),
+ "Number of rgb_segment definitions does not match up!");
+#endif
+
+#ifdef COMBO_ENABLE
+enum combo_events {
+ C_AUML,
+ C_OUML,
+ C_UUML,
+ C_SZ,
+ C_CBR,
+ C_PRN,
+ C_BRC,
+};
+
+// Maybe use this?
+// #define COMBO_ONLY_FROM_LAYER L_COLM
+
+// The official way has way too much duplication and intermediate names for my taste...
+const uint16_t PROGMEM my_action_combos[][3] = {
+ [C_AUML] = {KC_G_A, KC_W, COMBO_END},
+ [C_OUML] = {KC_G_O, KC_Y, COMBO_END},
+ [C_UUML] = {KC_C_N, KC_U, COMBO_END},
+ [C_SZ] = {KC_S_S, KC_Z, COMBO_END},
+ [C_CBR] = {KC_COLN, KC_LCBR, COMBO_END},
+ [C_PRN] = {KC_LCBR, KC_LPRN, COMBO_END},
+ [C_BRC] = {KC_LPRN, KC_LBRC, COMBO_END},
+};
+const uint16_t PROGMEM my_combos[][4] = {
+ {KC_LPRN, KC_F, KC_P, COMBO_END},
+ {KC_RPRN, KC_C, KC_D, COMBO_END},
+ {KC_LCBR, KC_W, KC_F, COMBO_END},
+ {KC_RCBR, KC_X, KC_C, COMBO_END},
+ {KC_TAB, KC_G_A, KC_A_R, COMBO_END},
+ {KC_BSLS, KC_B, KC_J, COMBO_END}, // remove this?
+ {KC_BSLS, KC_F, KC_U, COMBO_END},
+ {LSFT(KC_BSLS), KC_P, KC_L, COMBO_END},
+ {KC_MINUS, KC_C_T, KC_C_N, COMBO_END},
+ {LSFT(KC_MINUS), KC_D, KC_H, COMBO_END},
+ {KC_GRV, KC_Q, KC_W, COMBO_END}, // remove this?
+ {KC_GRV, KC_C, KC_COMM, COMBO_END},
+ {LSFT(KC_GRV), KC_G, KC_M, COMBO_END},
+ {KC_BTN3, KC_BTN1, KC_BTN2, COMBO_END},
+ {KC_BTN1, KC_BTN2, KC_BTN3, COMBO_END},
+};
+
+const uint16_t COMBO_LEN = sizeof(my_action_combos) / sizeof(my_action_combos[0]) + sizeof(my_combos) / sizeof(my_combos[0]);
+
+#define MY_ACTION_COMBO(ck) \
+ [ck] = { .keys = &(my_action_combos[ck][0]) }
+#define MY_COMBO(ck) \
+ { .keys = &(my_combos[ck][1]), .keycode = my_combos[ck][0] }
+
+// NOTE: while my_combos can live in PROGMEM, the key_combos data also
+// contains state that is tweaked at runtime, so we need to indirect. Ugh.
+#define COMBO_STATICALLY
+#ifdef COMBO_STATICALLY
+// TODO: fill this at runtime with a loop?
+combo_t key_combos[] = {
+ MY_ACTION_COMBO(0),
+ MY_ACTION_COMBO(1),
+ MY_ACTION_COMBO(2),
+ MY_ACTION_COMBO(3),
+ MY_ACTION_COMBO(4),
+ MY_ACTION_COMBO(5),
+ MY_ACTION_COMBO(6),
+ MY_COMBO(0),
+ MY_COMBO(1),
+ MY_COMBO(2),
+ MY_COMBO(3),
+ MY_COMBO(4),
+ MY_COMBO(5),
+ MY_COMBO(6),
+ MY_COMBO(7),
+ MY_COMBO(8),
+ MY_COMBO(9),
+ MY_COMBO(10),
+ MY_COMBO(11),
+ MY_COMBO(12),
+ MY_COMBO(13),
+ MY_COMBO(14),
+};
+
+_Static_assert(sizeof(key_combos) / sizeof(key_combos[0]) ==
+ (sizeof(my_action_combos) / sizeof(my_action_combos[0]) + sizeof(my_combos) / sizeof(my_combos[0])),
+ "Number of combo definitions does not match up!");
+#else
+combo_t key_combos[sizeof(my_action_combos) / sizeof(my_action_combos[0]) + sizeof(my_combos) / sizeof(my_combos[0])];
+#endif
+
+void process_combo_event(uint16_t combo_index, bool pressed) {
+ switch (combo_index) {
+ case C_AUML:
+ if (pressed) {
+ tap_code16(KC_RALT);
+ tap_code16(LSFT(KC_QUOT));
+ tap_code16(KC_A);
+ }
+ break;
+ case C_OUML:
+ if (pressed) {
+ tap_code16(KC_RALT);
+ tap_code16(LSFT(KC_QUOT));
+ tap_code16(KC_O);
+ }
+ break;
+ case C_UUML:
+ if (pressed) {
+ tap_code16(KC_RALT);
+ tap_code16(LSFT(KC_QUOT));
+ tap_code16(KC_U);
+ }
+ break;
+ case C_SZ:
+ if (pressed) {
+ tap_code16(KC_RALT);
+ tap_code16(KC_S);
+ tap_code16(KC_S);
+ }
+ break;
+ case C_CBR:
+ if (pressed) {
+ tap_code16(KC_LCBR);
+ tap_code16(KC_RCBR);
+ tap_code16(KC_LEFT);
+ }
+ break;
+ case C_PRN:
+ if (pressed) {
+ tap_code16(KC_LPRN);
+ tap_code16(KC_RPRN);
+ tap_code16(KC_LEFT);
+ }
+ break;
+ case C_BRC:
+ if (pressed) {
+ tap_code16(KC_LBRC);
+ tap_code16(KC_RBRC);
+ tap_code16(KC_LEFT);
+ }
+ break;
+ }
+}
+#endif
+
+void keyboard_post_init_user(void) {
+#ifndef KEYBOARD_preonic_rev3
+ default_layer_set(1ul << L_COLM);
+#endif
+#ifdef RGBLIGHT_LAYERS
+ // Enable the LED layers
+ rgblight_layers = my_rgb_layers;
+ rgblight_set_layer_state(0, true);
+#endif
+#if defined(COMBO_ENABLE) && !defined(COMBO_STATICALLY)
+ uint8_t i = 0;
+ for (; i < sizeof(my_action_combos) / sizeof(my_action_combos[0]); i++) {
+ key_combos[i].keys = &(my_action_combos[i][0]);
+ }
+ for (uint8_t j = 0; j < sizeof(my_combos) / sizeof(my_combos[0]); j++, i++) {
+ key_combos[i].keycode = my_combos[j][0];
+ key_combos[i].keys = &(my_combos[j][1]);
+ }
+#endif
+}
+
+uint16_t key_timer;
+bool delkey_registered;
+bool num_layer_was_used;
+bool extd_layer_was_used;
+// These keep state about the long-press-means-umlaut keys.
+bool auml_pressed;
+bool ouml_pressed;
+bool uuml_pressed;
+
+void maybe_send_umlaut(uint16_t keycode, bool *is_pressed) {
+ // Some other key did _not_ already re-arm this key, so now we need to do
+ // that ourselves.
+ if (*is_pressed) {
+ *is_pressed = false;
+ // If released within the timer, then just KC_A, KC_O, KC_U
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ tap_code16(keycode);
+ } else {
+ tap_code16(KC_RALT);
+ tap_code16(LSFT(KC_QUOT));
+ tap_code16(keycode);
+ }
+ }
+}
+
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+ // TODO: why not use key_timer here? is it dynamic or not?
+ static uint16_t extd_layer_timer;
+ if (layer_state_is(L_EXTD) && record->event.pressed) {
+ extd_layer_was_used = true;
+ }
+ if (layer_state_is(L_NUM) && record->event.pressed) {
+ num_layer_was_used = true;
+ }
+
+ // An umlaut key was pressed previously (but will only emit the key on
+ // release), but we've pressed a different key now, so fire the regular key,
+ // re-arm it and continue with whatever actual key was pressed just now.
+ if (record->event.pressed) {
+ if (auml_pressed) {
+ tap_code16(KC_A);
+ auml_pressed = false;
+ }
+ if (ouml_pressed) {
+ tap_code16(KC_O);
+ ouml_pressed = false;
+ }
+ if (uuml_pressed) {
+ tap_code16(KC_U);
+ uuml_pressed = false;
+ }
+ }
+
+ switch (keycode) {
+ // From https://github.com/qmk/qmk_firmware/issues/6053
+ case LT_EXTD_ESC:
+ if (record->event.pressed) {
+ extd_layer_was_used = false;
+ extd_layer_timer = timer_read();
+ layer_on(L_EXTD);
+ } else {
+ layer_off(L_EXTD);
+ unregister_mods(MOD_BIT(KC_LALT)); // undo what ALT_TAB might've set
+ // NOTE: need to track whether we made use of the extd layer and
+ // that all happened within the tapping term. Otherwise we'd emit
+ // that layer key code _plus_ an extra Esc.
+ if (timer_elapsed(extd_layer_timer) < TAPPING_TERM && !extd_layer_was_used) {
+ tap_code(KC_ESC);
+ }
+ }
+ return true;
+ case LT_NUM_BSPC:
+ if (record->event.pressed){
+ num_layer_was_used = false;
+ extd_layer_timer = timer_read();
+ layer_on(L_NUM);
+ } else {
+ layer_off(L_NUM);
+ // NOTE: Custom LT method so that any press of a key on that layer will prevent the backspace.
+ if (timer_elapsed(extd_layer_timer) < TAPPING_TERM && !num_layer_was_used) {
+ tap_code(KC_BSPC);
+ }
+ }
+ return true;
+ case LT_MOUSE_ALT_SHIFT_INS:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ layer_on(L_MOUSE);
+ } else {
+ layer_off(L_MOUSE);
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ tap_code16(LALT(LSFT(KC_INS)));
+ }
+ }
+ return true;
+ case LT_FUNC_SHIFT_INS:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ layer_on(L_FUNC);
+ } else {
+ layer_off(L_FUNC);
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ tap_code16(LSFT(KC_INS));
+ }
+ }
+ return true;
+#if 1
+ /* Looks like PERMISSIVE_HOLD on LT and OSM doesn't work properly. This
+ * is probaby https://github.com/qmk/qmk_firmware/issues/8971
+ */
+ case OSM_GUI:
+ /* OSM(MOD_LGUI) is delaying the event, but I need immediate triggering
+ * of the modifier to move windows around with the mouse. If only
+ * tapped, however, have it be a win OSM */
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ register_mods(MOD_BIT(KC_LGUI));
+ } else {
+ unregister_mods(MOD_BIT(KC_LGUI));
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ add_oneshot_mods(MOD_BIT(KC_LGUI));
+ } else {
+ del_oneshot_mods(MOD_BIT(KC_LGUI));
+ }
+ }
+ return true;
+ // Why do I have to roll my own? It seems the original ones work on
+ // keyrelease, at which time I might have let go of the layer tap
+ // already, so I cannot roll them fast...
+ case OSM_SFT:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ register_mods(MOD_BIT(KC_LSFT));
+ } else {
+ unregister_mods(MOD_BIT(KC_LSFT));
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ add_oneshot_mods(MOD_BIT(KC_LSFT));
+ } /*else {
+ del_oneshot_mods(MOD_BIT(KC_LSFT));
+ }*/
+ }
+ return true;
+ case OSM_CTL:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ register_mods(MOD_BIT(KC_LCTL));
+ } else {
+ unregister_mods(MOD_BIT(KC_LCTL));
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ add_oneshot_mods(MOD_BIT(KC_LCTL));
+ } /*else {
+ del_oneshot_mods(MOD_BIT(KC_LCTL));
+ }*/
+ }
+ return true;
+ case OSM_ALT:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ register_mods(MOD_BIT(KC_LALT));
+ } else {
+ unregister_mods(MOD_BIT(KC_LALT));
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ add_oneshot_mods(MOD_BIT(KC_LALT));
+ } /*else {
+ del_oneshot_mods(MOD_BIT(KC_LALT));
+ }*/
+ }
+ return true;
+#else
+#define OSM_ALT OSM(MOD_LALT)
+#define OSM_CTL OSM(MOD_LCTL)
+#define OSM_GUI OSM(MOD_LGUI)
+#define OSM_SFT OSM(MOD_LSFT)
+#endif
+ // Obsoleted by using combos for umlauts now.
+ case KC_A_AE:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ auml_pressed = true;
+ } else {
+ maybe_send_umlaut(KC_A, &auml_pressed);
+ }
+ break;
+ case KC_O_OE:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ ouml_pressed = true;
+ } else {
+ maybe_send_umlaut(KC_O, &ouml_pressed);
+ }
+ break;
+ case KC_U_UE:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ uuml_pressed = true;
+ } else {
+ maybe_send_umlaut(KC_U, &uuml_pressed);
+ }
+ break;
+ case MINS_UNDSCR:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ } else {
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ // Can't send KC_KP_MINUS, it doesn't compose to, say →
+ tap_code16(KC_MINUS);
+ } else {
+ tap_code16(KC_UNDERSCORE);
+ }
+ }
+ break;
+ case ALT_TAB:
+ if (record->event.pressed) {
+ register_mods(MOD_BIT(KC_LALT));
+ tap_code16(KC_TAB);
+ }
+ break;
+ case INS_HARD:
+ // Do Alt-Shift-Ins first to have xdotool copy from SELECTION to CLIPBOARD, then Shift-Ins to paste.
+ if (record->event.pressed) {
+ tap_code16(LSFT(LALT(KC_INS)));
+ } else {
+ tap_code16(LSFT(KC_INS));
+ }
+ break;
+ case SHIFT_INS:
+ if (record->event.pressed) {
+ // when keycode is pressed
+ key_timer = timer_read();
+ // Shift when held ...
+ register_mods(MOD_BIT(KC_RSFT));
+ } else {
+ // If released within the timer, then Shift+Ins
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ tap_code16(KC_INS);
+ }
+ unregister_mods(MOD_BIT(KC_RSFT));
+ }
+ break;
+ case ALT_SHIFT_INS:
+ if (record->event.pressed) {
+ key_timer = timer_read();
+ // Shift when held ...
+ register_mods(MOD_BIT(KC_LSFT));
+ } else {
+ // If released within the timer, then Shift+Alt+Ins
+ if (timer_elapsed(key_timer) < TAPPING_TERM) {
+ register_mods(MOD_BIT(KC_LALT));
+ tap_code16(KC_INS);
+ }
+ // Note: this makes xev(1) see KeyPress for Meta_L but KeyRelease for Alt_L
+ unregister_mods(MOD_BIT(KC_LSFT) | MOD_BIT(KC_LALT));
+ }
+ break;
+/*
+ * Obsoleted by making tmux understand Ctrl-(Shift)-Tab natively.
+ case TM_NEXT:
+ if (record->event.pressed) SEND_STRING(SS_LCTRL("a") "n");
+ break;
+ case TM_PREV:
+ if (record->event.pressed) SEND_STRING(SS_LCTRL("a") "p");
+ break;
+*/
+ // TODO: use key overrides to turn, e.g. Win+Ctrl-Tab into VIM_NEXT.
+ // Not sure why Ctrl-Pgup works in vim, but not in vim-inside-tmux.
+ case VIM_NEXT:
+ if (record->event.pressed) SEND_STRING(SS_TAP(X_ESC) SS_TAP(X_G) SS_TAP(X_T));
+ break;
+ case VIM_PREV:
+ if (record->event.pressed) SEND_STRING(SS_TAP(X_ESC) SS_TAP(X_G) SS_LSFT("t"));
+ break;
+ case WIN_LEFT:
+ if (record->event.pressed) SEND_STRING(SS_LCTRL("w") SS_TAP(X_H));
+ break;
+ case WIN_DN:
+ if (record->event.pressed) SEND_STRING(SS_LCTRL("w") SS_TAP(X_J));
+ break;
+ case WIN_UP:
+ if (record->event.pressed) SEND_STRING(SS_LCTRL("w") SS_TAP(X_K));
+ break;
+ case WIN_RGHT:
+ if (record->event.pressed) SEND_STRING(SS_LCTRL("w") SS_TAP(X_L));
+ break;
+ }
+
+ return true;
+}
+
+#ifdef LEADER_ENABLE
+LEADER_EXTERNS();
+
+void matrix_scan_user(void) {
+ LEADER_DICTIONARY() {
+ leading = false;
+ leader_end();
+
+#ifdef UCIS_ENABLE
+ SEQ_ONE_KEY(KC_U) {
+ qk_ucis_start();
+ }
+#endif
+ SEQ_ONE_KEY(KC_H) {
+ send_unicode_string("ᕕ( ᐛ )ᕗ"); // happy
+ }
+ SEQ_ONE_KEY(KC_D) {
+ send_unicode_string("ಠ_ಠ"); // disapproval
+ }
+ SEQ_ONE_KEY(KC_L) {
+ send_unicode_string("( ͡° ͜ʖ ͡°)"); // lenny
+ }
+ SEQ_ONE_KEY(KC_S) {
+ send_unicode_string("¯\\_(ツ)_/¯"); // shrug
+ }
+ // tableflip (LEADER - TF)
+ SEQ_TWO_KEYS(KC_T, KC_F) {
+ //set_unicode_input_mode(UC_LNX);
+ //send_unicode_hex_string("0028 30CE 0CA0 75CA 0CA0 0029 30CE 5F61 253B 2501 253B");
+ send_unicode_string("(╯°□°)╯︵ ┻━┻");
+ }
+ // untableflip
+ SEQ_THREE_KEYS(KC_U, KC_T, KC_F) {
+ //set_unicode_input_mode(UC_LNX);
+ //send_unicode_hex_string("0028 30CE 0CA0 75CA 0CA0 0029 30CE 5F61 253B 2501 253B");
+ send_unicode_string("┬─┬ノ( º _ ºノ)");
+ }
+ }
+}
+#endif
+
+#ifdef UCIS_ENABLE
+// 3 codepoints at most, otherwise increase UCIS_MAX_CODE_POINTS
+const qk_ucis_symbol_t ucis_symbol_table[] = UCIS_TABLE(
+ UCIS_SYM("poop", 0x1F4A9), // 💩
+ UCIS_SYM("rofl", 0x1F923), // 🤣
+ UCIS_SYM("look", 0x0CA0, 0x005F, 0x0CA0) // ಠ_ಠ
+);
+#endif
diff --git a/users/uqs/uqs.h b/users/uqs/uqs.h
new file mode 100644
index 0000000000..f8b30caf79
--- /dev/null
+++ b/users/uqs/uqs.h
@@ -0,0 +1,77 @@
+// Copyright 2022 Ulrich Spörlein (@uqs)
+// SPDX-License-Identifier: GPL-2.0-or-later
+// vi:et sw=4:
+#pragma once
+
+#include QMK_KEYBOARD_H
+
+enum layers {
+ L_QWER = 0,
+ L_WASD, // wasd gaming
+ L_COLM, // Colemak DHm
+ L_EXTD,
+ L_NUM,
+ L_FUNC,
+ L_MOUSE,
+ L_LAST, // unused
+};
+
+#ifdef VIA_ENABLE
+_Static_assert(DYNAMIC_KEYMAP_LAYER_COUNT >= L_LAST, "VIA enabled, but not enough DYNAMIC_KEYMAP_LAYER_COUNT for all layers");
+#endif
+
+#define KC_CTAB LCTL(KC_TAB)
+#define KC_SCTAB LCTL(LSFT(KC_TAB))
+
+// Custom single-key codes, see uqs.c for the combos.
+enum custom_keycodes {
+ SHIFT_INS = SAFE_RANGE,
+ ALT_SHIFT_INS,
+ INS_HARD,
+ KC_A_AE,
+ KC_O_OE,
+ KC_U_UE,
+ MINS_UNDSCR, // obsoleted by combos, remove this!
+ TM_NEXT,
+ TM_PREV,
+ VIM_NEXT,
+ VIM_PREV,
+ WIN_LEFT,
+ WIN_RGHT,
+ WIN_UP,
+ WIN_DN,
+ LT_EXTD_ESC,
+ LT_NUM_BSPC,
+ LT_MOUSE_ALT_SHIFT_INS,
+ LT_FUNC_SHIFT_INS,
+ OSM_GUI,
+ OSM_SFT,
+ OSM_CTL,
+ OSM_ALT,
+ ALT_TAB,
+};
+
+#ifndef LEADER_ENABLE
+#define KC_LEAD KC_NO
+#endif
+
+// Shorter names
+#define MS_WHDN KC_MS_WH_DOWN
+#define MS_WHUP KC_MS_WH_UP
+#define MS_WHLEFT KC_MS_WH_LEFT
+#define MS_WHRGHT KC_MS_WH_RIGHT
+
+// GASC/◆⎇⇧⎈ home row mod, read all about it here:
+// https://precondition.github.io/home-row-mods
+// Left-hand home row mods
+#define KC_G_A LGUI_T(KC_A)
+#define KC_A_R LALT_T(KC_R)
+#define KC_S_S LSFT_T(KC_S)
+#define KC_C_T LCTL_T(KC_T)
+
+// Right-hand home row mods
+#define KC_C_N RCTL_T(KC_N)
+#define KC_S_E RSFT_T(KC_E)
+#define KC_A_I LALT_T(KC_I) // RALT is special, it's AltGr and my compose key under Win (layout UScmpse) and *nix (setxkbmap -option compose:ralt)
+#define KC_G_O RGUI_T(KC_O)
+
diff --git a/users/zigotica/rows.h b/users/zigotica/rows.h
index e73d72bbe2..18f08ccb0b 100644
--- a/users/zigotica/rows.h
+++ b/users/zigotica/rows.h
@@ -23,7 +23,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ,---------------------------------------. ,---------------------------------------.
* | | | | | | | | | | | |
- * | ` ~ | W | D | P | F | | K | Y | U | Q | ' " |
+ * | ` ~ | W | D | P | F | | Q | L | U | Y | ' " |
* | | | | | | | | | | | |
* |-------+-------+-------+-------+-------| |-------+-------+-------+-------+-------|
* | | | | | | | | | | | |
@@ -31,11 +31,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* | alt | ctrl | shft | meta | | | | meta | shft | ctrl | alt |
* |-------+-------+-------+-------+-------| |-------+-------+-------+-------+-------|
* | | | | | | | | | | | |
- * | B | X | C | V | [ { | | , < | L | Z | J | . > |
+ * | B | X | C | V | [ { | | , < | K | Z | J | . > |
* | | | | | TD ]} | | TD ; | | | | TD : |
* `-------+-------+-------+-------+-------| |-------+-------+-------+-------+-------.
* | | | | | |
- * | ESC | SPC | | E | INTRO |
+ * | TAB | SPC | | E | INTRO |
* | num | nav | | sym | fn |
* `---------------' `---------------'
*
@@ -43,11 +43,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define _STENAI_L1 KC_GRV, KC_W, KC_D, KC_P, KC_F
#define _STENAI_L2 LALT_T(KC_H), LCTL_T(KC_R), LSFT_T(KC_S), LGUI_T(KC_T), KC_G
#define _STENAI_L3 KC_B, KC_X, KC_C, KC_V, ZK_BRC
-#define _STENAI_LT LT(_NUM, KC_ESC), LT(_NAV, KC_SPC)
+#define _STENAI_LT LT(_NUM, KC_TAB), LT(_NAV, KC_SPC)
-#define _STENAI_R1 KC_K, KC_Y, KC_U, KC_Q, KC_QUOT
+#define _STENAI_R1 KC_Q, KC_L, KC_U, KC_Y, KC_QUOT
#define _STENAI_R2 KC_M, RGUI_T(KC_N), RSFT_T(KC_A), RCTL_T(KC_I), RALT_T(KC_O)
-#define _STENAI_R3 ZK_SEMI, KC_L, KC_Z, KC_J, ZK_COLON
+#define _STENAI_R3 ZK_SEMI, KC_K, KC_Z, KC_J, ZK_COLON
#define _STENAI_RT LT(_SYM, KC_E), LT(_FN, KC_ENT)
@@ -147,14 +147,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* | | | | | | | | | | | |
* `-------+-------+-------+-------+-------| |-------+-------+-------+-------+-------.
* | | | |:::::::| |
-* | | TAB | |:::::::| |
+* | | ESC | |:::::::| |
* | | | |:::::::| |
* `---------------' `---------------'
*/
#define ____SYM_L1 KC_PERC, KC_AMPR, KC_QUES, KC_PIPE, KC_EXLM
#define ____SYM_L2 KC_HASH, KC_AT, KC_COLN, KC_SCLN, KC_DLR
#define ____SYM_L3 ZK_PRN, KC_TILD, KC_SLSH, KC_BSLS, KC_CIRC
-#define ____SYM_LT _______, KC_TAB
+#define ____SYM_LT _______, KC_ESC
#define ____SYM_R1 _BLANK_ROW
#define ____SYM_R2 _BLANK_ROW
@@ -178,14 +178,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* | | | | | | | | | | | |
* `-------+-------+-------+-------+-------| |-------+-------+-------+-------+-------.
* | | | | |:::::::|
-* | | TAB | | |:::::::|
+* | | ESC | | |:::::::|
* | | | | |:::::::|
* `---------------' `---------------'
*/
#define ____FN_L1 _BLANK_ROW
#define ____FN_L2 _BLANK_ROW
#define ____FN_L3 _BLANK_ROW
-#define ____FN_LT _______, KC_TAB
+#define ____FN_LT _______, KC_ESC
#define ____FN_R1 _______, KC_F7, KC_F8, KC_F9, KC_F10
#define ____FN_R2 _______, KC_F1, KC_F2, KC_F3, KC_F11
diff --git a/users/zigotica/zigotica.h b/users/zigotica/zigotica.h
index e9ff5ff16c..e85a04edbe 100644
--- a/users/zigotica/zigotica.h
+++ b/users/zigotica/zigotica.h
@@ -26,7 +26,7 @@ enum userspace_layers {
};
#else
enum userspace_layers {
- _TERMINAL = 0,
+ _BASE = 0,
_FIGMA,
_BROWSER,
_VIM,