From cda343acbe45826225edac75eaa63216bf76d874 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Mon, 30 May 2022 22:02:55 -0700 Subject: [Keymap] Drashna update for post Q2 merge (#17241) --- users/drashna/autocorrect_data.h | 5 + users/drashna/callbacks.c | 3 + users/drashna/callbacks.h | 3 - users/drashna/config.h | 14 +- .../keyrecords/autocorrection/autocorrection.c | 292 +++++++++++++++------ .../keyrecords/autocorrection/autocorrection.h | 9 +- .../autocorrection/make_autocorrection_data.py | 186 +++++++------ users/drashna/keyrecords/caps_word.c | 139 ---------- users/drashna/keyrecords/caps_word.h | 85 ------ users/drashna/keyrecords/keycodes.md | 5 - users/drashna/keyrecords/process_records.c | 72 ++--- users/drashna/keyrecords/process_records.h | 11 +- users/drashna/keyrecords/secrets.md | 17 +- users/drashna/keyrecords/unicode.c | 21 +- users/drashna/keyrecords/unicode.h | 16 ++ users/drashna/oled/oled_stuff.c | 135 +++++----- users/drashna/oled/oled_stuff.h | 9 +- users/drashna/oled/sh110x.c | 19 ++ users/drashna/pointing/pointing.c | 4 +- users/drashna/rgb/rgb_matrix_stuff.c | 3 + users/drashna/rules.mk | 12 +- users/drashna/split/transport_sync.c | 3 + users/drashna/split/transport_sync.h | 13 +- users/drashna/template.c | 15 -- users/drashna/template.h | 4 +- 25 files changed, 510 insertions(+), 585 deletions(-) create mode 100644 users/drashna/autocorrect_data.h delete mode 100644 users/drashna/keyrecords/caps_word.c delete mode 100644 users/drashna/keyrecords/caps_word.h create mode 100644 users/drashna/keyrecords/unicode.h (limited to 'users/drashna') diff --git a/users/drashna/autocorrect_data.h b/users/drashna/autocorrect_data.h new file mode 100644 index 0000000000..bcb5858aa8 --- /dev/null +++ b/users/drashna/autocorrect_data.h @@ -0,0 +1,5 @@ +#if __has_include("../qmk_secrets/autocorrection_data.h") +# include "../qmk_secrets/autocorrection_data.h" +#else +# include "autocorrect_data_default.h" +#endif diff --git a/users/drashna/callbacks.c b/users/drashna/callbacks.c index c11a381dee..0ceb1aebe5 100644 --- a/users/drashna/callbacks.c +++ b/users/drashna/callbacks.c @@ -87,6 +87,9 @@ void suspend_power_down_user(void) { __attribute__((weak)) void suspend_wakeup_init_keymap(void) {} void suspend_wakeup_init_user(void) { +#ifdef OLED_ENABLE + oled_timer_reset(); +#endif suspend_wakeup_init_keymap(); } diff --git a/users/drashna/callbacks.h b/users/drashna/callbacks.h index 5fe5f6a808..f6ac6b88de 100644 --- a/users/drashna/callbacks.h +++ b/users/drashna/callbacks.h @@ -23,6 +23,3 @@ void matrix_init_unicode(void); #ifdef SPLIT_KEYBOARD void matrix_slave_scan_keymap(void); #endif -#ifdef CAPS_WORD_ENABLE -# include "keyrecords/caps_word.h" -#endif diff --git a/users/drashna/config.h b/users/drashna/config.h index 4551c3504f..4a34f5d66a 100644 --- a/users/drashna/config.h +++ b/users/drashna/config.h @@ -37,9 +37,9 @@ // # define WPM_LAUNCH_CONTROL // # define WPM_ALLOW_COUNT_REGRESSOIN // # define WPM_UNFILTERED -# define WPM_SAMPLE_SECONDS 6 +# define WPM_SAMPLE_SECONDS 10 # define WPM_SAMPLE_PERIODS 50 -# define WPM_ESTIMATED_WORD_SIZE 6 +# define WPM_ESTIMATED_WORD_SIZE 5 #endif #ifdef AUDIO_ENABLE @@ -291,6 +291,12 @@ # ifndef OLED_BRIGHTNESS # define OLED_BRIGHTNESS 50 # endif -# undef OLED_UPDATE_INTERVAL -# define OLED_UPDATE_INTERVAL 100 +# if !defined(STM32F4XX) +# undef OLED_UPDATE_INTERVAL +# define OLED_UPDATE_INTERVAL 75 +# endif #endif + +#define ENABLE_COMPILE_KEYCODE + +#define BOTH_SHIFTS_TURNS_ON_CAPS_WORD diff --git a/users/drashna/keyrecords/autocorrection/autocorrection.c b/users/drashna/keyrecords/autocorrection/autocorrection.c index c7e938a341..682d6fd49c 100644 --- a/users/drashna/keyrecords/autocorrection/autocorrection.c +++ b/users/drashna/keyrecords/autocorrection/autocorrection.c @@ -10,6 +10,13 @@ # pragma GCC push_options # pragma GCC optimize("O0") # include "autocorrection_data.h" +# ifndef AUTOCORRECTION_MIN_LENGTH +# define AUTOCORRECTION_MIN_LENGTH AUTOCORRECT_MIN_LENGTH +# endif +# ifndef AUTOCORRECTION_MAX_LENGTH +# define AUTOCORRECTION_MAX_LENGTH AUTOCORRECT_MAX_LENGTH +# endif +# define autocorrection_data autocorrect_data # if AUTOCORRECTION_MIN_LENGTH < 4 # error Minimum Length is too short and may cause overflows # endif @@ -17,6 +24,138 @@ # error Dictionary size excees maximum size permitted # endif +static uint8_t typo_buffer[AUTOCORRECT_MAX_LENGTH] = {KC_SPC}; +static uint8_t typo_buffer_size = 1; + +/** + * @brief function for querying the enabled state of autocorrect + * + * @return true if enabled + * @return false if disabled + */ +bool autocorrect_is_enabled(void) { + return userspace_config.autocorrection; +} + +/** + * @brief Enables autocorrect and saves state to eeprom + * + */ +void autocorrect_enable(void) { + userspace_config.autocorrection = true; + eeconfig_update_user(userspace_config.raw); +} + +/** + * @brief Disables autocorrect and saves state to eeprom + * + */ +void autocorrect_disable(void) { + userspace_config.autocorrection = false; + typo_buffer_size = 0; + eeconfig_update_user(userspace_config.raw); +} + +/** + * @brief Toggles autocorrect's status and save state to eeprom + * + */ +void autocorrect_toggle(void) { + userspace_config.autocorrection = !userspace_config.autocorrection; + typo_buffer_size = 0; + eeconfig_update_user(userspace_config.raw); +} + +/** + * @brief handler for determining if autocorrect should process keypress + * + * @param keycode Keycode registered by matrix press, per keymap + * @param record keyrecord_t structure + * @param typo_buffer_size passed along to allow resetting of autocorrect buffer + * @param mods allow processing of mod status + * @return true Allow autocorection + * @return false Stop processing and escape from autocorrect. + */ +__attribute__((weak)) bool process_autocorrect_user(uint16_t *keycode, keyrecord_t *record, uint8_t *typo_buffer_size, uint8_t *mods) { + // See quantum_keycodes.h for reference on these matched ranges. + switch (*keycode) { + // Exclude these keycodes from processing. + case KC_LSFT: + case KC_RSFT: + case KC_CAPS: + case QK_TO ... QK_ONE_SHOT_LAYER_MAX: + case QK_LAYER_TAP_TOGGLE ... QK_LAYER_MOD_MAX: + case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: + return false; + + // Mask for base keycode from shifted keys. + case QK_LSFT ... QK_LSFT + 255: + case QK_RSFT ... QK_RSFT + 255: + if (*keycode >= QK_LSFT && *keycode <= (QK_LSFT + 255)) { + *mods |= MOD_LSFT; + } else { + *mods |= MOD_RSFT; + } + *keycode &= 0xFF; // Get the basic keycode. + return true; +#ifndef NO_ACTION_TAPPING + // Exclude tap-hold keys when they are held down + // and mask for base keycode when they are tapped. + case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: +# ifdef NO_ACTION_LAYER + // Exclude Layer Tap, if layers are disabled + // but action tapping is still enabled. + return false; +# endif + case QK_MOD_TAP ... QK_MOD_TAP_MAX: + // Exclude hold keycode + if (!record->tap.count) { + return false; + } + *keycode &= 0xFF; + break; +#else + case QK_MOD_TAP ... QK_MOD_TAP_MAX: + case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: + // Exclude if disabled + return false; +#endif + // Exclude swap hands keys when they are held down + // and mask for base keycode when they are tapped. + case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: +#ifdef SWAP_HANDS_ENABLE + if (*keycode >= 0x56F0 || !record->tap.count) { + return false; + } + *keycode &= 0xFF; + break; +#else + // Exclude if disabled + return false; +#endif + } + + // Disable autocorrect while a mod other than shift is active. + if ((*mods & ~MOD_MASK_SHIFT) != 0) { + *typo_buffer_size = 0; + return false; + } + + return true; +} + +/** + * @brief handling for when autocorrection has been triggered + * + * @param backspaces number of characters to remove + * @param str pointer to PROGMEM string to replace mistyped seletion with + * @return true apply correction + * @return false user handled replacement + */ +__attribute__((weak)) bool apply_autocorrect(uint8_t backspaces, const char *str) { + return true; +} + /** * @brief Process handler for autocorrect feature * @@ -25,131 +164,124 @@ * @return true Continue processing keycodes, and send to host * @return false Stop processing keycodes, and don't send to host */ -bool process_autocorrection(uint16_t keycode, keyrecord_t* record) { - static uint8_t typo_buffer[AUTOCORRECTION_MAX_LENGTH] = {KC_SPC}; - static uint8_t typo_buffer_size = 1; +bool process_autocorrection(uint16_t keycode, keyrecord_t *record) { + uint8_t mods = get_mods(); +#ifndef NO_ACTION_ONESHOT + mods |= get_oneshot_mods(); +#endif - if (keycode == AUTO_CTN) { - if (record->event.pressed) { - typo_buffer_size = 0; - userspace_config.autocorrection ^= 1; - eeconfig_update_user(userspace_config.raw); + if ((keycode >= AUTOCORRECT_ON && keycode <= AUTOCORRECT_TOGGLE) && record->event.pressed) { + if (keycode == AUTOCORRECT_ON) { + autocorrect_enable(); + } else if (keycode == AUTOCORRECT_OFF) { + autocorrect_disable(); + } else if (keycode == AUTOCORRECT_TOGGLE) { + autocorrect_toggle(); + } else { + return true; } + return false; } - if (!userspace_config.autocorrection) { + if (!autocorrect_is_enabled()) { typo_buffer_size = 0; return true; } + if (!record->event.pressed) { + return true; + } + + // autocorrect keycode verification and extraction + if (!process_autocorrect_user(&keycode, record, &typo_buffer_size, &mods)) { + return true; + } + + // keycode buffer check switch (keycode) { - case KC_LSFT: - case KC_RSFT: - return true; -# ifndef NO_ACTION_TAPPING - case QK_MOD_TAP ... QK_MOD_TAP_MAX: - if (((keycode >> 8) & 0xF) == MOD_LSFT) { - return true; - } -# ifndef NO_ACTION_LAYER - case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: -# endif - if (record->event.pressed || !record->tap.count) { - return true; - } - keycode &= 0xFF; + case KC_A ... KC_Z: + // process normally break; -# endif -# ifdef SWAP_HANDS_ENABLE - case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: - if (keycode >= 0x56F0 || record->event.pressed || !record->tap.count) { - return true; - } - keycode &= 0xFF; + case KC_1 ... KC_0: + case KC_TAB ... KC_SEMICOLON: + case KC_GRAVE ... KC_SLASH: + // Set a word boundary if space, period, digit, etc. is pressed. + keycode = KC_SPC; break; -# endif -# ifndef NO_ACTION_ONESHOT - case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: - if ((keycode & 0xF) == MOD_LSFT) { - return true; - } -# endif - default: - // Disable autocorrection while a mod other than shift is active. - if (((get_mods() | get_oneshot_mods()) & ~MOD_MASK_SHIFT) != 0) { - typo_buffer_size = 0; - return true; - } - if (!record->event.pressed) { - return true; - } - } - - // Subtract buffer for Backspace key, reset for other non-alpha. - if (!(KC_A <= keycode && keycode <= KC_Z)) { - if (keycode == KC_BSPC) { + case KC_ENTER: + // Behave more conservatively for the enter key. Reset, so that enter + // can't be used on a word ending. + typo_buffer_size = 0; + keycode = KC_SPC; + break; + case KC_BSPC: // Remove last character from the buffer. if (typo_buffer_size > 0) { --typo_buffer_size; } return true; - } else if (KC_1 <= keycode && keycode <= KC_SLSH && keycode != KC_ESC) { - // Set a word boundary if space, period, digit, etc. is pressed. - // Behave more conservatively for the enter key. Reset, so that enter - // can't be used on a word ending. - if (keycode == KC_ENT || (keycode == KC_MINUS && (get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT)) { - typo_buffer_size = 0; + case KC_QUOTE: + // Treat " (shifted ') as a word boundary. + if ((mods & MOD_MASK_SHIFT) != 0) { + keycode = KC_SPC; } - keycode = KC_SPC; - } else { + break; + default: // Clear state if some other non-alpha key is pressed. typo_buffer_size = 0; return true; - } } // Rotate oldest character if buffer is full. - if (typo_buffer_size >= AUTOCORRECTION_MAX_LENGTH) { - memmove(typo_buffer, typo_buffer + 1, AUTOCORRECTION_MAX_LENGTH - 1); - typo_buffer_size = AUTOCORRECTION_MAX_LENGTH - 1; + if (typo_buffer_size >= AUTOCORRECT_MAX_LENGTH) { + memmove(typo_buffer, typo_buffer + 1, AUTOCORRECT_MAX_LENGTH - 1); + typo_buffer_size = AUTOCORRECT_MAX_LENGTH - 1; } // Append `keycode` to buffer. typo_buffer[typo_buffer_size++] = keycode; // Return if buffer is smaller than the shortest word. - if (typo_buffer_size < AUTOCORRECTION_MIN_LENGTH) { + if (typo_buffer_size < AUTOCORRECT_MIN_LENGTH) { return true; } - // Check for typo in buffer using a trie stored in `autocorrection_data`. + // Check for typo in buffer using a trie stored in `autocorrect_data`. uint16_t state = 0; - uint8_t code = pgm_read_byte(autocorrection_data + state); - for (uint8_t i = typo_buffer_size - 1; i >= 0; --i) { + uint8_t code = pgm_read_byte(autocorrect_data + state); + for (int8_t i = typo_buffer_size - 1; i >= 0; --i) { uint8_t const key_i = typo_buffer[i]; - if (code & 64) { // Check for match in node with multiple children. + if (code & 64) { // Check for match in node with multiple children. code &= 63; - for (; code != key_i; code = pgm_read_byte(autocorrection_data + (state += 3))) { + for (; code != key_i; code = pgm_read_byte(autocorrect_data + (state += 3))) { if (!code) return true; } // Follow link to child node. - state = (pgm_read_byte(autocorrection_data + state + 1) | pgm_read_byte(autocorrection_data + state + 2) << 8); + state = (pgm_read_byte(autocorrect_data + state + 1) | pgm_read_byte(autocorrect_data + state + 2) << 8); // Check for match in node with single child. } else if (code != key_i) { return true; - } else if (!(code = pgm_read_byte(autocorrection_data + (++state)))) { + } else if (!(code = pgm_read_byte(autocorrect_data + (++state)))) { ++state; } - code = pgm_read_byte(autocorrection_data + state); + // Stop if `state` becomes an invalid index. This should not normally + // happen, it is a safeguard in case of a bug, data corruption, etc. + if (state >= DICTIONARY_SIZE) { + return true; + } + + code = pgm_read_byte(autocorrect_data + state); - if (code & 128) { // A typo was found! Apply autocorrection. - const uint8_t backspaces = code & 63; - for (uint8_t i = 0; i < backspaces; ++i) { - tap_code(KC_BSPC); + if (code & 128) { // A typo was found! Apply autocorrect. + const uint8_t backspaces = (code & 63) + !record->event.pressed; + if (apply_autocorrect(backspaces, (char const *)(autocorrect_data + state + 1))) { + for (uint8_t i = 0; i < backspaces; ++i) { + tap_code(KC_BSPC); + } + send_string_P((char const *)(autocorrect_data + state + 1)); } - send_string_P((char const*)(autocorrection_data + state + 1)); if (keycode == KC_SPC) { typo_buffer[0] = KC_SPC; @@ -166,5 +298,7 @@ bool process_autocorrection(uint16_t keycode, keyrecord_t* record) { # pragma GCC pop_options #else # pragma message "Warning!!! Autocorrect is not corretly setup!" -bool process_autocorrection(uint16_t keycode, keyrecord_t* record) { return true; } +bool process_autocorrection(uint16_t keycode, keyrecord_t* record) { + return true; +} #endif diff --git a/users/drashna/keyrecords/autocorrection/autocorrection.h b/users/drashna/keyrecords/autocorrection/autocorrection.h index cea93159ae..8946b91f1f 100644 --- a/users/drashna/keyrecords/autocorrection/autocorrection.h +++ b/users/drashna/keyrecords/autocorrection/autocorrection.h @@ -7,4 +7,11 @@ #include "drashna.h" -bool process_autocorrection(uint16_t keycode, keyrecord_t* record); +bool process_autocorrection(uint16_t keycode, keyrecord_t *record); +bool process_autocorrect_user(uint16_t *keycode, keyrecord_t *record, uint8_t *typo_buffer_size, uint8_t *mods); +bool apply_autocorrect(uint8_t backspaces, const char *str); + +bool autocorrect_is_enabled(void); +void autocorrect_enable(void); +void autocorrect_disable(void); +void autocorrect_toggle(void); diff --git a/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py b/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py index 54fd9ba594..0dd9b78b9c 100755 --- a/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py +++ b/users/drashna/keyrecords/autocorrection/make_autocorrection_data.py @@ -1,4 +1,4 @@ -# Copyright 2021 Google LLC +# Copyright 2021-2022 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -29,6 +29,7 @@ Each line of the dict file defines one typo and its correction with the syntax Example: :thier -> their + dosen't -> doesn't fitler -> filter lenght -> length ouput -> output @@ -42,7 +43,7 @@ https://getreuer.info/posts/keyboards/autocorrection import sys import textwrap -from typing import Any, Dict, List, Tuple +from typing import Any, Dict, Iterator, List, Tuple try: from english_words import english_words_lower_alpha_set as CORRECT_WORDS @@ -51,85 +52,67 @@ except ImportError: 'correctly spelled word. To check for this, install the english_words ' 'package and rerun this script:\n\n pip install english_words\n') # Use a minimal word list as a fallback. - CORRECT_WORDS = ('information', 'available', 'international', 'language', - 'loosest', 'reference', 'wealthier', 'entertainment', - 'association', 'provides', 'technology', 'statehood') + CORRECT_WORDS = ('apparent', 'association', 'available', 'classification', + 'effect', 'entertainment', 'fantastic', 'information', + 'integrate', 'international', 'language', 'loosest', + 'manual', 'nothing', 'provides', 'reference', 'statehood', + 'technology', 'virtually', 'wealthier', 'wonderful') KC_A = 4 KC_SPC = 0x2c +KC_QUOT = 0x34 + +TYPO_CHARS = dict( + [ + ("'", KC_QUOT), + (':', KC_SPC), # "Word break" character. + ] + + # Characters a-z. + [(chr(c), c + KC_A - ord('a')) for c in range(ord('a'), ord('z') + 1)] +) + def parse_file(file_name: str) -> List[Tuple[str, str]]: """Parses autocorrections dictionary file. Each line of the file defines one typo and its correction with the syntax "typo -> correction". Blank lines or lines starting with '#' are ignored. The - function validates that typos only have characters a-z and that typos are not - substrings of other typos, otherwise the longer typo would never trigger. + function validates that typos only have characters in TYPO_CHARS, that + typos are not substrings of other typos, and checking that typos don't trigger + on CORRECT_WORDS. Args: file_name: String, path of the autocorrections dictionary. Returns: List of (typo, correction) tuples. """ - + correct_words = ('information', 'available', 'international', 'language', 'loosest', 'reference', 'wealthier', 'entertainment', 'association', 'provides', 'technology', 'statehood') autocorrections = [] typos = set() - line_number = 0 - for line in open(file_name, 'rt'): - line_number += 1 - line = line.strip() - if line and line[0] != '#': - # Parse syntax "typo -> correction", using strip to ignore indenting. - tokens = [token.strip() for token in line.split('->', 1)] - if len(tokens) != 2 or not tokens[0]: - print(f'Error:{line_number}: Invalid syntax: "{line}"') + for line_number, typo, correction in parse_file_lines(file_name): + if typo in typos: + print(f'Warning:{line_number}: Ignoring duplicate typo: "{typo}"') + continue + + # Check that `typo` is valid. + if not(all([c in TYPO_CHARS for c in typo])): + print(f'Error:{line_number}: Typo "{typo}" has ' + 'characters other than ' + ''.join(TYPO_CHARS.keys())) + sys.exit(1) + for other_typo in typos: + if typo in other_typo or other_typo in typo: + print(f'Error:{line_number}: Typos may not be substrings of one ' + f'another, otherwise the longer typo would never trigger: ' + f'"{typo}" vs. "{other_typo}".') sys.exit(1) + if len(typo) < 5: + print(f'Warning:{line_number}: It is suggested that typos are at ' + f'least 5 characters long to avoid false triggers: "{typo}"') - typo, correction = tokens - typo = typo.lower() # Force typos to lowercase. - typo = typo.replace(' ', ':') - - if typo in typos: - print(f'Warning:{line_number}: Ignoring duplicate typo: "{typo}"') - continue + check_typo_against_dictionary(typo, line_number, correct_words) - # Check that `typo` is valid. - if not(all([ord('a') <= ord(c) <= ord('z') or c == ':' for c in typo])): - print(f'Error:{line_number}: Typo "{typo}" has ' - 'characters other than a-z and :.') - sys.exit(1) - for other_typo in typos: - if typo in other_typo or other_typo in typo: - print(f'Error:{line_number}: Typos may not be substrings of one ' - f'another, otherwise the longer typo would never trigger: ' - f'"{typo}" vs. "{other_typo}".') - sys.exit(1) - if len(typo) < 5: - print(f'Warning:{line_number}: It is suggested that typos are at ' - f'least 5 characters long to avoid false triggers: "{typo}"') - - if typo.startswith(':') and typo.endswith(':'): - if typo[1:-1] in CORRECT_WORDS: - print(f'Warning:{line_number}: Typo "{typo}" is a correctly spelled ' - 'dictionary word.') - elif typo.startswith(':') and not typo.endswith(':'): - for word in CORRECT_WORDS: - if word.startswith(typo[1:]): - print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger ' - f'on correctly spelled word "{word}".') - elif not typo.startswith(':') and typo.endswith(':'): - for word in CORRECT_WORDS: - if word.endswith(typo[:-1]): - print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger ' - f'on correctly spelled word "{word}".') - elif not typo.startswith(':') and not typo.endswith(':'): - for word in CORRECT_WORDS: - if typo in word: - print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger ' - f'on correctly spelled word "{word}".') - - autocorrections.append((typo, correction)) - typos.add(typo) + autocorrections.append((typo, correction)) + typos.add(typo) return autocorrections @@ -152,6 +135,47 @@ def make_trie(autocorrections: List[Tuple[str, str]]) -> Dict[str, Any]: return trie +def parse_file_lines(file_name: str) -> Iterator[Tuple[int, str, str]]: + """Parses lines read from `file_name` into typo-correction pairs.""" + + line_number = 0 + for line in open(file_name, 'rt'): + line_number += 1 + line = line.strip() + if line and line[0] != '#': + # Parse syntax "typo -> correction", using strip to ignore indenting. + tokens = [token.strip() for token in line.split('->', 1)] + if len(tokens) != 2 or not tokens[0]: + print(f'Error:{line_number}: Invalid syntax: "{line}"') + sys.exit(1) + + typo, correction = tokens + typo = typo.lower() # Force typos to lowercase. + typo = typo.replace(' ', ':') + + yield line_number, typo, correction + + +def check_typo_against_dictionary(typo: str, line_number: int, correct_words) -> None: + """Checks `typo` against English dictionary words.""" + + if typo.startswith(':') and typo.endswith(':'): + if typo[1:-1] in correct_words: + print(f'Warning:{line_number}: Typo "{typo}" is a correctly spelled dictionary word.') + elif typo.startswith(':') and not typo.endswith(':'): + for word in correct_words: + if word.startswith(typo[1:]): + print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger on correctly spelled word "{word}".') + elif not typo.startswith(':') and typo.endswith(':'): + for word in correct_words: + if word.endswith(typo[:-1]): + print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger on correctly spelled word "{word}".') + elif not typo.startswith(':') and not typo.endswith(':'): + for word in correct_words: + if typo in word: + print(f'Warning:{line_number}: Typo "{typo}" would falsely trigger on correctly spelled word "{word}".') + + def serialize_trie(autocorrections: List[Tuple[str, str]], trie: Dict[str, Any]) -> List[int]: """Serializes trie and correction data in a form readable by the C code. @@ -165,7 +189,7 @@ def serialize_trie(autocorrections: List[Tuple[str, str]], table = [] # Traverse trie in depth first order. - def traverse(trie_node): + def traverse(trie_node: Dict[str, Any]) -> Dict[str, Any]: if 'LEAF' in trie_node: # Handle a leaf trie node. typo, correction = trie_node['LEAF'] word_boundary_ending = typo[-1] == ':' @@ -200,37 +224,35 @@ def serialize_trie(autocorrections: List[Tuple[str, str]], traverse(trie) - def serialize(e): - def kc_code(c): - if ord('a') <= ord(c) <= ord('z'): - return ord(c) - ord('a') + KC_A - elif c == ':': - return KC_SPC - else: - raise ValueError(f'Invalid character: {c}') - - encode_link = lambda link: [link['byte_offset'] & 255, - link['byte_offset'] >> 8] - + def serialize(e: Dict[str, Any]) -> List[int]: if not e['links']: # Handle a leaf table entry. return e['data'] elif len(e['links']) == 1: # Handle a chain table entry. - return list(map(kc_code, e['chars'])) + [0] #+ encode_link(e['links'][0])) + return [TYPO_CHARS[c] for c in e['chars']] + [0] else: # Handle a branch table entry. data = [] for c, link in zip(e['chars'], e['links']): - data += [kc_code(c) | (0 if data else 64)] + encode_link(link) + data += [TYPO_CHARS[c] | (0 if data else 64)] + encode_link(link) return data + [0] byte_offset = 0 for e in table: # To encode links, first compute byte offset of each entry. e['byte_offset'] = byte_offset byte_offset += len(serialize(e)) - assert 0 <= byte_offset <= 0xffff return [b for e in table for b in serialize(e)] # Serialize final table. +def encode_link(link: Dict[str, Any]) -> List[int]: + """Encodes a node link as two bytes.""" + byte_offset = link['byte_offset'] + if not (0 <= byte_offset <= 0xffff): + print('Error: The autocorrection table is too large, a node link exceeds ' + '64KB limit. Try reducing the autocorrection dict to fewer entries.') + sys.exit(1) + return [byte_offset & 255, byte_offset >> 8] + + def write_generated_code(autocorrections: List[Tuple[str, str]], data: List[int], file_name: str) -> None: @@ -242,7 +264,10 @@ def write_generated_code(autocorrections: List[Tuple[str, str]], file_name: String, path of the output C file. """ assert all(0 <= b <= 255 for b in data) - typo_len = lambda e: len(e[0]) + + def typo_len(e: Tuple[str, str]) -> int: + return len(e[0]) + min_typo = min(autocorrections, key=typo_len)[0] max_typo = max(autocorrections, key=typo_len)[0] generated_code = ''.join([ @@ -252,9 +277,8 @@ def write_generated_code(autocorrections: List[Tuple[str, str]], for typo, correction in autocorrections)), f'\n#define AUTOCORRECTION_MIN_LENGTH {len(min_typo)} // "{min_typo}"\n', f'#define AUTOCORRECTION_MAX_LENGTH {len(max_typo)} // "{max_typo}"\n\n', - f'#define DICTIONARY_SIZE {len(data)}\n\n', - textwrap.fill('static const uint8_t autocorrection_data[DICTIONARY_SIZE] PROGMEM = {%s};' % ( - ', '.join(map(str, data))), width=120, subsequent_indent=' '), + textwrap.fill('static const uint8_t autocorrection_data[%d] PROGMEM = {%s};' % ( + len(data), ', '.join(map(str, data))), width=80, subsequent_indent=' '), '\n\n']) with open(file_name, 'wt') as f: diff --git a/users/drashna/keyrecords/caps_word.c b/users/drashna/keyrecords/caps_word.c deleted file mode 100644 index a152b2387b..0000000000 --- a/users/drashna/keyrecords/caps_word.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "caps_word.h" - -static bool caps_word_active = false; - -#if CAPS_WORD_IDLE_TIMEOUT > 0 -# if CAPS_WORD_IDLE_TIMEOUT < 100 || CAPS_WORD_IDLE_TIMEOUT > 30000 -// Constrain timeout to a sensible range. With the 16-bit timer, the longest -// representable timeout is 32768 ms, rounded here to 30000 ms = half a minute. -# error "caps_word: CAPS_WORD_IDLE_TIMEOUT must be between 100 and 30000 ms" -# endif - -static uint16_t idle_timer = 0; - -void caps_word_task(void) { - if (caps_word_active && timer_expired(timer_read(), idle_timer)) { - caps_word_set(false); - } -} -#endif // CAPS_WORD_IDLE_TIMEOUT > 0 - -bool process_caps_word(uint16_t keycode, keyrecord_t* record) { -#ifndef NO_ACTION_ONESHOT - const uint8_t mods = get_mods() | get_oneshot_mods(); -#else - const uint8_t mods = get_mods(); -#endif // NO_ACTION_ONESHOT - - if (!caps_word_active) { - // Pressing both shift keys at the same time enables caps word. - if ((mods & MOD_MASK_SHIFT) == MOD_MASK_SHIFT) { - caps_word_set(true); // Activate Caps Word. - return false; - } - return true; - } else { -#if CAPS_WORD_IDLE_TIMEOUT > 0 - idle_timer = record->event.time + CAPS_WORD_IDLE_TIMEOUT; -#endif // CAPS_WORD_IDLE_TIMEOUT > 0 - } - - if (!record->event.pressed) { - return true; - } - - if (!(mods & ~MOD_MASK_SHIFT)) { - switch (keycode) { - // Ignore MO, TO, TG, TT, and OSL layer switch keys. - case QK_MOMENTARY ... QK_MOMENTARY_MAX: - case QK_TO ... QK_TO_MAX: - case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: - case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: - case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: - return true; - -#ifndef NO_ACTION_TAPPING - case QK_MOD_TAP ... QK_MOD_TAP_MAX: - if (record->tap.count == 0) { - // Deactivate if a mod becomes active through holding a mod-tap key. - caps_word_set(false); - return true; - } - keycode &= 0xff; - break; - -# ifndef NO_ACTION_LAYER - case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: -# endif // NO_ACTION_LAYER - if (record->tap.count == 0) { - return true; - } - keycode &= 0xff; - break; -#endif // NO_ACTION_TAPPING - -#ifdef SWAP_HANDS_ENABLE - case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: - if (keycode > 0x56F0 || record->tap.count == 0) { - return true; - } - keycode &= 0xff; - break; -#endif // SWAP_HANDS_ENABLE - } - - if (caps_word_press_user(keycode)) { - return true; - } - } - - caps_word_set(false); // Deactivate Caps Word. - return true; -} - -void caps_word_set(bool active) { - if (active != caps_word_active) { - if (active) { - clear_mods(); -#ifndef NO_ACTION_ONESHOT - clear_oneshot_mods(); -#endif // NO_ACTION_ONESHOT -#if CAPS_WORD_IDLE_TIMEOUT > 0 - idle_timer = timer_read() + CAPS_WORD_IDLE_TIMEOUT; -#endif // CAPS_WORD_IDLE_TIMEOUT > 0 - } else if ((get_weak_mods() & MOD_BIT(KC_LSFT)) != 0) { - // If the weak shift mod is still on, turn it off and send an update to - // the host computer. - del_weak_mods(MOD_BIT(KC_LSFT)); - send_keyboard_report(); - } - - caps_word_active = active; - caps_word_set_user(active); - } -} - -bool caps_word_get(void) { - return caps_word_active; -} - -__attribute__((weak)) void caps_word_set_user(bool active) {} - -__attribute__((weak)) bool caps_word_press_user(uint16_t keycode) { - switch (keycode) { - // Keycodes that continue Caps Word, with shift applied. - case KC_A ... KC_Z: - add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key. - return true; - - // Keycodes that continue Caps Word, without shifting. - case KC_1 ... KC_0: - case KC_BSPC: - case KC_MINS: - case KC_UNDS: - return true; - - default: - return false; // Deactivate Caps Word. - } -} diff --git a/users/drashna/keyrecords/caps_word.h b/users/drashna/keyrecords/caps_word.h deleted file mode 100644 index 4279d7e831..0000000000 --- a/users/drashna/keyrecords/caps_word.h +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2021 Google LLC. -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "drashna.h" - -// Call this function from `process_record_user()` to implement Caps Word. -bool process_caps_word(uint16_t keycode, keyrecord_t* record); - -// If CAPS_WORD_IDLE_TIMEOUT is set, call `caps_word_task()` from -// `matrix_scan_user()` as described above. -// -// If CAPS_WORD_IDLE_TIMEOUT isn't set, calling this function has no effect (but -// will still compile). -#if CAPS_WORD_IDLE_TIMEOUT > 0 -void caps_word_task(void); -#else -static inline void caps_word_task(void) {} -#endif - -// Activates or deactivates Caps Word. For instance activate Caps Word with a -// combo by defining a `COMBO_ACTION` that calls `caps_word_set(true)`: -// -// void process_combo_event(uint16_t combo_index, bool pressed) { -// switch(combo_index) { -// case CAPS_COMBO: -// if (pressed) { -// caps_word_set(true); // Activate Caps Word. -// } -// break; -// -// // Other combos... -// } -// } -void caps_word_set(bool active); - -// Returns whether Caps Word is currently active. -bool caps_word_get(void); - -// An optional callback that gets called when Caps Word turns on or off. This is -// useful to represent the current Caps Word state, e.g. by setting an LED or -// playing a sound. In your keymap, define -// -// void caps_word_set_user(bool active) { -// if (active) { -// // Do something when Caps Word activates. -// } else { -// // Do something when Caps Word deactivates. -// } -// } -void caps_word_set_user(bool active); - -// An optional callback which is called on every key press while Caps Word is -// active. When the key should be shifted (that is, a letter key), the callback -// should call `add_weak_mods(MOD_BIT(KC_LSFT))` to shift the key. The callback -// also determines whether the key should continue Caps Word. Returning true -// continues the current "word", while returning false is "word breaking" and -// deactivates Caps Word. The default callback is -// -// bool caps_word_press_user(uint16_t keycode) { -// switch (keycode) { -// // Keycodes that continue Caps Word, with shift applied. -// case KC_A ... KC_Z: -// add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to the next key. -// return true; -// -// // Keycodes that continue Caps Word, without shifting. -// case KC_1 ... KC_0: -// case KC_BSPC: -// case KC_MINS: -// case KC_UNDS: -// return true; -// -// default: -// return false; // Deactivate Caps Word. -// } -// } -// -// To customize, copy the above function into your keymap and add/remove -// keycodes to the above cases. -// -// NOTE: Outside of this callback, you can use `caps_word_set(false)` to -// deactivate Caps Word. -bool caps_word_press_user(uint16_t keycode); diff --git a/users/drashna/keyrecords/keycodes.md b/users/drashna/keyrecords/keycodes.md index 348c68e46c..bb5b65a77c 100644 --- a/users/drashna/keyrecords/keycodes.md +++ b/users/drashna/keyrecords/keycodes.md @@ -5,14 +5,9 @@ Keycodes are defined in the `process_record.h` file and need to be included in t A bunch of macros are present and are only included on boards that are not the Ergodox EZ or Orthodox, as they are not needed for those boards. -* `KC_MAKE` - outputs `qmk compile -kb (keyboard) -km (keymap)` and enter, to start compiling the currenct keyboard. This uses generated variables to always use the current keyboard and keymap. Will work with any keyboard and any keymap. - * If you are holding shift, it will use `qmk flash` instead of `qmk compile`. - * If `MAKE_BOOTLOADER` is defined, it will always use `qmk flash` instead of `qmk compile`. * `DEFAULT_LAYER_1` ... `DEFAULT_LAYER_4` - This sets layer 0-3 as the default layer, and writes that to eeprom, and plays a chime. * `VRSN`, outputs the keyboard, keymap, commit and date info. Eg: * `handwired/tractyl_manuform/5x6_right/f411/drashna @ 0.15.9-162-g087d08, Built on: 2021-12-19-21:10:26` * `KC_DIABLO_CLEAR` - clears the diablo tapdance status. * `KC_CCCV` - Copy on hold, paste on tap. * `KEYLOCK` - This unloads the host driver, and prevents any data from being sent to the host. Hitting it again loads the driver, back. -* `REBOOT` - Uses watchdog timer on AVR, and `NVIC_SystemReset()` on ChibiOS to reset the board, without jumping to the bootloader. -* `EEP_RST` - Overrides the default behavior, disables EEPROM (which will trigger a reset on init), and reboots the keyboard as per `REBOOT` keycode. diff --git a/users/drashna/keyrecords/process_records.c b/users/drashna/keyrecords/process_records.c index 99267d88a8..240156e816 100644 --- a/users/drashna/keyrecords/process_records.c +++ b/users/drashna/keyrecords/process_records.c @@ -3,9 +3,6 @@ #include "drashna.h" #include "version.h" -#ifdef CAPS_WORD_ENABLE -# include "caps_word.h" -#endif #ifdef AUTOCORRECTION_ENABLE # include "autocorrection/autocorrection.h" #endif @@ -37,6 +34,15 @@ __attribute__((weak)) bool process_record_secrets(uint16_t keycode, keyrecord_t * @return false Stop process keycode and do not send to host */ bool process_record_user(uint16_t keycode, keyrecord_t *record) { +#ifdef ENCODER_ENABLE // some debouncing for weird issues + if (IS_ENCODEREVENT(record->event)) { + static bool ignore_first = true; + if (ignore_first) { + ignore_first = false; + return false; + } + } +#endif // If console is enabled, it will print the matrix position and status of each key pressed #ifdef KEYLOGGER_ENABLE uprintf("KL: kc: 0x%04X, col: %2u, row: %2u, pressed: %b, time: %5u, int: %b, count: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed, record->event.time, record->tap.interrupted, record->tap.count); @@ -58,9 +64,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { #if defined(CUSTOM_POINTING_DEVICE) && process_record_pointing(keycode, record) #endif -#ifdef CAPS_WORD_ENABLE - && process_caps_word(keycode, record) -#endif #ifdef AUTOCORRECTION_ENABLE && process_autocorrection(keycode, record) #endif @@ -87,33 +90,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } break; - case KC_MAKE: // Compiles the firmware, and adds the flash command based on keyboard bootloader - if (!record->event.pressed) { -#ifndef MAKE_BOOTLOADER - uint8_t temp_mod = mod_config(get_mods()); - uint8_t temp_osm = mod_config(get_oneshot_mods()); - clear_mods(); - clear_oneshot_mods(); -#endif - send_string_with_delay_P(PSTR("qmk"), TAP_CODE_DELAY); -#ifndef MAKE_BOOTLOADER - if ((temp_mod | temp_osm) & MOD_MASK_SHIFT) -#endif - { - send_string_with_delay_P(PSTR(" flash "), TAP_CODE_DELAY); -#ifndef MAKE_BOOTLOADER - } else { - send_string_with_delay_P(PSTR(" compile "), TAP_CODE_DELAY); -#endif - } - send_string_with_delay_P(PSTR("-kb " QMK_KEYBOARD " -km " QMK_KEYMAP), TAP_CODE_DELAY); -#ifdef CONVERT_TO_PROTON_C - send_string_with_delay_P(PSTR(" -e CTPC=yes"), TAP_CODE_DELAY); -#endif - send_string_with_delay_P(PSTR(SS_TAP(X_ENTER)), TAP_CODE_DELAY); - } - break; - case VRSN: // Prints firmware version if (record->event.pressed) { send_string_with_delay_P(PSTR(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION ", Built on: " QMK_BUILDDATE), TAP_CODE_DELAY); @@ -148,13 +124,19 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { dprintf("rgblight layer change [EEPROM]: %u\n", userspace_config.rgb_layer_change); eeconfig_update_user(userspace_config.raw); if (userspace_config.rgb_layer_change) { -# if defined(CUSTOM_RGBLIGHT) && defined(CUSTOM_RGB_MATRIX) +# if defined(CUSTOM_RGB_MATRIX) + rgb_matrix_set_flags(LED_FLAG_UNDERGLOW | LED_FLAG_KEYLIGHT | LED_FLAG_INDICATOR); +# if defined(CUSTOM_RGBLIGHT) rgblight_enable_noeeprom(); +# endif # endif - layer_state_set(layer_state); // This is needed to immediately set the layer color (looks better) -# if defined(CUSTOM_RGBLIGHT) && defined(CUSTOM_RGB_MATRIX) + layer_state_set(layer_state); // This is needed to immediately set the layer color (looks better) +# if defined(CUSTOM_RGB_MATRIX) } else { + rgb_matrix_set_flags(LED_FLAG_ALL); +# if defined(CUSTOM_RGBLIGHT) rgblight_disable_noeeprom(); +# endif # endif } } @@ -218,23 +200,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { } break; } - case EEP_RST: - if (record->event.pressed) { - eeconfig_disable(); - shutdown_user(); -#ifdef __AVR__ - wdt_enable(WDTO_250MS); -#else - NVIC_SystemReset(); -#endif - } - return false; - case REBOOT: - if (record->event.pressed) { - software_reset(); - } - return false; - } + } return true; } diff --git a/users/drashna/keyrecords/process_records.h b/users/drashna/keyrecords/process_records.h index 5ca2966131..e83e4ce308 100644 --- a/users/drashna/keyrecords/process_records.h +++ b/users/drashna/keyrecords/process_records.h @@ -21,7 +21,6 @@ enum userspace_custom_keycodes { KC_DVORAK, // Sets default layer to DVORAK LAST_DEFAULT_LAYER_KEYCODE = KC_DVORAK, // Sets default layer to WORKMAN KC_DIABLO_CLEAR, // Clears all Diablo Timers - KC_MAKE, // Run keyboard's customized make command KC_RGB_T, // Toggles RGB Layer Indication mode RGB_IDL, // RGB Idling animations KC_SECRET_1, // test1 @@ -46,8 +45,9 @@ enum userspace_custom_keycodes { KC_AUSSIE, KC_ZALGO, KC_ACCEL, - AUTO_CTN, // Toggle Autocorrect status - REBOOT, + AUTOCORRECT_ON, + AUTOCORRECT_OFF, + AUTOCORRECT_TOGGLE, NEW_SAFE_RANGE // use "NEWPLACEHOLDER for keymap specific codes }; @@ -95,9 +95,6 @@ bool process_record_unicode(uint16_t keycode, keyrecord_t *record); # endif #endif -#define KC_RESET RESET -#define KC_RST KC_RESET - #ifdef SWAP_HANDS_ENABLE # define KC_C1R3 SH_T(KC_TAB) #elif defined(DRASHNA_LP) @@ -130,7 +127,7 @@ bool process_record_unicode(uint16_t keycode, keyrecord_t *record); #define MG_NKRO MAGIC_TOGGLE_NKRO - +#define AUTO_CTN AUTOCORRECT_TOGGLE /* Custom Keycodes for Diablo 3 layer But since TD() doesn't work when tap dance is disabled diff --git a/users/drashna/keyrecords/secrets.md b/users/drashna/keyrecords/secrets.md index a9408dc2ef..3c40fa41b3 100644 --- a/users/drashna/keyrecords/secrets.md +++ b/users/drashna/keyrecords/secrets.md @@ -24,14 +24,12 @@ secrets.h Here is the magic. This handles including the "secrets", and adding the custom macros to send them. ```c -#include "drashna.h" // replace with your keymap's "h" file, or whatever file stores the keycodes +#include QMK_KEYBOARD_H #if (__has_include("secrets.h") && !defined(NO_SECRETS)) #include "secrets.h" #else -// `PROGMEM const char secret[][x]` may work better, but it takes up more space in the firmware -// And I'm not familiar enough to know which is better or why... -static const char * const secret[] = { +static const char * const secrets[] = { "test1", "test2", "test3", @@ -43,9 +41,10 @@ static const char * const secret[] = { bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case KC_SECRET_1 ... KC_SECRET_5: // Secrets! Externally defined strings, not stored in repo - if (!record->event.pressed) { - clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); - send_string_with_delay(secret[keycode - KC_SECRET_1], MACRO_TIMER); + if (record->event.pressed) { + clear_mods(); + clear_oneshot_mods(); + send_string_with_delay(secrets[keycode - KC_SECRET_1], MACRO_TIMER); } return false; break; @@ -59,7 +58,7 @@ bool process_record_secrets(uint16_t keycode, keyrecord_t *record) { Now, for the actual secrets! The file needs to look like ```c -static const char * secrets[] = { +static const char * secrets[] = { "secret1", "secret2", "secret3", @@ -96,7 +95,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) { Here, you want your `/users//rules.mk` file to "detect" the existence of the `secrets.c` file, and only add it if the file exists. -Additionally, to ensure that it's not added or processed in any way, it checks to see if `NO_SECRETS` is set. This way, if you run `make keyboard:name NO_SECRETS=yes`, it will remove the feature altogether. +Additionally, to ensure that it's not added or processed in any way, it checks to see if `NO_SECRETS` is set. This way, if you run `qmk compile -kb keyboard -km name -e NO_SECRETS=yes`, it will remove the feature altogether. ```make ifneq ($(strip $(NO_SECRETS)), yes) diff --git a/users/drashna/keyrecords/unicode.c b/users/drashna/keyrecords/unicode.c index af87ee2a61..c1fe8df2c3 100644 --- a/users/drashna/keyrecords/unicode.c +++ b/users/drashna/keyrecords/unicode.c @@ -4,9 +4,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "drashna.h" +#include "unicode.h" #include "process_unicode_common.h" -uint16_t typing_mode = KC_NOMODE; +uint8_t typing_mode = UCTM_NO_MODE; /** * @brief Registers the unicode keystrokes based on desired unicode @@ -242,10 +243,10 @@ bool process_record_unicode(uint16_t keycode, keyrecord_t *record) { break; case KC_NOMODE ... KC_ZALGO: if (record->event.pressed) { - if (typing_mode != keycode) { - typing_mode = keycode; + if (typing_mode != keycode - KC_NOMODE) { + typing_mode = keycode - KC_NOMODE; } else { - typing_mode = KC_NOMODE; + typing_mode = UCTM_NO_MODE; } } break; @@ -259,19 +260,19 @@ bool process_record_unicode(uint16_t keycode, keyrecord_t *record) { keycode &= 0xFF; } - if (typing_mode == KC_WIDE) { + if (typing_mode == UCTM_WIDE) { if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) { return process_record_glyph_replacement(keycode, record, unicode_range_translator_wide); } - } else if (typing_mode == KC_SCRIPT) { + } else if (typing_mode == UCTM_SCRIPT) { if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) { return process_record_glyph_replacement(keycode, record, unicode_range_translator_script); } - } else if (typing_mode == KC_BLOCKS) { + } else if (typing_mode == UCTM_BLOCKS) { if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) { return process_record_glyph_replacement(keycode, record, unicode_range_translator_boxes); } - } else if (typing_mode == KC_REGIONAL) { + } else if (typing_mode == UCTM_REGIONAL) { if (((KC_A <= keycode) && (keycode <= KC_0)) || keycode == KC_SPACE) { if (!process_record_glyph_replacement(keycode, record, unicode_range_translator_regional)) { wait_us(500); @@ -279,9 +280,9 @@ bool process_record_unicode(uint16_t keycode, keyrecord_t *record) { return false; } } - } else if (typing_mode == KC_AUSSIE) { + } else if (typing_mode == UCTM_AUSSIE) { return process_record_aussie(keycode, record); - } else if (typing_mode == KC_ZALGO) { + } else if (typing_mode == UCTM_ZALGO) { return process_record_zalgo(keycode, record); } return true; diff --git a/users/drashna/keyrecords/unicode.h b/users/drashna/keyrecords/unicode.h new file mode 100644 index 0000000000..dd261d3406 --- /dev/null +++ b/users/drashna/keyrecords/unicode.h @@ -0,0 +1,16 @@ +// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +enum unicode_typing_mode { + UCTM_NO_MODE, + UCTM_WIDE, + UCTM_SCRIPT, + UCTM_BLOCKS, + UCTM_REGIONAL, + UCTM_AUSSIE, + UCTM_ZALGO, +}; + +extern uint8_t typing_mode; diff --git a/users/drashna/oled/oled_stuff.c b/users/drashna/oled/oled_stuff.c index 2a26b8b638..8c76897fba 100644 --- a/users/drashna/oled/oled_stuff.c +++ b/users/drashna/oled/oled_stuff.c @@ -18,19 +18,23 @@ #include "drashna.h" #ifdef UNICODE_COMMON_ENABLE # include "process_unicode_common.h" +# include "keyrecords/unicode.h" +#endif +#ifdef AUDIO_CLICKY +# include "process_clicky.h" +#endif +#if defined(AUTOCORRECTION_ENABLE) +# include "keyrecords/autocorrection/autocorrection.h" #endif -# ifdef AUDIO_CLICKY -# include "process_clicky.h" -# endif #include extern bool host_driver_disabled; -uint32_t oled_timer = 0; -char keylog_str[OLED_KEYLOGGER_LENGTH] = {0}; -static uint16_t log_timer = 0; +uint32_t oled_timer = 0; +char keylog_str[OLED_KEYLOGGER_LENGTH] = {0}; +static uint16_t log_timer = 0; #ifdef OLED_DISPLAY_VERBOSE -static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0}; +static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0}; #endif deferred_token kittoken; @@ -100,12 +104,15 @@ void add_keylog(uint16_t keycode, keyrecord_t *record) { */ bool process_record_user_oled(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { - oled_timer = timer_read32(); + oled_timer_reset(); add_keylog(keycode, record); } return true; } +void oled_timer_reset(void) { + oled_timer = timer_read32(); +} /** * @brief Renders keylogger buffer to oled * @@ -262,9 +269,8 @@ void render_layer_state(void) { } }; - // clang-format on - uint8_t layer_is[4] = { 0, 4, 4, 4}; + uint8_t layer_is[4] = {0, 4, 4, 4}; if (layer_state_is(_ADJUST)) { layer_is[0] = 3; } else if (layer_state_is(_RAISE)) { @@ -280,7 +286,6 @@ void render_layer_state(void) { layer_is[2] = 5; } - oled_set_cursor(1, 2); oled_write_raw_P(tri_layer_image[layer_is[0]][0], sizeof(tri_layer_image[0][0])); oled_set_cursor(5, 2); @@ -322,7 +327,7 @@ void render_layer_state(void) { * * @param led_usb_state Current keyboard led state */ -void render_keylock_status(uint8_t led_usb_state) { +void render_keylock_status(led_t led_usb_state) { #if defined(OLED_DISPLAY_VERBOSE) oled_set_cursor(1, 6); #endif @@ -330,12 +335,12 @@ void render_keylock_status(uint8_t led_usb_state) { #if !defined(OLED_DISPLAY_VERBOSE) oled_write_P(PSTR(" "), false); #endif - oled_write_P(PSTR(OLED_RENDER_LOCK_NUML), led_usb_state & (1 << USB_LED_NUM_LOCK)); + oled_write_P(PSTR(OLED_RENDER_LOCK_NUML), led_usb_state.num_lock); oled_write_P(PSTR(" "), false); - oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state & (1 << USB_LED_CAPS_LOCK)); + oled_write_P(PSTR(OLED_RENDER_LOCK_CAPS), led_usb_state.caps_lock); #if defined(OLED_DISPLAY_VERBOSE) oled_write_P(PSTR(" "), false); - oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state & (1 << USB_LED_SCROLL_LOCK)); + oled_write_P(PSTR(OLED_RENDER_LOCK_SCLK), led_usb_state.scroll_lock); #endif } @@ -417,15 +422,14 @@ void render_bootmagic_status(void) { oled_write_P(logo[0][0], !is_bootmagic_on); } #ifndef OLED_DISPLAY_VERBOSE - oled_write_P(PSTR(" "), false); oled_write_P(logo[1][1], is_bootmagic_on); oled_write_P(logo[0][1], !is_bootmagic_on); #endif oled_write_P(PSTR(" "), false); oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NKRO), keymap_config.nkro); oled_write_P(PSTR(" "), false); -#ifdef AUTOCORRECTION_ENABLE - oled_write_P(PSTR("CRCT"), userspace_config.autocorrection); +#if defined(AUTOCORRECTION_ENABLE) || defined(AUTOCORRECT_ENABLE) + oled_write_P(PSTR("CRCT"), autocorrect_is_enabled()); oled_write_P(PSTR(" "), false); #else oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_NOGUI), keymap_config.no_gui); @@ -439,7 +443,7 @@ void render_bootmagic_status(void) { } #endif oled_write_P(PSTR(" "), false); - oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_ONESHOT), !is_oneshot_enabled()); + oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_ONESHOT), is_oneshot_enabled()); #ifdef SWAP_HANDS_ENABLE oled_write_P(PSTR(" "), false); oled_write_P(PSTR(OLED_RENDER_BOOTMAGIC_SWAP), swap_hands); @@ -461,7 +465,7 @@ void render_user_status(void) { l_is_clicky_on = user_state.audio_clicky_enable; # endif # else - is_audio_on = is_audio_on(); + is_audio_on = is_audio_on(); # ifdef AUDIO_CLICKY l_is_clicky_on = is_clicky_on(); # endif @@ -501,7 +505,7 @@ void render_user_status(void) { static const char PROGMEM cat_mode[2][3] = {{0xF8, 0xF9, 0}, {0xF6, 0xF7, 0}}; oled_write_P(cat_mode[0], host_driver_disabled); #if defined(UNICODE_COMMON_ENABLE) - static const char PROGMEM uc_mod_status[5][3] = {{0xEC, 0xED, 0}, {0x20, 0x20, 0}, {0x20, 0x20, 0}, {0x20, 0x20, 0}, {0xEA, 0xEB, 0}}; + static const char PROGMEM uc_mod_status[5][3] = {{0xEC, 0xED, 0}, {0x20, 0x20, 0}, {0x20, 0x20, 0}, {0x20, 0x20, 0}, {0xEA, 0xEB, 0}}; oled_write_P(uc_mod_status[get_unicode_input_mode()], false); #endif if (userspace_config.nuke_switch) { @@ -549,9 +553,9 @@ void render_wpm_graph(uint8_t max_lines_graph, uint8_t vertical_offset) { uint8_t currwpm = get_current_wpm(); float max_wpm = OLED_WPM_GRAPH_MAX_WPM; - if (timer_elapsed(timer) > OLED_WPM_GRAPH_REFRESH_INTERVAL) { // check if it's been long enough before refreshing graph - x = (max_lines_graph - 1) - ((currwpm / max_wpm) * (max_lines_graph - 1)); // main calculation to plot graph line - for (uint8_t i = 0; i <= OLED_WPM_GRAPH_GRAPH_LINE_THICKNESS - 1; i++) { // first draw actual value line + if (timer_elapsed(timer) > OLED_WPM_GRAPH_REFRESH_INTERVAL) { // check if it's been long enough before refreshing graph + x = (max_lines_graph - 1) - ((currwpm / max_wpm) * (max_lines_graph - 1)); // main calculation to plot graph line + for (uint8_t i = 0; i <= OLED_WPM_GRAPH_GRAPH_LINE_THICKNESS - 1; i++) { // first draw actual value line oled_write_pixel(3, x + i + vertical_offset, true); } # ifdef OLED_WPM_GRAPH_VERTICAL_LINE @@ -577,20 +581,11 @@ void render_wpm_graph(uint8_t max_lines_graph, uint8_t vertical_offset) { } } # endif - oled_pan(false); // then move the entire graph one pixel to the right - static const char PROGMEM display_border[3] = {0x0, 0xFF, 0x0}; - for (uint8_t i = 0; i < 7; i++) { - oled_set_cursor(0, i + 8); - oled_write_raw_P(display_border, sizeof(display_border)); - oled_set_cursor(21, i + 8); - oled_write_raw_P(display_border, sizeof(display_border)); - } - static const char PROGMEM footer_image[] = {0, 3, 4, 8, 16, 32, 64, 128, 128, 128, 128, 128, 128, 128, 192, 224, 240, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 240, 224, 192, 128, 128, 128, 128, 128, 128, 128, 64, 32, 16, 8, 4, 3, 0}; - oled_set_cursor(0, 15); - - oled_write_raw_P(footer_image, sizeof(footer_image)); - - timer = timer_read(); // refresh the timer for the next iteration +# include + uint8_t y_start = ceil(vertical_offset / 8); + uint8_t y_length = y_start + ceil(max_lines_graph / 8); + oled_pan_section(false, y_start, y_length, 3, 125); // then move the entire graph one pixel to the right + timer = timer_read(); // refresh the timer for the next iteration } #endif } @@ -617,13 +612,13 @@ __attribute__((weak)) void oled_driver_render_logo_right(void) { // WPM-responsive animation stuff here #define OLED_SLEEP_FRAMES 2 -#define OLED_SLEEP_SPEED 10 // below this wpm value your animation will idle +#define OLED_SLEEP_SPEED 10 // below this wpm value your animation will idle -#define OLED_WAKE_FRAMES 2 // uncomment if >1 -#define OLED_WAKE_SPEED OLED_SLEEP_SPEED // below this wpm value your animation will idle +#define OLED_WAKE_FRAMES 2 // uncomment if >1 +#define OLED_WAKE_SPEED OLED_SLEEP_SPEED // below this wpm value your animation will idle #define OLED_KAKI_FRAMES 3 -#define OLED_KAKI_SPEED 40 // above this wpm value typing animation to triggere +#define OLED_KAKI_SPEED 40 // above this wpm value typing animation to triggere #define OLED_RTOGI_FRAMES 2 //#define OLED_LTOGI_FRAMES 2 @@ -781,25 +776,13 @@ void oled_driver_render_logo_left(void) { # if (defined(KEYBOARD_bastardkb_charybdis) || defined(KEYBOARD_handwired_tractyl_manuform)) && defined(POINTING_DEVICE_ENABLE) render_pointing_dpi_status(charybdis_get_pointer_sniping_enabled() ? charybdis_get_pointer_sniping_dpi() : charybdis_get_pointer_default_dpi(), 1); -// credit and thanks to jaspertandy on discord for these images - static const char PROGMEM mouse_logo[3][2][16] = { - // mouse icon - { - { 0, 0, 0, 252, 2, 2, 2, 58, 2, 2, 2, 252, 0, 0, 0, 0 }, - { 0, 0, 63, 96, 64, 64, 64, 64, 64, 64, 64, 96, 63, 0, 0, 0 } - }, - // crosshair icon - { - { 128, 240, 136, 228, 146, 138, 202, 127, 202, 138, 146, 228, 136, 240, 128, 0 }, - { 0, 7, 8, 19, 36, 40, 41, 127, 41, 40, 36, 19, 8, 7, 0, 0 } - }, - // dragscroll icon - { - { 0, 0, 112, 136, 156, 2, 15, 1, 15, 2, 140, 68, 56, 0, 0, 0 }, - { 0, 0, 2, 6, 15, 28, 60, 124, 60, 28, 15, 6, 2, 0, 0, 0 } - } - }; - + // credit and thanks to jaspertandy on discord for these images + static const char PROGMEM mouse_logo[3][2][16] = {// mouse icon + {{0, 0, 0, 252, 2, 2, 2, 58, 2, 2, 2, 252, 0, 0, 0, 0}, {0, 0, 63, 96, 64, 64, 64, 64, 64, 64, 64, 96, 63, 0, 0, 0}}, + // crosshair icon + {{128, 240, 136, 228, 146, 138, 202, 127, 202, 138, 146, 228, 136, 240, 128, 0}, {0, 7, 8, 19, 36, 40, 41, 127, 41, 40, 36, 19, 8, 7, 0, 0}}, + // dragscroll icon + {{0, 0, 112, 136, 156, 2, 15, 1, 15, 2, 140, 68, 56, 0, 0, 0}, {0, 0, 2, 6, 15, 28, 60, 124, 60, 28, 15, 6, 2, 0, 0, 0}}}; uint8_t image_index = 0; # ifdef OLED_DISPLAY_TEST @@ -847,7 +830,7 @@ void render_status_right(void) { #if !defined(OLED_DISPLAY_VERBOSE) && defined(WPM_ENABLE) && !defined(CONVERT_TO_PROTON_C) render_wpm(2); #endif - render_keylock_status(host_keyboard_leds()); + render_keylock_status(host_keyboard_led_state()); } void render_status_left(void) { @@ -860,9 +843,11 @@ void render_status_left(void) { render_keylogger_status(); } -__attribute__((weak)) void oled_render_large_display(void) {} +__attribute__((weak)) void oled_render_large_display(bool side) {} -__attribute__((weak)) oled_rotation_t oled_init_keymap(oled_rotation_t rotation) { return rotation; } +__attribute__((weak)) oled_rotation_t oled_init_keymap(oled_rotation_t rotation) { + return rotation; +} oled_rotation_t oled_init_user(oled_rotation_t rotation) { if (is_keyboard_master()) { @@ -876,10 +861,11 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation) { return oled_init_keymap(rotation); } -__attribute__((weak)) bool oled_task_keymap(void) { return true; } +__attribute__((weak)) bool oled_task_keymap(void) { + return true; +} bool oled_task_user(void) { - if (is_keyboard_master()) { #ifndef OLED_DISPLAY_TEST if (timer_elapsed32(oled_timer) > 60000) { @@ -896,29 +882,29 @@ bool oled_task_user(void) { return false; } -#if defined(OLED_DISPLAY_128X128) - oled_set_cursor(0, 7); - oled_render_large_display(); -#endif - #if defined(OLED_DISPLAY_VERBOSE) static const char PROGMEM header_image[] = { 0, 192, 32, 16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3, 7, 15, 31, 63, 127, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 63, 31, 15, 7, 3, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 192, 0, // 0,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 7, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 7, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255, 0 }; - static const char PROGMEM footer_image[] = {0, 3, 4, 8, 16, 32, 64, 128, 128, 128, 128, 128, 128, 128, 192, 224, 240, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 240, 224, 192, 128, 128, 128, 128, 128, 128, 128, 64, 32, 16, 8, 4, 3, 0}; - oled_set_cursor(0, 0); oled_write_raw_P(header_image, sizeof(header_image)); - oled_set_cursor(0, 1); #endif #ifndef OLED_DISPLAY_TEST if (is_keyboard_left()) { #endif render_status_left(); +#if defined(OLED_DISPLAY_128X128) + oled_set_cursor(0, 7); + oled_render_large_display(true); +#endif #ifndef OLED_DISPLAY_TEST } else { render_status_right(); +# if defined(OLED_DISPLAY_128X128) + oled_set_cursor(0, 7); + oled_render_large_display(false); +# endif } #endif @@ -936,6 +922,7 @@ bool oled_task_user(void) { oled_write_raw_P(display_border, sizeof(display_border)); } + static const char PROGMEM footer_image[] = {0, 3, 4, 8, 16, 32, 64, 128, 128, 128, 128, 128, 128, 128, 192, 224, 240, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 240, 224, 192, 128, 128, 128, 128, 128, 128, 128, 64, 32, 16, 8, 4, 3, 0}; oled_set_cursor(0, num_of_rows); oled_write_raw_P(footer_image, sizeof(footer_image)); #endif diff --git a/users/drashna/oled/oled_stuff.h b/users/drashna/oled/oled_stuff.h index 7245f6131c..4dea4b7be4 100644 --- a/users/drashna/oled/oled_stuff.h +++ b/users/drashna/oled/oled_stuff.h @@ -23,11 +23,11 @@ extern deferred_token kittoken; void oled_driver_render_logo(void); bool process_record_user_oled(uint16_t keycode, keyrecord_t *record); oled_rotation_t oled_init_keymap(oled_rotation_t rotation); -extern uint32_t oled_timer; +void oled_timer_reset(void); void render_keylogger_status(void); void render_default_layer_state(void); void render_layer_state(void); -void render_keylock_status(uint8_t led_usb_state); +void render_keylock_status(led_t led_usb_state); void render_matrix_scan_rate(uint8_t padding); void render_mod_status(uint8_t modifiers); void render_bootmagic_status(void); @@ -37,9 +37,12 @@ void render_wpm(uint8_t padding); void render_pointing_dpi_status(uint16_t cpi, uint8_t padding); void oled_driver_render_logo_left(void); void oled_driver_render_logo_right(void); -void oled_render_large_display(void); +void oled_render_large_display(bool side); void render_wpm_graph(uint8_t max_lines_graph, uint8_t vertical_offset); +void oled_pan_section(bool left, uint16_t y_start, uint16_t y_end, uint16_t x_start, uint16_t x_end); + + #if defined(OLED_DISPLAY_128X128) || defined(OLED_DISPLAY_128X64) # define OLED_DISPLAY_VERBOSE diff --git a/users/drashna/oled/sh110x.c b/users/drashna/oled/sh110x.c index cfdae1db16..aa081ca732 100644 --- a/users/drashna/oled/sh110x.c +++ b/users/drashna/oled/sh110x.c @@ -521,6 +521,25 @@ void oled_pan(bool left) { oled_dirty = OLED_ALL_BLOCKS_MASK; } +void oled_pan_section(bool left, uint16_t y_start, uint16_t y_end, uint16_t x_start, uint16_t x_end) { + uint16_t i = 0; + for (uint16_t y = y_start; y < y_end; y++) { + if (left) { + for (uint16_t x = x_start; x < x_end - 1; x++) { + i = y * OLED_DISPLAY_WIDTH + x; + oled_buffer[i] = oled_buffer[i + 1]; + oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE)); + } + } else { + for (uint16_t x = x_end - 1; x > 0; x--) { + i = y * OLED_DISPLAY_WIDTH + x; + oled_buffer[i] = oled_buffer[i - 1]; + oled_dirty |= ((OLED_BLOCK_TYPE)1 << (i / OLED_BLOCK_SIZE)); + } + } + } +} + oled_buffer_reader_t oled_read_raw(uint16_t start_index) { if (start_index > OLED_MATRIX_SIZE) start_index = OLED_MATRIX_SIZE; oled_buffer_reader_t ret_reader; diff --git a/users/drashna/pointing/pointing.c b/users/drashna/pointing/pointing.c index 2e313ba574..551034ff45 100644 --- a/users/drashna/pointing/pointing.c +++ b/users/drashna/pointing/pointing.c @@ -29,7 +29,7 @@ report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { if (x != 0 && y != 0) { mouse_timer = timer_read(); #ifdef OLED_ENABLE - oled_timer = timer_read32(); + oled_timer_reset(); #endif if (timer_elapsed(mouse_debounce_timer) > TAP_CHECK) { if (enable_acceleration) { @@ -94,8 +94,10 @@ bool process_record_pointing(uint16_t keycode, keyrecord_t* record) { record->event.pressed ? mouse_keycode_tracker++ : mouse_keycode_tracker--; mouse_timer = timer_read(); break; +#if 0 case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: break; +#endif case QK_MOD_TAP ... QK_MOD_TAP_MAX: if (record->event.pressed || !record->tap.count) { break; diff --git a/users/drashna/rgb/rgb_matrix_stuff.c b/users/drashna/rgb/rgb_matrix_stuff.c index e6d631466d..36a7502733 100644 --- a/users/drashna/rgb/rgb_matrix_stuff.c +++ b/users/drashna/rgb/rgb_matrix_stuff.c @@ -57,6 +57,9 @@ void keyboard_post_init_rgb_matrix(void) { rgb_matrix_mode_noeeprom(RGB_MATRIX_REST_MODE); } #endif + if (userspace_config.rgb_layer_change) { + rgb_matrix_set_flags(LED_FLAG_UNDERGLOW | LED_FLAG_KEYLIGHT | LED_FLAG_INDICATOR); + } } bool process_record_user_rgb_matrix(uint16_t keycode, keyrecord_t *record) { diff --git a/users/drashna/rules.mk b/users/drashna/rules.mk index 12fa956b7d..b96e8a532b 100644 --- a/users/drashna/rules.mk +++ b/users/drashna/rules.mk @@ -13,8 +13,9 @@ GRAVE_ESC_ENABLE = no # DEBUG_MATRIX_SCAN_RATE_ENABLE = api ifneq ($(strip $(NO_SECRETS)), yes) - ifneq ("$(wildcard $(USER_PATH)/keyrecords/secrets.c)","") - SRC += $(USER_PATH)/keyrecords/secrets.c + ifneq ("$(wildcard $(USER_PATH)/../../../qmk_secrets/secrets.c)","") + SRC += $(USER_PATH)/../../../qmk_secrets/secrets.c + SECURE_ENABLE = yes endif ifeq ($(strip $(NO_SECRETS)), lite) OPT_DEFS += -DNO_SECRETS @@ -102,6 +103,7 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes) ifeq ($(strip $(CUSTOM_POINTING_DEVICE)), yes) SRC += $(USER_PATH)/pointing/pointing.c OPT_DEFS += -DCUSTOM_POINTING_DEVICE + OPT_DEFS += -DMOUSE_EXT_REPORT endif endif @@ -119,9 +121,3 @@ ifeq ($(strip $(AUTOCORRECTION_ENABLE)), yes) SRC += $(USER_PATH)/keyrecords/autocorrection/autocorrection.c OPT_DEFS += -DAUTOCORRECTION_ENABLE endif - -CAPS_WORD_ENABLE ?= no -ifeq ($(strip $(CAPS_WORD_ENABLE)), yes) - SRC += $(USER_PATH)/keyrecords/caps_word.c - OPT_DEFS += -DCAPS_WORD_ENABLE -endif diff --git a/users/drashna/split/transport_sync.c b/users/drashna/split/transport_sync.c index 539a18900c..38df8fda3f 100644 --- a/users/drashna/split/transport_sync.c +++ b/users/drashna/split/transport_sync.c @@ -11,6 +11,7 @@ #ifdef UNICODE_COMMON_ENABLE # include "process_unicode_common.h" extern unicode_config_t unicode_config; +# include "keyrecords/unicode.h" #endif #ifdef AUDIO_ENABLE # include "audio.h" @@ -97,6 +98,7 @@ void user_transport_update(void) { #endif #ifdef UNICODE_COMMON_ENABLE user_state.unicode_mode = unicode_config.input_mode; + user_state.unicode_typing_mode = typing_mode; #endif #ifdef SWAP_HANDS_ENABLE user_state.swap_hands = swap_hands; @@ -110,6 +112,7 @@ void user_transport_update(void) { user_state.raw = transport_user_state; #ifdef UNICODE_COMMON_ENABLE unicode_config.input_mode = user_state.unicode_mode; + typing_mode = user_state.unicode_typing_mode; #endif #if defined(CUSTOM_POINTING_DEVICE) tap_toggling = user_state.tap_toggling; diff --git a/users/drashna/split/transport_sync.h b/users/drashna/split/transport_sync.h index f38fdcf1ef..77e5140eda 100644 --- a/users/drashna/split/transport_sync.h +++ b/users/drashna/split/transport_sync.h @@ -12,12 +12,13 @@ extern char keylog_str[OLED_KEYLOGGER_LENGTH]; typedef union { uint32_t raw; struct { - bool audio_enable :1; - bool audio_clicky_enable :1; - bool tap_toggling :1; - uint8_t unicode_mode :3; - bool swap_hands :1; - bool host_driver_disabled :1; + bool audio_enable :1; + bool audio_clicky_enable :1; + bool tap_toggling :1; + uint8_t unicode_mode :3; + bool swap_hands :1; + bool host_driver_disabled :1; + uint8_t unicode_typing_mode :3; }; } user_runtime_config_t; diff --git a/users/drashna/template.c b/users/drashna/template.c index c4a62c6448..c032bd1ce3 100644 --- a/users/drashna/template.c +++ b/users/drashna/template.c @@ -25,21 +25,6 @@ __attribute__((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t * // And use "NEWPLACEHOLDER" for new safe range bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { - case KC_MAKE: - if (!record->event.pressed) { - SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP -#if (defined(BOOTLOADER_DFU) || defined(BOOTLOADER_LUFA_DFU) || defined(BOOTLOADER_QMK_DFU)) - ":dfu" -#elif defined(BOOTLOADER_HALFKAY) - ":teensy" -#elif defined(BOOTLOADER_CATERINA) - ":avrdude" -#endif - SS_TAP(X_ENTER)); - } - return false; - break; - case VRSN: if (record->event.pressed) { SEND_STRING(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION); diff --git a/users/drashna/template.h b/users/drashna/template.h index 26ac98edb9..bb08bb3e41 100644 --- a/users/drashna/template.h +++ b/users/drashna/template.h @@ -12,7 +12,7 @@ enum custom_keycodes { VRSN = SAFE_RANGE, // can always be here - KC_MAKE, - KC_RESET, + QK_MAKE, + QK_BOOT, NEWPLACEHOLDER // use "NEWPLACEHOLDER for keymap specific codes }; -- cgit v1.2.3