qmk-dactyl-manuform-a/keyboards/thevankeyboards/minivan/keymaps/josjoha/unicode_macros.c

2350 lines
80 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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"
// 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_LCTRL) SS_DOWN(X_LSHIFT) "f" SS_UP(X_LSHIFT) SS_UP(X_LCTRL) ); // 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
};
// 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_LSHIFT)|MOD_BIT(KC_RSHIFT));
// 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
}else{
if (_NORMAL_ == alternate) {
layer_move (_DEF_NSY);
}else{
layer_move (_ALT_NSY);
}
}
}
else { // Has to be zero.
if (duo_press_acc_bon){ // Still holding the _ACC/_BON layer switch key, but zero DUO_HOLD layer keys
# 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{
if (alternate) { // Back to letters
layer_move (_ALT_BASE);
}else{
layer_move (_DEF_BASE);
}
}
}
}
break;
# else
// This is the eviscerated version, compiled when all Unicode layers _ACC, _DRA, _BON are cut, and layer key
// .. combinations have not been assigned other uses.
case DUO_HOLD: // The macro for the keys 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 (0 != duo_press_nsy_dra) { // One or more of the DUO_HOLD keys is pressed
if (_NORMAL_ == alternate) {
layer_move (_DEF_NSY);
}else{
layer_move (_ALT_NSY);
}
}
}else{ // key up
duo_press_nsy_dra --;
if (0 == duo_press_nsy_dra) { // None of the DUO_HOLD keys remains pressed
if (alternate) { // Back to letters
layer_move (_ALT_BASE);
}else{
layer_move (_DEF_BASE);
}
}
}
break;
# endif // DUO_HOLD_BASIC
// When held the key is shift. When tapped it is computed if the tap is short enough,
// and if no other key was pressed, in which case: right-shift-up is a toggle to the _FUN layer.
// The timing is meant to be able to undo an erroneous shift press just by holding longer,
// and the test if another key was pressed is to prevent an erroneous detection when typing
// very fast.
// The reason for this on shift is to isolate GUI, where _FUN was previously more easily
// located. No alternative tapping function with GUI because some systems do not treat GUI
// purely as a modifier it seems. Since it is a toggle anyway, _FUN can fit away from the thumb-hold row.
case CHOLTAP_RSHFT: // When tapped it toggles the _FUN layer, when held it is Shift
if (record->event.pressed) { // key down
SEND_STRING (SS_DOWN (X_RSFT));
shift_ison = 1; // shift depressed
key_timer = timer_read ();
isolate_trigger = TRUE; // keep track of whether another key gets pressed until key-up
}else{ // key up
SEND_STRING (SS_UP (X_RSFT));
shift_ison = 0; // shift released
if (isolate_trigger) { // no other key was hit since key down
// Held medium long: _PAD, long: _MOV.
// The reason to have a switch to _MOV on the left hand, is to be able to reach arrows on a toggle,
// all by the left hand, when the right hand is on the mouse.
if ((timer_elapsed (key_timer) <= 200)) { // tapped short (milliseconds)
# ifndef SWITCH_RSHIFT_FUN_RAR // user config to reverse what this key its timing toggles to
layer_move (_FUN); // activates function layer as a toggle
} else { // held for longer
layer_move (_RAR);
# else
layer_move (_RAR); // activates function layer as a toggle
} else { // held for longer
layer_move (_FUN);
# endif
}
}
}
break;
// The left-shift version of the above keycode. User can configure something (_PAD is default)
case CHOLTAP_LSHFT: // When tapped it toggles the _MOV layer, when held it is Shift
// _RAR was the first idea, but some of its keys are too dangerous regarding accidents.
if (record->event.pressed) { // key down
SEND_STRING (SS_DOWN (X_LSFT));
shift_ison = 1; // shift depressed
# ifndef REMOVE_PAD // The _PAD layer exists, we will use a timer …
key_timer = timer_read ();
# endif
// This variable is re-used, for speed and because using both shifts is useless,
// .. thus very rare, and also not a usage problem if it occured.
isolate_trigger = TRUE; // keep track of whether another key gets pressed.
}else{ // key up
SEND_STRING (SS_UP (X_LSFT));
shift_ison = 0; // shift released
if (isolate_trigger) { // no other key was hit since key down
# ifndef REMOVE_PAD // The _PAD layer exists, differentiate meaning by timer.
// Held medium long: _PAD, long: _MOV.
// The reason to have a switch to _MOV on the left hand, is to be able to reach arrows on a toggle,
// all by the left hand, when the right hand is on the mouse.
if ((timer_elapsed (key_timer) <= 200)) { // tapped medium-long (milliseconds)
# ifndef SWITCH_LSHIFT_PAD_MOV // user config to reverse what this key its timing toggles to
layer_move (_PAD);
} else { // held for longer
layer_move (_MOV);
# else
layer_move (_MOV);
} else { // held for longer
layer_move (_PAD);
# endif
}
# else // _PAD layer was eviscerated
layer_move (_MOV);
# endif
}
}
break;
/*
case RSFT_TILDE:
if (record->event.pressed) { // key down
SEND_STRING (SS_DOWN (X_RSFT));
shift_ison = 1; // shift depressed
key_timer = timer_read ();
isolate_trigger = TRUE; // keep track of whether another key gets pressed until key-up
}else{ // key up
SEND_STRING (SS_UP (X_RSFT));
shift_ison = 0; // shift released
if (isolate_trigger) { // no other key was hit since key down
// Held medium long: _PAD, long: _MOV.
// The reason to have a switch to _MOV on the left hand, is to be able to reach arrows on a toggle,
// all by the left hand, when the right hand is on the mouse.
if ((timer_elapsed (key_timer) <= 200)) { // tapped short (milliseconds)
SEND_STRING ("~");
}
}
}
break;
*/
case RSFT_TILDE: // firmware size optimization, saves 36 bytes
case LSFT_DASH:
if (record->event.pressed) { // key down
if (RSFT_TILDE == keycode) { // this is probably not needed, both can be left or right shift
SEND_STRING (SS_DOWN (X_RSFT));
}else{
SEND_STRING (SS_DOWN (X_LSFT));
}
shift_ison = 1; // shift depressed
key_timer = timer_read ();
isolate_trigger = TRUE; // keep track of whether another key gets pressed until key-up
}else{ // key up
if (RSFT_TILDE == keycode) {
SEND_STRING (SS_UP (X_RSFT));
}else{
SEND_STRING (SS_UP (X_LSFT));
}
shift_ison = 0; // shift released
if (isolate_trigger) { // no other key was hit since key down
// Held medium long: _PAD, long: _MOV.
// The reason to have a switch to _MOV on the left hand, is to be able to reach arrows on a toggle,
// all by the left hand, when the right hand is on the mouse.
if ((timer_elapsed (key_timer) <= 200)) { // tapped short (milliseconds)
if (RSFT_TILDE == keycode) {
SEND_STRING ("~");
}else{
SEND_STRING ("-");
}
}
}
}
break;
case _FUN_STAY: // toggles if the f-keys return _FUN layer to BASE after one press
if (record->event.pressed) { // key down
if (_fun_stay == FALSE) {
_fun_stay = TRUE;
}else{
_fun_stay = FALSE;
}
indicate_fun_stay (); // leds
}
break;
# ifdef MOREKEY2_ARROW_CLUSTER
case _MOV_UP: // To be sure it activates on up key, and not already has triggered the _MOV layer during up-key.
if (record->event.pressed) { // key down
;
}else{ // key up
layer_move (_MOV);
}
break;
# endif
// These keys are so disruptive on an erroneous key press, that they are behind a shift lock.
// When used unshifted, they print a memory aid string: their name.
case C_KC_PWR:
if (record->event.pressed) { // key down
if (shift_ison) {
SEND_STRING (SS_TAP (X_PWR));
}else{
SEND_STRING ("<POWER>"); // Memory aid
}
}
break;
case C_KC_WAKE:
if (record->event.pressed) { // key down
if (shift_ison) {
SEND_STRING (SS_TAP (X_WAKE));
}else{
SEND_STRING ("<WAKE>"); // Memory aid
}
}
break;
case C_KC_SLEP:
if (record->event.pressed) { // key down
if (shift_ison) {
SEND_STRING (SS_TAP (X_SLEP));
}else{
SEND_STRING ("<SLEEP>"); // Memory aid
}
}
break;
case C_KC_PAUS:
if (record->event.pressed) { // key down
if (shift_ison) {
SEND_STRING (SS_TAP (X_PAUS));
}else{
SEND_STRING ("<PAUSE>"); // Memory aid
}
}
break;
case LEDS_ON: // Toggles left/right leds on or off
if (record->event.pressed) { // key down
if (leds_on == FALSE) {
leds_on = TRUE;
}else{
leds_on = FALSE;
}
}
break;
# ifdef LEDS_OFF_BASE_DEF // This messes with led effect on/off, so we need to track the state of this setting now.
case RGBTOG_: // Toggles middle led on or off
if (record->event.pressed) { // key down
if (led_middle_on == FALSE) {
led_middle_on = TRUE;
rgblight_enable_noeeprom ();
}else{
led_middle_on = FALSE;
rgblight_disable_noeeprom ();
}
}
break;
# endif
// Some keycodes treated specially for the two counting systems (speed, text size)
// Deletions:
case KC_BSPC: // non-counting speed
case KC_DEL: // non-counting speed
if (record->event.pressed) { // key down
if (sizecount_measure) sizecount_chars--; // minus count for text size (removed a character)
}
break;
// White space for counting words
case LT__MOV__KC_ENT: // We want to count the <enter> for word-counts, sadly this looses the key repetition of LT(…)
if (record->event.pressed) { // key down
key_timer = timer_read ();
layer_move (_MOV);
}else{ // key up
if (alternate) { // Back to letters
layer_move (_ALT_BASE);
}else{
layer_move (_DEF_BASE);
}
if (timer_elapsed (key_timer) <= TAPPING_TERM_HOLTAP) { // tapped
send_string ("\n");
if (sizecount_measure) {
sizecount_chars++;
if (sizecount_word) sizecount_blanks++; // count a word
sizecount_word = FALSE; // don't count immediately next blank as a word
}
}
}
break;
// Word counting
case KC_SPC:
if (record->event.pressed) { // key down
if (sizecount_measure) {
sizecount_chars++;
if (sizecount_word) sizecount_blanks++; // count a word
sizecount_word = FALSE; // don't count immediately next blank as a word
}
}
break;
// These are excluded from counting for text size/speed, they prevent the “default“ in the case statement to execute.
case KC_LEFT:
case KC_UP:
case KC_DOWN:
case KC_RIGHT:
case KC_PGUP:
case KC_PGDN:
case KC_HOME:
case KC_END:
case LALT_T ( KC_LEFT ):
if (speed_measure) speed_countdown++; // Navigation could be integral to someone typing and correcting mistakes,
// but those keys don't add any text.
// Mouse movement is discounted in both speed and text size
case KC_WH_L:
case KC_WH_D:
case KC_WH_U:
case KC_WH_R:
case KC_MS_L:
case KC_MS_D:
case KC_MS_U:
case KC_MS_R:
case KC_BTN1:
case KC_BTN5:
case KC_BTN4:
case KC_BTN3:
case KC_BTN2:
break;
default: // If something else, it is a speed- and text measurement counting key
if (record->event.pressed) { // key down
if (speed_measure) speed_countdown--;
if (sizecount_measure) sizecount_chars++;
}
}
// If speed measuring is on, count keypresses
// The idea is to more/less follow common standard with typing speed counting: shift is not counted,
// layer-switching or its equivalent is neither. Arrows are not counted.
if (speed_measure) {
if (record->event.pressed) { // key down
if (0 >= speed_countdown) {
// key presses per second, but times ten for added precision of one digit
// This calculation quickly looses precision if not calculated with high enough numbers, but low enough to fit.
speed = (int) ( (SPEED_COUNTDOWN * 1000 ) / ((timer_read32 () - speed_counttime)/10) ); // counts time in ms
speed_led (speed); // updates led
// record for average
if (0 < (speed/10)) { // ignore 0 k/s batches, we assume the typer took a break
speed_batches++;
speed_add += speed;
}
// reset for next batch
speed_countdown = SPEED_COUNTDOWN; // reset
speed_counttime = timer_read32 ();
}
}
}
// For word-counting, ignore double blanks
if (sizecount_measure) {
if (record->event.pressed) {
bool within = TRUE; // When text size is maximized, this indicates we are not yet at that maximum.
# ifdef RGBLIGHT_ENABLE
unsigned short size_fraction = 0; // Used to compute led color as a fraction of a set maximum which is already typed.
# endif
// ignoring blanks wordcount
if ((keycode != KC_SPC)
&&
(keycode != KC_TAB) // This is ok, but a tab on BASE layer combo with Control, is not caught by this XXX (problem ignored, I never write Tab in a text worth counting)
&&
(keycode != LT__MOV__KC_ENT)
&&
(keycode != LT__MOV__KC_ENT)) {
sizecount_word = TRUE; // current key is not a blank, so we set this trigger for next key press
}
// computing maximum count effects: leds
if (0 != sizecount_max) {
if (SIZECOUNT_WORD == sizecount_max_type) {
if (sizecount_blanks > sizecount_max) within = FALSE;
}else{ // count chars
if (sizecount_chars > sizecount_max) within = FALSE;
}
// led colors
if (within) { // green to red middle led
# ifdef RGBLIGHT_ENABLE
if (SIZECOUNT_WORD == sizecount_max_type) {
size_fraction = (90 * sizecount_blanks) / sizecount_max;
}else{
size_fraction = (90 * sizecount_chars) / sizecount_max;
}
rgblight_sethsv_noeeprom (90 - size_fraction , 255, 255); // green to red, full saturation, full lit
# endif
}else{ // when at or over the limit: blink led red/white
if ((KC_BSPC != keycode)
&& (KC_DEL != keycode) // User already deleting, doubling is confusing
&& (CHOLTAP_LAYR != keycode)) { // This brings up the _RAR layer, to access the Count settings.
SEND_STRING (SS_TAP(X_BSPC)); // refuses to type further, the user is stopped from typing to make it obvious
}
# ifdef RGBLIGHT_ENABLE
if (sizecount_chars & 0x1) { // flip by every keypress
rgblight_sethsv_noeeprom (HSV_RED);
}else{
rgblight_sethsv_noeeprom (HSV_WHITE);
}
# endif
}
# ifdef RGBLIGHT_ENABLE
rgblight_set (); // only center led is altered, no need to go through isolate_rgblight_set()
# endif
}
}
}
// Simple macros, printing a character.
switch (keycode) {
/* _ACC layer definitions. */
// ------------------------- row 4
# ifndef REMOVE_ACC // This cuts out the whole _ACC layer.
case XP_ACC_AA: // because a
if (record->event.pressed) { // key down
unicode_hex2output (CAL_ACU, CAU_ACU);// á Á
}
break;
case XP_ACC_AB: // because o (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (COL_ACU, COU_ACU);// ó Ó
}
break;
case XP_ACC_AC: // because e (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CEL_ACU, CEU_ACU);// é É
}
break;
case XP_ACC_AD: // because u (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CUL_ACU, CUU_ACU);// ú Ú
}
break;
case XP_ACC_AE: // because i (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CIL_ACU, CIU_ACU);// í Í
}
break;
case XP_ACC_AF: // Because near Y
if (record->event.pressed) { // key down
unicode_hex2output (CYL_ACU, CYU_ACU);// ý Ý
}
break;
case XP_ACC_AG: // because near Y
if (record->event.pressed) { // key down
unicode_hex2output (CIJL_BI, CIJU_BI);// ij IJ
}
break;
case XP_ACC_AH: // because c (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CCL_CDL, CCU_CDL);// ç Ç
}
break;
case XP_ACC_AI: // because ring-finger left is o (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (COL_STK, COU_STK);// ø Ø
}
break;
case XP_ACC_AJ: // because pinky finger left is a
if (record->event.pressed) { // key down
unicode_hex2output (CAL_RNG, CAU_RNG);// å Å
}
break;
// ------------------------- row 3
case XP_ACC_BA: // because a
if (record->event.pressed) { // key down
unicode_hex2output (CAL_DIA, CAU_DIA);// ä Ä
}
break;
case XP_ACC_BB: // because o (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (COL_DIA, COU_DIA);// ö Ö
}
break;
case XP_ACC_BC: // because e (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CEL_DIA, CEU_DIA);// ë Ë
}
break;
case XP_ACC_BD: // because u (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CUL_DIA, CUU_DIA);// ü Ü
}
break;
case XP_ACC_BE: // because i
if (record->event.pressed) { // key down
unicode_hex2output (CIL_DIA, CIU_DIA);// ï Ï
}
break;
case XP_ACC_BF: // because near y
if (record->event.pressed) { // key down
unicode_hex2output (CYL_DIA, CYU_DIA);// ÿ Ÿ
}
break;
case XP_ACC_BG: // because vague logic about other hand having ae near on similar fingers
if (record->event.pressed) { // key down
unicode_hex2output (COEL_BI, COEU_BI);// œ Œ
}
break;
case XP_ACC_BH: // because near œ, toward the side of a (pinky)
if (record->event.pressed) { // key down
unicode_hex2output (CAEL_BI, CAEU_BI);// æ Æ
}
break;
case XP_ACC_BI: // because n
if (record->event.pressed) { // key down
unicode_hex2output (CNL_TLD, CNU_TLD);// ñ Ñ
}
break;
case XP_ACC_BJ: // because s
if (record->event.pressed) { // key down
unicode_hex2output_single (CSL_SHP);// ß ß
}
break;
case XP_ACC_BK: // because roughly the location on French keyboard
if (record->event.pressed) { // key down
unicode_hex2output_single (C_MU_L);// μ
}
break;
// ------------------------- row 2
case XP_ACC_CA: // because a
if (record->event.pressed) { // key down
unicode_hex2output (CAL_GRA, CAU_GRA);//à À
}
break;
case XP_ACC_CB: // because o (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (COL_GRA, COU_GRA);// ò Ò
}
break;
case XP_ACC_CC: // because e (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CEL_GRA, CEU_GRA);// è È
}
break;
case XP_ACC_CD: // because u (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CUL_GRA, CUU_GRA);// ù Ù
}
break;
case XP_ACC_CE: // because i (Dvorak)
if (record->event.pressed) { // key down
unicode_hex2output (CIL_GRA, CIU_GRA);// ì Ì
}
break;
case XP_ACC_CF: // because other hand same finger i
if (record->event.pressed) { // key down
unicode_hex2output (CIL_CAR, CIU_CAR);// î Î
}
break;
case XP_ACC_CG: // because other hand same finger u
if (record->event.pressed) { // key down
unicode_hex2output (CUL_CAR, CUU_CAR);// û Û
}
break;
case XP_ACC_CH: // because other hand same finger e
if (record->event.pressed) { // key down
unicode_hex2output (CEL_CAR, CEU_CAR);// ê Ê
}
break;
case XP_ACC_CI: // because other hand same finger o
if (record->event.pressed) { // key down
unicode_hex2output (COL_CAR, COU_CAR);// ô Ô
}
break;
case XP_ACC_CJ: // because other hand same finger a
if (record->event.pressed) { // key down
unicode_hex2output (CAL_CAR, CAU_CAR);// â Â
}
break;
# endif // REMOVE_ACC // This cuts out the whole _ACC layer.
/* _DRA layer definitions. */
# ifndef REMOVE_DRA // This cuts out the whole _DRA layer
// ------------------------- row 4
case XP_DRA_AA: // because '", the opening „“ at the open of the keyboard (left/up)
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_DQUHR, CS_DQUL);// “ „
# else
unicode_hex2output_single (CS_DQUHR);// “
# endif
}
break;
case XP_DRA_AB: // because to the right of opening “, ≤ on <
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_DQUH, CS_ELTHAN);// ” ≤
# else
unicode_hex2output_single (CS_DQUH);// ”
# endif
}
break;
case XP_DRA_AC: // because this is where the £ is on an English keyboard, on 'any' money symbols ¤; ≥ on >
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_POUND, CS_EGTHAN);// £ ≥
# else
unicode_hex2output_single (CS_POUND);// £
# endif
}
break;
case XP_DRA_AD: // because ∅ looks like ¢, and ¢ (cent) is on $ (money) ?
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_NONE, CS_CENT);// ∅ ¢
# endif
}
break;
case XP_DRA_AE: // because percentages %‰‱ and money ƒ are numerical ?
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_PLMI, CS_LGULDEN);// ± ƒ
# else
unicode_hex2output_single (CS_PLMI);// ±
# endif
}
break;
case XP_DRA_AF: // Because left of 🙂, on top of ★
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_FLEUR, CS_HEART);// ❦ ♥
# else
unicode_hex2output_single (CS_HEART);// ♥
# endif
}
break;
case XP_DRA_AG: // because 😊 ⍨
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_SMIL, CS_SAD_);// 🙂 🙁
# endif
}
break;
case XP_DRA_AH: // because «no reason», next to 😊 (emoticons)
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_THUP, CS_THDN);// 👍 👎
# endif
}
break;
case XP_DRA_AI: // because (
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_OPSUP, CS_OPSUB);// ⁽ ₍
# endif
}
break;
case XP_DRA_AJ: // because )
if (record->event.pressed) { // key down
# ifdef FULL_DRA_4THROW
unicode_hex2output (CS_CPSUP, CS_CPSUB);// ⁾ ₎
# endif
}
break;
// ------------------------- row 3
case XP_DRA_BA: // because 1
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_1SUP, CN_1SUB);// ¹ ₁
# else
unicode_hex2output_single (CN_1SUP);// ¹
# endif
}
break;
case XP_DRA_BB: // because 2
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_2SUP, CN_2SUB);// ² ₂
# else
unicode_hex2output_single (CN_2SUP);// ²
# endif
}
break;
case XP_DRA_BC: // because 3
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_3SUP, CN_3SUB);// ³ ₃
# else
unicode_hex2output_single (CN_3SUP);// ³
# endif
}
break;
case XP_DRA_BD: // because 4
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_4SUP, CN_4SUB);// ⁴ ₄
# else
unicode_hex2output_single (CN_4SUP);// ⁴
# endif
}
break;
case XP_DRA_BE: // because 5
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_5SUP, CN_5SUB);// ⁵ ₅
# else
unicode_hex2output_single (CN_5SUP);// ⁵
# endif
}
break;
case XP_DRA_BF: // because 6
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_6SUP, CN_6SUB);// ⁶ ₆
# else
unicode_hex2output_single (CN_6SUP);// ⁶
# endif
}
break;
case XP_DRA_BG: // because 7
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_7SUP, CN_7SUB);// ⁷ ₇
# else
unicode_hex2output_single (CN_7SUP);// ⁷
# endif
}
break;
case XP_DRA_BH: // because 8
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_8SUP, CN_8SUB);// ⁸ ₈
# else
unicode_hex2output_single (CN_8SUP);// ⁸
# endif
}
break;
case XP_DRA_BI: // because 9
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_9SUP, CN_9SUB);// ⁹ ₉
# else
unicode_hex2output_single (CN_9SUP);// ⁹
# endif
}
break;
case XP_DRA_BJ: // because 0
if (record->event.pressed) { // key down
# ifdef SUB_SCRIPT_NUMS
unicode_hex2output (CN_0SUP, CN_0SUB);// ⁰ ₀
# else
unicode_hex2output_single (CN_0SUP);// ⁰
# endif
}
break;
// ------------------------- row 2
case XP_DRA_CA: // because [
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_OCBRA, CB_HHORI);// 「 ━
# else
unicode_hex2output_single (CB_HHORI);// ━
# endif
}
break;
case XP_DRA_CB: // because ]
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_CCBRA, CB_LHORI);// 」 ─
# else
unicode_hex2output_single (CB_LHORI);// ─
# endif
}
break;
case XP_DRA_CC: // because «no reason»
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_DEGREE, CS_CIRCLE);// °
# else
unicode_hex2output_single (CS_DEGREE);// °
# endif
}
break;
case XP_DRA_CD: // because «no reason»
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_BULLET, CS_PARA);// • §
# else
unicode_hex2output_single (CS_BULLET);// •
# endif
}
break;
case XP_DRA_CE: // because «no reason»
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_ELLIPS, CS_MIDDOT);// … ·
# else
unicode_hex2output_single (CS_ELLIPS);// …
# endif
}
break;
case XP_DRA_CF: // because «no reason» (+ resembles ‛☒’ ?), ✗
if (record->event.pressed) { // key down
unicode_hex2output (CS_CHECK_B, CS_CHECK_N);// ☐ ☒
}
break;
# endif
// This one must be included for _RAR layer
case XP_DRA_CG: // because next to ✗ ☐ ☒
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_CHECK_Y, CS_CHECK_H);// ☑ 🗹
# else
unicode_hex2output_single (CS_CHECK_Y);// ☑
# endif
}
break;
# ifndef REMOVE_DRA // This cuts out the whole _DRA layer
case XP_DRA_CH: // because ?
if (record->event.pressed) { // key down
unicode_hex2output (CQU_INV, CEX_INV);// ¿ ¡
}
break;
case XP_DRA_CI: // because {, ┄ «no reason» (opposite side from ━)
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_ODABRA, CB_LHORID);// 《 ┄
# else
unicode_hex2output_single (CB_LHORID);// ┄
# endif
}
break;
case XP_DRA_CJ: // because }, ┅ «no reason» (opposite side from ─)
if (record->event.pressed) { // key down
# ifdef FULL_DRA_2NDROW
unicode_hex2output (CS_CDABRA, CB_HHORID);// 》 ┅
# else
unicode_hex2output_single (CB_HHORID);// ┅
# endif
}
break;
# endif // REMOVE_DRA
/* _BON layer definitions. Due to running out of X(…), XP(…) space.*/
// ------------------------- row 4
# ifndef REMOVE_BON // Removes this layer entirely, if set.
case XP_BON_AA: // because of ' "
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output (CS_HQUOSB, CS_USER_DEFINED);// 🛠
# else
unicode_hex2output_single (CS_HQUOSB);//
# endif
}
break;
case XP_BON_AB: // because of <, because "WASD" on _MOV
// 0x2019, single quotation mark:
// 0x2B06 arrow up: ⬆
if (record->event.pressed) { // key down
unicode_hex2output (CS_HQUOSE, CS_ARR_UP);//
}
break;
case XP_BON_AC: // because of >
// 0x00A4 any currency symbol: ¤
// 0x1F12F Copyleft: 🄯 (means free to copy, see also © for not free to copy.)
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output (CS_CURREN, CS_COPYL);// ¤ 🄯
# else
unicode_hex2output_single (CS_CURREN);// ¤
# endif
}
break;
case XP_BON_AD: // because $ and ¢ can be about money, and money is often added together
// because … no reason, left over space.
// 0x2211, summation: ∑
// 0xA9, copyright: ©
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output (CS_CUMMU, CS_COPY);// ∑ ©
# else
unicode_hex2output_single (CS_CUMMU);// ∑
# endif
}
break;
case XP_BON_AE: // because % for percent
// 0x2030,// promille: ‰
// 0x2031,// pro ten thousandth: ‱
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output (CS_PROM, CS_PROTT);// ‰ ‱
# else
unicode_hex2output_single (CS_PROM);// ‰
# endif
}
break;
case XP_BON_AF: // Because ♥ is a star, ❦ and stars can be used as bullet points
// 0x2605, star: ★
// 0x066D, star small: ٭
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output (CS_STARB, CS_STARL);// ★ ٭
# else
unicode_hex2output_single (CS_STARB);// ★
# endif
}
break;
case XP_BON_AG: // because of 🙂 🙁
// 0x1f60A,// <smile> ^^ 😊
// 0x2368,// "Squiggly" face <sad> ⍨
# ifdef FULL_BON_4THROW
if (record->event.pressed) { // key down
unicode_hex2output (CS_SMILP, CS_SQUIG);// 😊 ⍨
}
# endif
break;
case XP_BON_AH: // because * also for multiply, because asterisk *
// 0x00D7,// multiply: ×
// 0x20F0 high asterisk: ⃰(this thing seems to behave a bit weird in vim(1) or terminal)
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output (CS_MULT, CS_ASTL);// ×
# else
unicode_hex2output_single (CS_MULT);// ×
# endif
}
break;
case XP_BON_AI: // because ø sort of seems to divide something, and √ also does that, and close to ⁻⁺ (exponential)
// 0x221A,// square root: √
if (record->event.pressed) { // key down
# ifdef FULL_BON_4THROW
unicode_hex2output_single (CS_SQRT);// √
# endif
}
break;
case XP_BON_AJ: // because å points in the circle where this exponential minus goes, and it is right/"up" on the board
// because ⁻⁺ belong together
// 0x207B,// exponential minus sign: ⁻
// 0x207A,// exponential plus: ⁺
# ifdef FULL_BON_4THROW
if (record->event.pressed) { // key down
unicode_hex2output (CS_EXPMIN, CS_EXPPLS);// ⁻ ⁺
}
# endif
break;
// ------------------------- row 3
case XP_BON_BA: // because 1, because "WASD" on _MOV (depending on setup)
// 0x2460, "1" : ①
// 0x2B05, arrow left: ⬅
if (record->event.pressed) { // key down
unicode_hex2output (CN_1CIRC, CS_ARR_LE);// ① ⬅
}
break;
case XP_BON_BB: // because 2, because "WASD" on _MOV (depending)
// 0x2461, "2" : ②
// 0x2B07, arrow down: ⬇
if (record->event.pressed) { // key down
unicode_hex2output (CN_2CIRC, CS_ARR_DN);// ② ⬇
}
break;
case XP_BON_BC: // because 3, because "WASD" on _MOV (depending)
// 0x2462, "3" : ③
// 0x27A1, arrow right: ➡
if (record->event.pressed) { // key down
unicode_hex2output (CN_3CIRC, CS_ARR_RI);// ③ ➡
}
break;
case XP_BON_BD: // because 4, because ┏ forms a box with the other box drawings to the right/down
// 0x2463, "4" : ④
// 0x250F, box drawing heavy: ┏
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CN_4CIRC, CB_C_RIDN);// ④ ┏
# else
unicode_hex2output_single (CN_4CIRC);// ④
# endif
}
break;
case XP_BON_BE: // because 5, because ┓ forms a box
// 0x2513,box drawing heavy: ┓
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CN_5CIRC, CB_C_LEDN);// ⑤ ┓
# else
unicode_hex2output_single (CN_5CIRC);// ⑤
# endif
}
break;
case XP_BON_BF: // because 6, because ┃ continues box block
// 0x2465, "6" : ⑥
// 0x2503, box drawing heavy: ┃
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CN_6CIRC, CB_VE);// ⑥ ┃
# else
unicode_hex2output_single (CN_6CIRC);// ⑥
# endif
}
break;
case XP_BON_BG: // because 7, because ┇ continues box block
// 0x2466, "7" : ⑦
// 0x2507, dotted line verticle (heavy): ┇
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CN_7CIRC, CB_VE_DOT);// ⑦ ┇
# else
unicode_hex2output_single (CN_7CIRC);// ⑦
# endif
}
break;
case XP_BON_BH: // because 8, ╋ because 8 also has a crossing line in it
// 0x254B, crossing lines: ╋
// 0x2467, "8" : ⑨
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CN_8CIRC, CB_VE_BI);// ⑧ ╋
# else
unicode_hex2output_single (CN_8CIRC);// ⑧
# endif
}
break;
case XP_BON_BI: // because 9
// 0x2468, "9" : ⑨
// 0x2513,box drawing heavy: ┓
if (record->event.pressed) { // key down
unicode_hex2output_single (CN_9CIRC);// ⑨
}
break;
case XP_BON_BJ: // because 0, because a "0" can also be a symbol for infinity, round & round
// 0x24EA, "0" : ⓪
// 0x221E,// infinity:∞
if (record->event.pressed) { // key down
unicode_hex2output (CN_0CIRC, CS_INFIN);// ⓪ ∞
}
break;
case XP_BON_BK: // because -, because ~
// 0x2014,// dash: — (might not render differently than a hyphen - in some applications. Dash is longer).
// 0x2248,// about equal to: ≈
if (record->event.pressed) { // key down
unicode_hex2output (CS_DASH, CS_ABOUT);// — ≈
}
break;
// ------------------------- row 2
case XP_BON_CA: // because 1 above, because 「[
// 0x2039, opening single corner quotation:
if (record->event.pressed) { // key down
unicode_hex2output_single (CS_GUILSLE);//
}
break;
case XP_BON_CB: // because 2 above, because 」]
// 0x203A, closing sinle corner quotation:
if (record->event.pressed) { // key down
unicode_hex2output_single (CS_GUILSRI);//
}
break;
case XP_BON_CC: // because 3 above, because / (division)
// 0x00F7,// division: ÷
if (record->event.pressed) { // key down
unicode_hex2output_single (CS_DIVI);// ÷
}
break;
case XP_BON_CD: // because 4 above, ┗ because forms box
// 0x261E, hand bullet point: ☞
// 0x2517, box drawing heavy: ┗
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CS_FINGER, CB_C_RIUP);// ☞ ┗
# else
unicode_hex2output_single (CS_FINGER);// ☞
# endif
}
break;
case XP_BON_CE: // because 5 above, because =, ┛ because forms box
// 0x2260,// inequal: ≠
// 0x251B, box drawing heavy: ┛
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CS_UNEQL, CB_C_LEUP);// ≠ ┛
# else
unicode_hex2output_single (CS_UNEQL);// ≠
# endif
}
break;
case XP_BON_CF: // because ☒ , ┣ box drawings block, some place
// 0x2717, cross mark: ✗ (complements ✓)
// 0x2523, box drawing: ┣
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CS_BOTCH, CB_VE_RI);// ✗ ┣
# else
unicode_hex2output_single (CS_BOTCH);// ✗
# endif
}
break;
case XP_BON_CG: // because 7 above, because ☑ 🗹 , ┫ complements with key to its left
// 0x2713, checkmark: ✓
// 0x252B, box drawing: ┫
if (record->event.pressed) { // key down
# ifdef BOX_DRAWINGS
unicode_hex2output (CS_CHECK, CB_VE_LE);// ✓ ┫
# else
unicode_hex2output_single (CS_CHECK);// ✓
# endif
}
break;
case XP_BON_CH: // because 8 above, because ¡ (inverted exclamation mark)
// 0x26A0,// alert: ⚠
if (record->event.pressed) { // key down
unicode_hex2output_single (CS_ALERT);// ⚠
}
break;
case XP_BON_CI: // because 9 above, because 《
// 0xAB, French quotation opening: «
if (record->event.pressed) { // key down
unicode_hex2output_single (CS_GUILLE);// «
}
break;
case XP_BON_CJ: // because 0 above, because 》
// 0xBB, French quotation closing: »
if (record->event.pressed) { // key down
unicode_hex2output_single (CS_GUILRI);// »
}
break;
# endif // REMOVE_BON
}
return true;
};