From 98da119293b7f231694119b51afc709b3d817ea2 Mon Sep 17 00:00:00 2001
From: Era James <51322608+era1112@users.noreply.github.com>
Date: Thu, 10 Mar 2022 23:07:37 +0300
Subject: [PATCH] era1112 keymap for preonic (#16064)

Added the keymap I have been using as a daily driver for the last month.

* good firmware 26 jan, best clicky mode stability so far

* modified to reflect master branch coding style

* further modified to reflect master branch coding style

* improving clicky stability, tuned down clicky delay duration

* changed name of keymap folder to use lowercase letters
---
 keyboards/preonic/keymaps/era1112/config.h  |  60 ++++
 keyboards/preonic/keymaps/era1112/keymap.c  | 365 ++++++++++++++++++++
 keyboards/preonic/keymaps/era1112/readme.md |   8 +
 keyboards/preonic/keymaps/era1112/rules.mk  |  26 ++
 4 files changed, 459 insertions(+)
 create mode 100644 keyboards/preonic/keymaps/era1112/config.h
 create mode 100644 keyboards/preonic/keymaps/era1112/keymap.c
 create mode 100644 keyboards/preonic/keymaps/era1112/readme.md
 create mode 100644 keyboards/preonic/keymaps/era1112/rules.mk

diff --git a/keyboards/preonic/keymaps/era1112/config.h b/keyboards/preonic/keymaps/era1112/config.h
new file mode 100644
index 0000000000..86cc6135e5
--- /dev/null
+++ b/keyboards/preonic/keymaps/era1112/config.h
@@ -0,0 +1,60 @@
+// Copyright 2022 Era James(@Era1112)
+// SPDX - License - Identifier: GPL - 2.0 - or -later
+
+#pragma once
+
+
+//----------- Default statements -----------//
+//------------------------------------------//
+#define MUSIC_MASK (keycode < 0xFF)
+
+/*
+ * MIDI options
+ */
+
+/* enable basic MIDI features:
+   - MIDI notes can be sent when in Music mode is on
+*/
+#define MIDI_BASIC
+
+/* enable advanced MIDI features:
+   - MIDI notes can be added to the keymap
+   - Octave shift and transpose
+   - Virtual sustain, portamento, and modulation wheel
+   - etc.
+*/
+#define MIDI_ADVANCED
+
+/* override number of MIDI tone keycodes (each octave adds 12 keycodes and allocates 12 bytes) */
+//#define MIDI_TONE_KEYCODE_OCTAVES 2
+
+
+//----------- Added statements -------------//
+//------------------------------------------//
+#define TAPPING_TERM 200                        // For tapdances
+
+// Commented to see if it helps stalls on clicky mode #define DYNAMIC_MACRO_NO_NESTING                // Improve dynamic macro stability
+#ifdef AUDIO_ENABLE
+	#define AUDIO_INIT_DELAY                    // to make startup audio work
+	#define STARTUP_SONG SONG(PREONIC_SOUND)
+	#define AUDIO_CLICKY                        // enable clicky mode
+
+	// Clicky mode parameters
+	#define AUDIO_CLICKY_FREQ_MIN 65.0f         // Default 65
+	#define AUDIO_CLICKY_FREQ_DEFAULT 800.0f    // Default 440
+	#define AUDIO_CLICKY_FREQ_MAX 1500.0f       // Defaul 1500
+	#define AUDIO_CLICKY_FREQ_RANDOMNESS 1.0f   // Default 0.05
+	#define AUDIO_CLICKY_DELAY_DURATION 0.1f    // Default 1
+#endif  //AUDIO_ENABLE
+
+#define RGBLIGHT_SLEEP                  // RGB lights turn off when host sleeps
+
+// Firmware minimization
+
+// Commented to see if it helps stalls on clicky mode 
+// #define NO_ACTION_ONESHOT
+// #undef LOCKING_SUPPORT_ENABLE
+// #undef LOCKING_RESYNC_ENABLE
+// #define NO_MUSIC_MODE
+// #define LAYER_STATE_8BIT        // Limits keymap to 8 layers
+// #undef RGBLIGHT_ANIMATIONS      // Removes rgb animations
diff --git a/keyboards/preonic/keymaps/era1112/keymap.c b/keyboards/preonic/keymaps/era1112/keymap.c
new file mode 100644
index 0000000000..4031f998db
--- /dev/null
+++ b/keyboards/preonic/keymaps/era1112/keymap.c
@@ -0,0 +1,365 @@
+// Copyright 2022 Era James(@Era1112)
+// SPDX - License - Identifier: GPL - 2.0 - or -later
+
+#include QMK_KEYBOARD_H                     // Default statement
+
+#define HSV_RETRO_CONSOLE   36, 150, 255    //HSV_YELLOW = 43, 255, 255
+
+
+//----------- RGB Default Settings -----------//
+//--------------------------------------------//
+#ifdef RGBLIGHT_ENABLE
+
+void keyboard_post_init_user(void) {
+    rgblight_enable_noeeprom(); // Enables RGB, without saving settings
+    rgblight_sethsv_noeeprom(HSV_RETRO_CONSOLE);
+    rgblight_mode_noeeprom(RGBLIGHT_MODE_STATIC_LIGHT);
+}
+
+#endif  // RGBLIGHT_ENABLE
+
+//----------- Layer names -----------//
+//-----------------------------------//
+enum preonic_layers {
+  _QWERTY,
+  _LOWER,
+  _RAISE,
+  _ADJUST,
+};
+
+
+//----------- Sounds -----------//
+//------------------------------//
+#ifdef AUDIO_ENABLE
+
+    float capslockToggleSound[][2] = SONG(STARTUP_SOUND);
+    float dynamicBufferRecordSound[][2] = SONG(STARTUP_SOUND);
+    float dynamicBufferFullSound[][2] = SONG(GOODBYE_SOUND);
+
+#endif  // AUDIO_ENABLE
+
+
+//----------- Called when dynamic buffer full -----------//
+//-------------------------------------------------------//
+void backlight_toggle(void) {
+#ifdef AUDIO_ENABLE
+
+    PLAY_SONG(dynamicBufferFullSound);
+
+#endif  // AUDIO_ENABLE
+}
+
+
+//----------- Tapdance prelims -----------//
+//----------------------------------------//
+typedef enum {
+    TD_NONE,
+    TD_UNKNOWN,
+    TD_1_TAP,
+    TD_1_HOLD,
+    TD_2_TAP,
+    TD_2_HOLD,
+} td_state_t;
+
+typedef struct {
+    bool is_press_action;
+    td_state_t state;
+} td_tap_t;
+
+td_state_t cur_dance(qk_tap_dance_state_t* 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 'TD_DOUBLE_SINGLE_TAP', however this is not fully tested
+ *
+ */
+td_state_t cur_dance(qk_tap_dance_state_t* state) {
+    if (state->count == 1) {
+        if (state->interrupted || !state->pressed) {
+            return TD_1_TAP;
+        // Key has not been interrupted, but the key is still held. Means you want to send a 'HOLD'.
+        } else {
+        return TD_1_HOLD;
+        }
+    } else if (state->count == 2) {
+        // TD_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->pressed) return TD_2_HOLD;
+        else return TD_2_TAP;
+    } else {
+        return TD_UNKNOWN;
+    }
+}
+
+
+//----------- 2tap capslock --------------//
+//----------------------------------------//
+void twoCapsLock_finished(qk_tap_dance_state_t* state, void* user_data);
+void twoCapsLock_reset(qk_tap_dance_state_t* state, void* user_data);
+
+static td_tap_t twoCapsLock_tap_state = {
+    .is_press_action = true,
+    .state = TD_NONE
+};
+
+void twoCapsLock_finished(qk_tap_dance_state_t* state, void* user_data) {
+    twoCapsLock_tap_state.state = cur_dance(state);
+    switch (twoCapsLock_tap_state.state) {
+    case TD_NONE: register_code(KC_LSFT); break;
+    case TD_UNKNOWN: register_code(KC_LSFT); break;
+    case TD_1_TAP: register_code(KC_LSFT); break;
+    case TD_1_HOLD: register_code(KC_LSFT); break;
+    case TD_2_TAP:
+        register_code(KC_CAPS);
+#ifdef AUDIO_ENABLE
+        PLAY_SONG(capslockToggleSound);
+#endif  // AUDIO_ENABLE
+        break;
+    case TD_2_HOLD: register_code(KC_LSFT); break;      
+    }
+}
+
+void twoCapsLock_reset(qk_tap_dance_state_t* state, void* user_data) {
+    switch (twoCapsLock_tap_state.state) {
+    case TD_UNKNOWN: unregister_code(KC_LSFT); break;
+    case TD_NONE: unregister_code(KC_LSFT); break;
+    case TD_1_TAP: unregister_code(KC_LSFT); break;
+    case TD_1_HOLD: unregister_code(KC_LSFT); break;
+    case TD_2_TAP:
+        unregister_code(KC_CAPS);
+#ifdef AUDIO_ENABLE
+        PLAY_SONG(capslockToggleSound);
+#endif  // AUDIO_ENABLE
+        break;
+    case TD_2_HOLD: unregister_code(KC_LSFT); break;
+    }
+    twoCapsLock_tap_state.state = TD_NONE;
+}
+
+
+//----------- Rotary Encoder --------------//
+//----------------------------------------//
+bool encoder_update_user(uint8_t index, bool clockwise) {
+    if (layer_state_is(_QWERTY)) {
+        if (clockwise) {
+            tap_code(KC_WH_U);
+        } else {
+            tap_code(KC_WH_D);
+        }
+    }
+    else if (layer_state_is(_LOWER)) {
+        if (clockwise) {
+            tap_code16(S(KC_F3));
+        } else {
+            tap_code(KC_F3);
+        }
+    } else if (layer_state_is(_RAISE)) {
+        if (clockwise) {
+            tap_code16(C(KC_Z));
+        } else {
+            tap_code16(C(KC_Y));
+        }
+    }
+    return false;
+}
+
+//----------- Custom keycodes ------------//
+//----------------------------------------//
+enum {
+    TD_2_CAPSLOCK
+};
+
+enum custom_keycodes {
+    CU_BLNKON = SAFE_RANGE,
+    CU_BLNKOFF,
+    CU_RGBON,
+    CU_RGBOFF,
+    ENC_MODE
+};
+
+static bool blinky = false;         // Track blinky behavior on/off for keycode
+
+qk_tap_dance_action_t tap_dance_actions[] = {
+    [TD_2_CAPSLOCK] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, twoCapsLock_finished, twoCapsLock_reset)
+};
+
+
+//----------- Intercepts and overrides ------------//
+//-------------------------------------=-----------//
+bool process_record_user(uint16_t keycode, keyrecord_t* record) {
+    switch (keycode) {
+    // Turn RGB LEDs off
+    case CU_RGBOFF:
+
+        // If pressed
+        if (record->event.pressed) {
+            rgblight_sethsv_noeeprom(HSV_OFF);   
+            return true;
+
+        // If released
+        } else {
+            return true;
+        }
+
+    // Turn RGB LEDs on
+    case CU_RGBON:
+
+        // If pressed
+        if (record->event.pressed) {
+            rgblight_sethsv_noeeprom(HSV_RETRO_CONSOLE);  
+            return true;
+
+        // If released
+        } else {
+            return true;
+        }
+
+    // Turn blinky LEDs off
+    case CU_BLNKOFF:
+
+        // If pressed
+        if (record->event.pressed) {
+            blinky = false;
+            return true;
+
+        // If released
+        } else {
+            return true;
+        }
+
+    // Turn blinky LEDs on
+    case CU_BLNKON:
+
+        // If pressed
+        if (record->event.pressed) {
+            blinky = true;
+            return true;
+
+        // If released
+        } else {
+            return true;
+        }
+
+    // Sound when Dynamic recording started
+    case DYN_REC_START1:
+
+        // If pressed
+        if (record->event.pressed) {
+        #ifdef AUDIO_ENABLE
+            PLAY_SONG(dynamicBufferRecordSound);
+        #endif  // AUDIO_ENABLE
+            return true; // Let QMK send the press/release events
+
+        // If released
+        } else {
+            return true; // Let QMK send the press/release events
+        }
+
+    // Sound when Dynamic recording stopped
+    case DYN_REC_STOP:
+
+        // If pressed
+        if (record->event.pressed) {
+        #ifdef AUDIO_ENABLE
+            PLAY_SONG(dynamicBufferFullSound); 
+        #endif  // AUDIO_ENABLE
+            return true; // Let QMK send the enter press/release events
+
+        // If released
+        } else {
+            return true; // Let QMK send the press/release events
+        }
+
+    // Encoder Click
+    case ENC_MODE:
+        if (record->event.pressed) {
+            if (layer_state_is(_QWERTY)) {
+                tap_code(KC_BTN1);
+                return false;
+            } else if (layer_state_is(_LOWER)) {
+                return false;
+            } else if (layer_state_is(_RAISE)) {
+                return false;
+            }
+        }
+
+
+    // Adds blinks if blinky is on
+    default:
+        if (blinky == true) {
+            rgblight_toggle();
+        }
+
+    return true; // Process all other keycodes normally
+
+    }
+}
+
+
+//----------- Keymap ------------//
+//-------------------------------//
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+
+    // main layer
+    [_QWERTY] = LAYOUT_ortho_5x12 (
+        // (Non-disabled top row), uncomment and replace if you want preonic-style instead of planck-style
+        // KC_MINS,            KC_1,           KC_2,           KC_3,           KC_4,           KC_5,           KC_6,           KC_7,           KC_8,       KC_9,       KC_0,       KC_EQL,
+		KC_NO,              KC_NO,          KC_NO,          KC_NO,          KC_NO,          KC_NO,          KC_NO,          KC_NO,          KC_NO,      KC_NO,      KC_NO,      KC_NO,
+        KC_TAB,             KC_Q,           KC_W,           KC_E,           KC_R,           KC_T,           KC_Y,           KC_U,           KC_I,       KC_O,       KC_P,       KC_BSPC,
+        KC_ESC,             KC_A,           KC_S,           KC_D,           KC_F,           KC_G,           KC_H,           KC_J,           KC_K,       KC_L,       KC_SCLN,    KC_ENT,
+        KC_LSFT,            KC_Z,           KC_X,           KC_C,           KC_V,           KC_B,           KC_N,           KC_M,           KC_COMM,    KC_DOT,     KC_SLSH,    TD(TD_2_CAPSLOCK),
+        ENC_MODE,           KC_LCTL,        KC_LGUI,        KC_LALT,        MO(_LOWER),     KC_SPC,         KC_SPC,         MO(_RAISE),     KC_LEFT,    KC_DOWN,    KC_UP,      KC_RGHT
+    ),
+
+    // lower key
+    [_LOWER] = LAYOUT_ortho_5x12 (
+        DYN_MACRO_PLAY1,    DYN_REC_START1, DYN_REC_STOP,   KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,            KC_TRNS,        KC_TRNS,    KC_TRNS,    KC_TRNS,
+        KC_TRNS,            KC_1,           KC_2,           KC_3,           KC_4,           KC_5,           KC_6,           KC_7,               KC_8,           KC_9,       KC_0,       KC_DEL,
+        KC_BSPC,            KC_F1,          KC_F2,          KC_F3,          KC_F4,          KC_F5,          KC_F6,          KC_QUOT,            KC_GRV,         KC_LCBR,    KC_RCBR,    KC_TRNS,
+        KC_TRNS,            KC_F7,          KC_F8,          KC_F9,          KC_F10,         KC_F11,         KC_F12,         KC_MINS,            KC_EQL,         KC_TRNS,    KC_BSLS,    KC_TRNS,
+        KC_TRNS,            KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        MO(_ADJUST),        KC_HOME,        KC_PGDN,    KC_PGUP,    KC_END
+    ),
+
+    // raise key
+    [_RAISE] = LAYOUT_ortho_5x12 (
+        DYN_MACRO_PLAY1,    DYN_REC_START1, DYN_REC_STOP,   KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,            KC_TRNS,        KC_TRNS,    KC_TRNS,    KC_TRNS,
+        KC_TRNS,            KC_EXLM,        KC_AT,          KC_HASH,        KC_DLR,         KC_PERC,        KC_CIRC,        KC_AMPR,            KC_ASTR,        KC_LPRN,    KC_RPRN,    KC_DEL,
+        KC_DEL,             KC_F1,          KC_F2,          KC_F3,          KC_F4,          KC_F5,          KC_F6,          KC_DQUO,            KC_TILD,        KC_LBRC,    KC_RBRC,    KC_TRNS,
+        KC_TRNS,            KC_F7,          KC_F8,          KC_F9,          KC_F10,         KC_F11,         KC_F12,         KC_UNDS,            KC_PLUS	,       KC_TRNS,    KC_PIPE,    KC_TRNS,
+        KC_TRNS,            KC_TRNS,        KC_TRNS,        KC_TRNS,        MO(_ADJUST),    KC_TRNS,        KC_TRNS,        KC_TRNS,            KC_MUTE,        KC_VOLD,    KC_VOLU,    KC_F24
+    ),
+
+    // hardware adjust layer, raise+lower
+    [_ADJUST] = LAYOUT_ortho_5x12 (
+        AU_ON,              AU_OFF,          CK_ON,           CK_OFF,          KC_NO,           KC_NO,           KC_NO,       KC_NO,           KC_NO,       KC_NO,       KC_NO,       KC_NO,
+																																															
+        CU_RGBON,           CU_RGBOFF,       CU_BLNKON,       CU_BLNKOFF,      KC_NO,           KC_NO,           KC_NO,       KC_NO,           KC_NO,       KC_NO,       KC_NO,       KC_NO,
+		KC_NO,              KC_NO,           KC_NO,           KC_NO,           KC_NO,           KC_NO,           KC_NO,       KC_NO,           KC_NO,       KC_NO,       KC_NO,       KC_NO,
+        KC_NO,              KC_NO,           KC_NO,           KC_NO,           KC_NO,           KC_NO,           KC_NO,       KC_NO,           KC_NO,       KC_NO,       KC_NO,       KC_NO,
+        KC_NO,              KC_NO,           KC_NO,           KC_NO,           KC_NO,           KC_NO,           KC_NO,       KC_NO,           KC_NO,       KC_NO,       KC_NO,       KC_NO
+    )
+    
+};
diff --git a/keyboards/preonic/keymaps/era1112/readme.md b/keyboards/preonic/keymaps/era1112/readme.md
new file mode 100644
index 0000000000..76775b85aa
--- /dev/null
+++ b/keyboards/preonic/keymaps/era1112/readme.md
@@ -0,0 +1,8 @@
+A preonic keymap that includes:
+- doubletap tapdance for caps lock
+- rotary encoder
+- macro record/playback
+- light on/off
+- sound on/off
+- blink-on-keypress w/ on/off keystroke
+- beep-on-keypress w/ on/off keystroke (this has stability issues when typing fast, still trying to remediate)
\ No newline at end of file
diff --git a/keyboards/preonic/keymaps/era1112/rules.mk b/keyboards/preonic/keymaps/era1112/rules.mk
new file mode 100644
index 0000000000..4e83382dad
--- /dev/null
+++ b/keyboards/preonic/keymaps/era1112/rules.mk
@@ -0,0 +1,26 @@
+## Copyright 2022 Era James (@Era1112)
+## SPDX-License-Identifier: GPL-2.0-or-later
+
+# DEFAULT STATEMENTS
+# ==================
+
+SRC += muse.c
+
+
+# ADDED STATEMENTS
+# ================
+
+AUDIO_ENABLE = yes          # Audio output on
+TAP_DANCE_ENABLE = yes		# For double-tap tapdances
+DYNAMIC_MACRO_ENABLE = yes	# For dynamuic macros
+RGBLIGHT_ENABLE = yes		# For RGB lighting functions
+ENCODER_ENABLE = yes		# For Rotary encoders
+
+
+# Firmware minimization
+# Commented to see if it helps stalls on clicky mode 													 
+CONSOLE_ENABLE = no
+#LTO_ENABLE = yes
+SPACE_CADET_ENABLE = no
+GRAVE_ESC_ENABLE = no 
+MAGIC_ENABLE = no