summaryrefslogtreecommitdiffstats
path: root/keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c')
-rw-r--r--keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c2671
1 files changed, 2671 insertions, 0 deletions
diff --git a/keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c b/keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c
new file mode 100644
index 0000000000..8372ae4cd1
--- /dev/null
+++ b/keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c
@@ -0,0 +1,2671 @@
+/*
+ * License (GPL):
+
+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/>.
+
+ * Author: © 2019, 2020 by Jos Boersema
+ *
+ */
+
+/* This file contains mostly the Unicode and special macros.
+ It contains the function: process_record_user(...)
+ */
+
+#include "./unicode_macros.h"
+#include "./unicode_weurope.h"
+#include "./unicode_hebrew.h"
+
+// Definition of ƒ (Dutch currency symbol).
+// Best changed in user_config.h, if you like a Euro symbol instead.
+//
+# ifndef UNICODE_CURRENCY // Prior optional definition in user_config.h
+# define UNICODE_CURRENCY 0x0192 // Hex number. The unicode hex number for position ƒ in the default keymap.
+# endif
+
+//
+// 🛠
+#define CS_USER_DEFINED 0x1F6E0 // Hammer & wrench (place holder).
+
+#define DIV10POINT TRUE // suggest to function write_number, to divide by 10 and print as a fraction: N.N
+
+// Gives Unicode code points to the relevant QMK functions.
+// Handles Dvorak 'descramble' Unicode mode, if compiled (only tested on Linux).
+void unicode_hex2output (long unsigned int unshifted, long unsigned int shifted) {
+
+ long unsigned int input; // which argument to work on
+
+# ifdef DVORAK_DESCRAMBLE // Do the letter descramble if needed.
+
+ char output[10]; // will hold the ascii for output
+ int index; // count backwards 'to left' in the string
+ long unsigned int bitmove; // move computation to next digit.
+ long unsigned int work; // temporary value for computation
+
+# endif
+
+ // What to work on
+ if(shift_ison) input = shifted; // Trying to get everything possible here in this function, to reduce firmware size.
+ else input = unshifted;
+
+# ifndef DVORAK_DESCRAMBLE // Only normal mode
+
+ register_unicode ( (uint32_t) input ) ;
+
+# else
+
+ if(_FULL_ != alternate){
+
+ register_unicode ( (uint32_t) input ) ; // normal Unicode mode
+
+ }else{ // Special Dvorak-descramble mode: 0-9=0-9, a=a, b=n, c=i, d=h, e=d, f=y
+
+ // Take the hex value 4 bits at a time, starting with the least significant, convert to ascii, store
+ index = 9;
+ output[index] = '\0'; // terminator
+ bitmove = 0x1;
+ while ((work = (input / bitmove)) && (index >= 0)) {
+ index --;
+ work &= 0xF;
+ if (work < 0xA){ // numbers
+ output[index] = work + 0x30; // pad to ASCII
+ }else{ // alphas
+ if (0xA == work) output[index] = 'a';
+ if (0xB == work) output[index] = 'n';
+ if (0xC == work) output[index] = 'i';
+ if (0xD == work) output[index] = 'h';
+ if (0xE == work) output[index] = 'd';
+ if (0xF == work) output[index] = 'y';
+ }
+ bitmove *= 0x10; // next digit
+ }
+
+ SEND_STRING ( SS_DOWN(X_LCTL) SS_DOWN(X_LSFT) "f" SS_UP(X_LSFT) SS_UP(X_LCTL) ); // lead-in for Unicode on Linux, 'descramble' mode
+ send_string (output + index); // pointer to argument with formatted string
+ SEND_STRING ( " " ); // Ends the Unicode numerical input mode
+ }
+
+# endif // DVORAK_DESCRAMBLE mode for that Base layer & mode setting is compiled in
+
+}
+
+
+// Wrapper for unicode keys that do have the same on shift.
+void unicode_hex2output_single (long unsigned int either) {
+ unicode_hex2output (either, either);
+}
+
+
+// Required by QMK Unicode
+const uint32_t PROGMEM unicode_map[] = {
+
+};
+
+// Macro name definitions. The Unicode layers _ACC, _DRA and _BON are defined here,
+// because the Unicode map system does not have enough space (at time of this programming, year 2020).
+enum custom_keycodes {
+
+ // Macro, allowing the upper left button to switch to either _DEF_BASE base layer, or the _ALT_BASE base layer.
+ // Alternate is set on/half/off in the _RAR layer. The word "base" is used to avoid "default," because the default
+ // layer system call DF() is not being used.
+ CTO_BASE = SAFE_RANGE, // 'C' for costum, "TO" for to, "BASE" for chosen base layer
+
+ OTHER_BASE, // cycles modes: use _DEF_BASE, _ALT_BASE. For “dvorak²” layout (descramble) compile option, there is a third mode.
+
+# if defined(BASE_NUMPAD__ALT_BASE)
+ OTHER_BASE_GO, // Like OTHER_BASE, but also immediately switches to the other BASE layer.
+# endif
+
+ CTO_NUMS, // activates number-symbols layer, taking into account the dual layout mode
+ CTO_ACCE, // accented ''
+ CTO_DRAW, // drawings ''
+
+# ifndef CHOLTAP_ACCE_NOP
+ CHOLTAP_ACCE, // Go to accented layer, or others in combination with other keys.
+# endif
+
+// Keys can be pressed together for a separate layer (like 'adjust layer' on the Planck).
+ DUO_HOLD,
+
+ CHOLTAP_RSHFT, // Go to _FUN layer, or shift modifier.
+ CHOLTAP_LSHFT, // Go to <configurable> layer, or shift modifier.
+ CHOLTAP_LAYR, // Go to _RAR layer, or right arrow
+
+// Shifts which on tap produce a key
+
+ RSFT_TILDE,
+ LSFT_DASH,
+
+// Special macro to make F-keys one-shot or not.
+ _FUN_STAY,
+
+// Layer toggle to be guaranteed on up-key, therefore macro definition here.
+ _MOV_UP,
+
+// These macros protect the critical keys like 'Power' from accidental press, by needing Shift to be pressed.
+ C_KC_PWR, // Powers computer off.
+ C_KC_WAKE,
+ C_KC_SLEP, // sleep computer
+ C_KC_PAUS, // pauze computer
+
+// Toggles side leds on/off.
+ LEDS_ON,
+ RGBTOG_,
+
+// Typing speed measuring
+ SPEED_TOG,
+ SPEED_REPORT,
+
+// Word/character counting
+ COUNT_TOG, // starts word counting
+ COUNT_REPORT, // writes to the computer as if typing, gives count report
+ COUNT_WORDMIN, // reduces the word count
+ COUNT_NULL, // resets count to zero
+ LT__MOV__KC_ENT, // move to layer _MOV, or <enter>
+
+// The _ACC layer, additional Unicode.
+# ifndef REMOVE_ACC // This cuts out the whole _ACC layer.
+ XP_ACC_AA,
+ XP_ACC_AB,
+ XP_ACC_AC,
+ XP_ACC_AD,
+ XP_ACC_AE,
+ XP_ACC_AF,
+ XP_ACC_AG,
+ XP_ACC_AH,
+ XP_ACC_AI,
+ XP_ACC_AJ,
+ XP_ACC_BA,
+ XP_ACC_BB,
+ XP_ACC_BC,
+ XP_ACC_BD,
+ XP_ACC_BE,
+ XP_ACC_BF,
+ XP_ACC_BG,
+ XP_ACC_BH,
+ XP_ACC_BI,
+ XP_ACC_BJ,
+ XP_ACC_BK,
+ XP_ACC_CA,
+ XP_ACC_CB,
+ XP_ACC_CC,
+ XP_ACC_CD,
+ XP_ACC_CE,
+ XP_ACC_CF,
+ XP_ACC_CG,
+ XP_ACC_CH,
+ XP_ACC_CI,
+ XP_ACC_CJ,
+# endif // REMOVE_ACC
+
+# ifndef REMOVE_DRA // This cuts out the whole _DRA layer
+// The _DRA layer, additional Unicode.
+ XP_DRA_AA,
+ XP_DRA_AB,
+ XP_DRA_AC,
+ XP_DRA_AD,
+ XP_DRA_AE,
+ XP_DRA_AF,
+ XP_DRA_AG,
+ XP_DRA_AH,
+ XP_DRA_AI,
+ XP_DRA_AJ,
+ XP_DRA_BA,
+ XP_DRA_BB,
+ XP_DRA_BC,
+ XP_DRA_BD,
+ XP_DRA_BE,
+ XP_DRA_BF,
+ XP_DRA_BG,
+ XP_DRA_BH,
+ XP_DRA_BI,
+ XP_DRA_BJ,// XP_DRA_BK , // no 'BK' key definition on this layer
+ XP_DRA_CA,
+ XP_DRA_CB,
+ XP_DRA_CC,
+ XP_DRA_CD,
+ XP_DRA_CE,
+ XP_DRA_CF,
+# endif // REMOVE_DRA
+ XP_DRA_CG, // Needed for ☑ on Unicode tester key in _RAR
+# ifndef REMOVE_DRA // This cuts out the whole _DRA layer
+ XP_DRA_CH,
+ XP_DRA_CI,
+ XP_DRA_CJ,
+# endif // REMOVE_DRA
+
+// The _BON layer, additional Unicode.
+# ifndef REMOVE_BON // Removes this layer entirely, if set.
+ XP_BON_AA,
+ XP_BON_AB,
+ XP_BON_AC,
+ XP_BON_AD,
+ XP_BON_AE,
+ XP_BON_AF,
+ XP_BON_AG,
+ XP_BON_AH,
+ XP_BON_AI,
+ XP_BON_AJ,
+ XP_BON_BA,
+ XP_BON_BB,
+ XP_BON_BC,
+ XP_BON_BD,
+ XP_BON_BE,
+ XP_BON_BF,
+ XP_BON_BG,
+ XP_BON_BH,
+ XP_BON_BI,
+ XP_BON_BJ,
+ XP_BON_BK,
+ XP_BON_CA,
+ XP_BON_CB,
+ XP_BON_CC,
+ XP_BON_CD,
+ XP_BON_CE,
+ XP_BON_CF,
+ XP_BON_CG,
+ XP_BON_CH,
+ XP_BON_CI,
+ XP_BON_CJ,
+# endif // REMOVE_BON
+
+// Hebrew
+# if defined(BASE_HEBREW__DEF_BASE) || defined(BASE_HEBREW__ALT_BASE)
+ XP_HEB_AA,
+ XP_HEB_AB,
+ XP_HEB_AC,
+ XP_HEB_AD,
+ XP_HEB_AE,
+ XP_HEB_AF,
+ XP_HEB_AG,
+ XP_HEB_AH,
+ XP_HEB_AI,
+ XP_HEB_AJ,
+ XP_HEB_BA,
+ XP_HEB_BB,
+ XP_HEB_BC,
+ XP_HEB_BD,
+ XP_HEB_BE,
+ XP_HEB_BF,
+ XP_HEB_BG,
+ XP_HEB_BH,
+ XP_HEB_BI,
+ XP_HEB_BJ,
+# if defined(HEBREW_ISRAEL)
+ XP_HEB_BK, //
+# endif
+ XP_HEB_CA,
+ XP_HEB_CB,
+ XP_HEB_CC,
+ XP_HEB_CD,
+ XP_HEB_CE,
+ XP_HEB_CF,
+ XP_HEB_CG,
+# if defined(HEBREW_ISRAEL) || defined(HEBREW_DVORAK)
+ XP_HEB_CH,
+ XP_HEB_CI,
+ XP_HEB_CJ,
+# endif
+ XP_HEB_MQF, // ־
+# endif //BASE_HEBREW__*
+
+};
+
+// Pre-existing function, called for every key up and down.
+// This function is sortof the hub of the whole thing.
+bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+
+ // User input for the word count menu
+ if (sizecount_menu) {
+ if (record->event.pressed) { // key down
+
+ switch (keycode) {
+ case KC_0: // read in how many is maximum
+ sizecount_max = (sizecount_max * 10);
+ break;
+
+ case KC_1:
+ sizecount_max = (sizecount_max * 10) + 1;
+ break;
+
+ case KC_2:
+ sizecount_max = (sizecount_max * 10) + 2;
+ break;
+
+ case KC_3:
+ sizecount_max = (sizecount_max * 10) + 3;
+ break;
+
+ case KC_4:
+ sizecount_max = (sizecount_max * 10) + 4;
+ break;
+
+ case KC_5:
+ sizecount_max = (sizecount_max * 10) + 5;
+ break;
+
+ case KC_6:
+ sizecount_max = (sizecount_max * 10) + 6;
+ break;
+
+ case KC_7:
+ sizecount_max = (sizecount_max * 10) + 7;
+ break;
+
+ case KC_8:
+ sizecount_max = (sizecount_max * 10) + 8;
+ break;
+
+ case KC_9:
+ sizecount_max = (sizecount_max * 10) + 9;
+ break;
+
+ case KC_C: // count characters
+ sizecount_max_type = SIZECOUNT_CHAR;
+ sizecount_menu = FALSE;
+ break;
+
+ case KC_W: // count words
+ sizecount_max_type = SIZECOUNT_WORD;
+ sizecount_menu = FALSE;
+ break;
+
+ // Anything else ends menu input.
+ case KC_DOT:
+ case KC_ESC:
+ sizecount_menu = FALSE; // break out
+ break;
+
+ }
+ if (!sizecount_menu) { // end
+ send_string ("->");
+ write_number (sizecount_max, FALSE); // just indicate something
+ }
+ }
+ }
+
+ // Go back to base-layer after pressing an F-key, on key-up to avoid BASE key activation
+ if ((_fun_stay == FALSE) && //
+ (((keycode >= KC_F1) && (keycode <= KC_F12))
+ ||
+ ((keycode >= KC_F13) && (keycode <= KC_F24)))) { // assumes keycodes 1-12 and 13-24 are consequtive, which seems likely, although using 1-24 failed (probably not consequtive)
+ // Go back to base layer
+ if (!(record->event.pressed)) { // key up
+ if (alternate) { //
+ layer_move (_ALT_BASE);
+ }else{
+ layer_move (_DEF_BASE);
+ }
+ }
+ }
+
+ // Detect if Shift was pressed in isolation, by seeing if another key was pressed during the time
+ // the right shift key was held down.
+ // This system is also used by CHOLTAP_ACCE
+ // This helps make sure a tapped use of these keys is correctly differentiated from their use as a
+ // modifier/layer-hold key. The Shift and CHOLTAP_ACCE should not normally interfere with each other.
+ if (isolate_trigger) { // speed: hoping this statement to execute a little quicker overall, than the next
+ if ((keycode != CHOLTAP_RSHFT) // not right shift up
+ &&
+ (keycode != CHOLTAP_LSHFT) // not left shift up
+ &&
+ (keycode != CHOLTAP_ACCE) // _ACC layer (and others)
+ &&
+ (keycode != RSFT_TILDE) // Shift on _NSY
+ &&
+ (keycode != LSFT_DASH) // Shift on _NSY
+ &&
+ (keycode != CHOLTAP_LAYR))
+ { // _RAR layer, or RAlt/Alt-Gr
+ isolate_trigger = FALSE; // another key was pressed
+ }
+ }
+
+ // This block contains the complex macros, which should not count in speed counting or word/character counting,
+ // because they aren't typed characters.
+ switch (keycode) {
+
+ // Typing speed measuring
+ case SPEED_TOG: // Toggle speed measuring on/off
+ if (record->event.pressed) { // key down
+ if (speed_measure) {
+ speed_measure = FALSE;
+
+# ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_noeeprom (HSV_PURPLE); // indicates stop (_RAR color)
+# endif
+
+ }else{
+ // initialization of measurements
+ speed_measure = TRUE; // activates
+ speed = 0; // start at 0 k/s
+ speed_countdown = SPEED_COUNTDOWN; // reset, speed is measured in batches of keypresses
+ speed_counttime = timer_read32 ();// get current time
+ speed_add = 0;// speed average accumulator, it keeps adding the *speed* of each batch to this total
+ speed_batches = 0; // divider for speed_add to get the average
+
+# ifdef RGBLIGHT_ENABLE
+ // set middle led
+ rgblight_sethsv_noeeprom (HSV_WHITE); // indicates start
+# endif
+
+ }
+
+# ifdef RGBLIGHT_ENABLE
+ isolate_rgblight_set ();
+# endif
+
+ }
+ break;
+
+ case SPEED_REPORT: // Report the current typing speed by writing it, as if typing
+ if (record->event.pressed) { // down
+ short added = 5; // This counts how many characters the report itself is adding into the current text,
+ // to later delete it from the character count for text-size counting.
+
+ if (speed_measure) {
+
+# ifdef WORDS_PER_MINUTE
+
+ // The speed is recorded as an accumulation of keystrokes-per-second, times 10 for added precision.
+ // This will be converted into words-per-minute by dividing by 5 characters for a word including
+ // blank space and punctuation, and multiplied by 60 for seconds per minute. ⁶⁰/₅ = 12. Multiplied
+ // by 12 is the simple conversion.
+ send_string ("<"); // +1 character written // analogue to '<POWER>'
+ added += write_number ((long int)((speed*12)/10), FALSE); // writes the speed
+ send_string ("wpm"); // +3 character written
+ if (0 != speed_batches) {
+ long int average_times_ten;
+ average_times_ten =(long int) ((speed_add * 12) / speed_batches); // *12 converts k/s to wpm
+
+ send_string (";"); // +① ''
+ added += write_number (average_times_ten / 10, FALSE); // writes the average speed, cannot use decimal because precision is not there
+ send_string ("wpm"); // +③
+ added += write_number ((long int) speed_batches, FALSE); // amount of batches
+ send_string ("x"); // +①
+ added += 9 + write_number ((long int) SPEED_COUNTDOWN, FALSE); // amount of batches
+ send_string ("keys"); // +④ = ⑨
+
+ speed_led ( (int) (average_times_ten / 12));// on report, show the average
+ // we need to convert back to k/s now
+ }
+
+# else // keystrokes per second, k/s
+
+ send_string ("<"); // +1 character written // analogue to '<POWER>'
+ added += write_number ((long int)(speed/10), FALSE); // writes the speed
+ send_string ("k/s"); // +3 character written
+ if (0 != speed_batches) {
+ long int average_times_ten;
+ average_times_ten =(long int) (speed_add / speed_batches);
+
+ send_string (";"); // +① ''
+ added += write_number (average_times_ten, DIV10POINT); // writes the average speed
+ send_string ("k/s"); // +③
+ added += write_number ((long int) speed_batches, FALSE); // amount of batches
+ send_string ("x"); // +①
+ added += 9 + write_number ((long int) SPEED_COUNTDOWN, FALSE); // amount of batches
+ send_string ("keys"); // +④ = ⑨
+
+ speed_led ( (int) average_times_ten );// on report, show the average. speed_led divides by 10
+ }
+
+# endif
+
+ send_string (">"); // +1 = 5
+ if (sizecount_measure) sizecount_chars += added; // the user is expected to hit <backspace>
+ }else{
+ send_string ("<Soff>"); // indicates off
+ if (sizecount_measure) sizecount_chars += 5; // user: <backspace>, to take it down again
+ }
+
+ key_timer = timer_read ();
+
+ }else{ // key up
+ // This use of the key is for callibrating your colors; it is difficult otherwise to see.
+ // This is not part of normal usage, therefore it is kept bare bones to reduce firmware size
+ if (timer_elapsed (key_timer) > 999) { // held for one second
+ speed += 10;
+ write_number ((long int)(speed/10), FALSE); // writes the speed
+ speed_led (speed); // update led
+ }
+ }
+ break;
+
+ case COUNT_TOG: // Toggle start/stop text size measuring
+ if (record->event.pressed) { // key down
+
+ key_timer = timer_read ();
+
+ }else{ // up
+ if (timer_elapsed (key_timer) < 500) { // held for less than half a second (tapped)
+ if (sizecount_measure) {
+
+ sizecount_measure = FALSE;
+
+# ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_noeeprom (HSV_PURPLE); // indicates stop (color of _RAR)
+ isolate_rgblight_set ();
+# endif
+
+ }else{
+
+ sizecount_measure = TRUE; // start counting
+ sizecount_word = FALSE; // detect double blanks. leading blanks are not a word
+
+# ifdef RGBLIGHT_ENABLE
+ if (0 == sizecount_max) {
+ rgblight_sethsv_noeeprom (HSV_BLUE); // indicates start/activated, but only without maximum set
+ isolate_rgblight_set (); // .. if maximum set, led goes green to red.
+ }else{
+ rgblight_sethsv_noeeprom (HSV_GREEN); // indicates start/activated, but only without maximum set
+ isolate_rgblight_set (); // .. if maximum set, led goes green to red.
+ }
+# endif
+
+ }
+ }else{ // held longer
+ sizecount_menu = TRUE;
+ send_string ("<Nc|w>"); // Menu: N amount, c|w character|word counting. Input is a number then ‛c’ or ‛w’
+ sizecount_max = 0;
+ }
+ }
+ break;
+
+ case COUNT_NULL: // Sets the count to zero, which allows on/off to have a suspend/resume
+ if (record->event.pressed) { // key up
+ sizecount_blanks = 0; //
+ sizecount_chars = 0;
+
+# ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_noeeprom (HSV_CYAN); // indicates reset
+ isolate_rgblight_set ();
+# endif
+
+ }
+ break;
+
+ case COUNT_REPORT: // Report the current typing speed
+ if (record->event.pressed) {
+ // We assume the user is writing a report in its active document, and then likely deleting it.
+ short added = 0; // This counts how much characters the report adds into the user document.
+
+ if (sizecount_measure) {
+ send_string ("<"); // + 1 and ① characters (1 is one logical stream, ① another)
+ if (0 == sizecount_max) { // no size counting maximum, print both characters and words
+
+ added += write_number (sizecount_chars, FALSE); // returns how many characters where printed
+ send_string ("c;"); // + 2
+ added += write_number (sizecount_blanks, FALSE) + 5; // adds here
+ send_string ("w>"); // + 2 = 5
+
+ }else{ // Only show the one for which the maximum is set, don't throw off that mental focus
+ if (SIZECOUNT_WORD == sizecount_max_type ) {
+
+ added += write_number (sizecount_blanks, FALSE) + 3;
+ send_string ("w>"); // + ② = ③
+
+ }else{ // characters
+
+ added += write_number (sizecount_chars, FALSE) + 3; // returns how many characters where printed
+ send_string ("c>"); // + ② = ③
+
+ }
+ // add current maximum setting
+ send_string ("["); // + 1
+ added += write_number (sizecount_max, FALSE) + 3;
+ if (SIZECOUNT_WORD == sizecount_max_type) send_string ("w]"); // + 2
+ else send_string ("c]"); // + 2
+ }
+ sizecount_chars += added; // Account for the written characters in the report itself.
+
+ }else{ // no size counting, also here: keep the report terse
+ send_string ("<Coff>"); // indicates off (no need to add to count, since counting is off)
+ }
+ }
+ break;
+
+ // This allows the user to manually remove word counts, when he has deleted a word.
+ // This is not needed for character count, because <backspace> counts as minus.
+ case COUNT_WORDMIN: // Take down one word in the word-count.
+ if (record->event.pressed) { // down
+ key_timer = timer_read ();
+ }else{ // up
+ if (timer_elapsed (key_timer) < 500) { // held for less than half a second (tapped)
+ sizecount_blanks--;
+ }else{
+ sizecount_blanks -= 10;
+ }
+ }
+ break;
+
+ // Shift detection system.
+ // Disused because it turned out 'one shot' like Unicode input. Shift detection copied from.
+ // https://github.com/kyleterry/qmk_firmware/blob/master/quantum/quantum.c
+ //uint8_t shifted = get_mods() & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT));
+
+ // Crude but self contained in this source file shift detection.
+ // ... right shift
+ case KC_RSFT:
+ // + ... left shift
+ case KC_LSFT:
+ if (record->event.pressed) { // key down
+ shift_ison = 1; // shift depressed
+ }else{ // key up
+ shift_ison = 0; // shift released
+ }
+ // There are macros on Shift who also alter this variable.
+ break;
+
+ case OTHER_BASE: // Switching through the default/alternate BASE modes, and Descramble for that Dvorak compile
+ if (record->event.pressed) {
+ ;
+ }else{ // key up
+
+ // Cycles through the modes
+# ifdef DVORAK_DESCRAMBLE // version Dvorak+Dvorak-descramble has 3 modes
+ if (_NORMAL_ == alternate) {
+ alternate = _FULL_;// alternate layers
+ default_layer_set (_ALT_BASE_MASK); // This is needed only for a rare case,
+ // where _DEF_BASE and _ALT_BASE their layer switching keys don't line up,
+ // such as with Qwerty Base Arrow
+ } else if (_HALF_ == alternate) {
+ alternate = _NORMAL_;// normal layers
+ default_layer_set (_DEF_BASE_MASK);
+ }else{ // _FULL_ == alternate
+ alternate = _HALF_;// alternate layers, without 'descramble' recomputing Unicode
+ //default_layer_set (_ALT_BASE_MASK);
+ // it cycles, and this comes always after it was set _FULL_
+ }
+# else // Only switching the BASE layers between alternate and default
+
+ if (_NORMAL_ == alternate) {
+ alternate = _FULL_;// alternate base layers
+ default_layer_set (_ALT_BASE_MASK);
+ }else{
+ alternate = _NORMAL_;// default base layers
+ default_layer_set (_DEF_BASE_MASK);
+ }
+# endif
+
+ indicate_base (); // activate led change
+ }
+ break;
+
+# if defined(BASE_NUMPAD__ALT_BASE)
+
+ case OTHER_BASE_GO: // Switching through the default/alternate BASE modes, and Descramble for that Dvorak compile
+ if (record->event.pressed) {
+ ;
+ }else{ // key up
+
+ // Cycles through the modes
+# ifdef DVORAK_DESCRAMBLE // version Dvorak+Dvorak-descramble has 3 modes
+ if (_NORMAL_ == alternate) {
+ alternate = _FULL_;// alternate layers
+ default_layer_set (_ALT_BASE_MASK);
+ } else if (_HALF_ == alternate) {
+ alternate = _NORMAL_;// normal layers
+ default_layer_set (_DEF_BASE_MASK);
+ }else{ // _FULL_ == alternate
+ alternate = _HALF_;// alternate layers, without 'descramble' recomputing Unicode
+ //default_layer_set (_ALT_BASE_MASK);
+ // it cycles, and this comes always after it was set _FULL_
+ }
+# else // Only switching the BASE layers between alternate and default
+
+ if (_NORMAL_ == alternate) {
+ alternate = _FULL_;// alternate base layers
+ default_layer_set (_ALT_BASE_MASK);
+ }else{
+ alternate = _NORMAL_;// default base layers
+ default_layer_set (_DEF_BASE_MASK);
+ }
+# endif
+ // make the switch to the other Base layer
+ if (alternate) { //
+ layer_move (_ALT_BASE);
+ }else{
+ layer_move (_DEF_BASE);
+ }
+ }
+ break;
+# endif
+
+ // Switching to layers:
+
+ case CTO_BASE:
+ // User pressed upper/left button, while not on BASE layer: ‛escape’ from a layer to BASE layer.
+ // On BASE itself, that key is <Escape>.
+ if (record->event.pressed) { // key down
+ ;
+ }else{ // key up
+ if (alternate) { // go to the alternate version (bit of a hack maybe, but all alternate
+ // ... modes are non-zero)
+ layer_move (_ALT_BASE);
+ }else{
+ layer_move (_DEF_BASE);
+ }
+ }
+ break;
+
+ case CTO_NUMS: // activates number-symbols layer
+ if (record->event.pressed) { // key down
+ ;
+ }else{ // key up, so that upon key down the target layer isn't already activated, triggering that key on up
+ if (alternate) { // go to the alternate version
+ layer_move (_ALT_NSY);
+ }else{
+ layer_move (_DEF_NSY);
+ }
+ }
+ break;
+
+ case CTO_ACCE: // Unicode layer
+ if (record->event.pressed) { // key down
+ ;
+ }else{ // key up
+
+# ifndef REMOVE_ACC // This cuts out the whole _ACC layer.
+ layer_move (_ACC); // activates normal accented layer
+# else
+# ifdef _ACC_KEY_ALT_LAYER
+ layer_move (_ACC_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+
+ }
+ break;
+
+ case CTO_DRAW: // Unicode layer
+ if (record->event.pressed) { // key down
+ ;
+ }else{ // key up
+
+# ifndef REMOVE_DRA // This cuts out the whole _DRA layer.
+ layer_move (_DRA); // activates normal accented layer
+# else
+# ifdef _DRA_KEY_ALT_LAYER
+ layer_move (_DRA_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+ }
+ break;
+
+ // The below are a simulated LT(layer,kc), layer-tap.
+ // Double-tap-hold repeater functionality: not done.
+ // They switch what layer to use depending on 'alternate' variable
+ // Basically it starts the right layer on key down, goes back to base layer on key up,
+ // and throws in a keypress as well if tapped.
+ // It also integrates with DUO_HOLD, to reach the _BON layer.
+
+# ifndef CHOLTAP_ACCE_NOP // When this key has been eviscerated, this macro becomes useless
+ case CHOLTAP_ACCE: // Works with DUO_HOLD macro to activate one of several layers.
+ if (record->event.pressed) { // key down
+ key_timer = timer_read ();
+ isolate_trigger = TRUE; // keep track of whether another key gets pressed.
+
+ duo_press_acc_bon ++; // This signals to the two DUO_HOLD keys, whether a move to _BON is desired.
+
+ if (duo_press_nsy_dra) { // One or more of the DUO_HOLD layer keys was already pressed; move to _BON
+
+# ifndef REMOVE_BON // Removes this layer entirely, if set.
+ layer_move (_BON); // Bonus Unicode layer
+# else
+# ifdef _BON_KEY_ALT_LAYER
+ layer_move (_BON_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+
+ }else{ // pressed in isolation
+
+# ifndef REMOVE_ACC // This cuts out the whole _ACC layer.
+ layer_move (_ACC); // Accented layer
+# else
+# ifdef _ACC_KEY_ALT_LAYER
+ layer_move (_ACC_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+
+ }
+ }else{ // key up
+
+ duo_press_acc_bon --;
+
+ if (1 == duo_press_nsy_dra) { // One DUO_HOLD layer keys is still pressed; move to numbers/symbols
+
+ if (_FULL_ == alternate) {
+ layer_move (_ALT_NSY);
+ }else{
+ layer_move (_DEF_NSY);
+ }
+ }else if (2 == duo_press_nsy_dra) { // Two of the DUO_HOLD layer keys are still pressed: move to _DRA
+
+# ifndef REMOVE_DRA // This cuts out the whole _DRA layer.
+ layer_move (_DRA); // activates normal accented layer
+# else
+# ifdef _DRA_KEY_ALT_LAYER
+ layer_move (_DRA_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+
+ }else{
+ if (alternate) { // No _DEF_NSY layer keys remain pressed; Go back to base layer
+ layer_move (_ALT_BASE);
+ }else{
+ layer_move (_DEF_BASE);
+ }
+ }
+
+ // Pressed in isolation
+ if (isolate_trigger)
+ {
+ if (timer_elapsed (key_timer) <= TAPPING_TERM_HOLTAP) { // tapped
+ SEND_STRING (SS_TAP (X_DEL));
+ }
+ }
+ }
+ break;
+# endif // CHOLTAP_ACCE_NOP
+
+ case CHOLTAP_LAYR: //to _RAR on hold, otherwise a keycode
+ if (record->event.pressed) { // key down
+ key_timer = timer_read ();
+ isolate_trigger = TRUE; // keep track of whether another key gets pressed.
+
+# ifdef BASE_RIGHT_ALT
+ SEND_STRING (SS_DOWN (X_RALT));
+# else
+ layer_move (_RAR); // activates descrambled drawings layer
+# endif
+
+ }else{ // key up
+ // Go back to base layer
+ if (speed_measure) speed_led (speed); // The _RAR layer overwrites the middle led,
+ //.. for use with alternate _HALF_ led colors (middle); thus needs to be set back to speed
+ // led color upon leaving.
+
+# ifdef BASE_RIGHT_ALT
+ SEND_STRING (SS_UP (X_RALT));
+# else
+ if (alternate) {
+ layer_move (_ALT_BASE);
+ }else{
+ layer_move (_DEF_BASE);
+ }
+# endif
+
+ // Pressed in isolation
+ if (isolate_trigger)
+ {
+ if (timer_elapsed (key_timer) <= TAPPING_TERM_HOLTAP) { // tapped
+ SEND_STRING (SS_TAP (X_RIGHT));
+ }
+ }
+ }
+ break;
+
+# ifndef DUO_HOLD_BASIC
+ // This is the normal 'big' version, dealing with switching between _DEF_NSY/_ALT_NSY, _ACC, _DRA and _BON, in
+ // .. conjunction with the CHOLTAP_ACCE macro.
+ case DUO_HOLD: // The macro around the split space-bar. Both keys come to this macro.
+ if (record->event.pressed) { // key down
+
+ duo_press_nsy_dra ++; // simple way to keep track of how many are pressed
+
+ if (duo_press_acc_bon){ // Preceded by holding the _ACC/_BON layer switch key: move to _BON
+
+# ifndef REMOVE_BON // Removes this layer entirely, if set.
+ layer_move (_BON); // Bonus Unicode layer
+# else
+# ifdef _BON_KEY_ALT_LAYER
+ layer_move (_BON_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+
+ }else if (1 == duo_press_nsy_dra) { // This is the first press of either of the DUO_HOLD keys on BASE
+
+ if (_NORMAL_ == alternate) {
+ layer_move (_DEF_NSY);
+ }else{
+ layer_move (_ALT_NSY);
+ }
+ }
+ else if (2 == duo_press_nsy_dra) { // both are pressed
+
+# ifndef REMOVE_DRA // This cuts out the whole _DRA layer.
+ layer_move (_DRA); // activates normal accented layer
+# else
+# ifdef _DRA_KEY_ALT_LAYER
+ layer_move (_DRA_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif
+ }
+
+ }else{ // key up
+
+ duo_press_nsy_dra --;
+
+ if (1 == duo_press_nsy_dra) {
+ if (duo_press_acc_bon){ // Still holding the _ACC/_BON layer switch key, and one DUO_HOLD keys
+
+# ifndef REMOVE_BON // Removes this layer entirely, if set.
+ layer_move (_BON); // Bonus Unicode layer
+# else
+# ifdef _BON_KEY_ALT_LAYER
+ layer_move (_BON_KEY_ALT_LAYER); // Alternative layer user configuration
+# endif
+# endif