From 9632360caa5e6511b0ec13cb4c55eb64408232b5 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Tue, 30 Aug 2022 03:20:04 -0500 Subject: Use a macro to compute the size of arrays at compile time (#18044) * Add ARRAY_SIZE and CEILING utility macros * Apply a coccinelle patch to use ARRAY_SIZE * fix up some straggling items * Fix 'make test:secure' * Enhance ARRAY_SIZE macro to reject acting on pointers The previous definition would not produce a diagnostic for ``` int *p; size_t num_elem = ARRAY_SIZE(p) ``` but the new one will. * explicitly get definition of ARRAY_SIZE * Convert to ARRAY_SIZE when const is involved The following spatch finds additional instances where the array is const and the division is by the size of the type, not the size of the first element: ``` @ rule5a using "empty.iso" @ type T; const T[] E; @@ - (sizeof(E)/sizeof(T)) + ARRAY_SIZE(E) @ rule6a using "empty.iso" @ type T; const T[] E; @@ - sizeof(E)/sizeof(T) + ARRAY_SIZE(E) ``` * New instances of ARRAY_SIZE added since initial spatch run * Use `ARRAY_SIZE` in docs (found by grep) * Manually use ARRAY_SIZE hs_set is expected to be the same size as uint16_t, though it's made of two 8-bit integers * Just like char, sizeof(uint8_t) is guaranteed to be 1 This is at least true on any plausible system where qmk is actually used. Per my understanding it's universally true, assuming that uint8_t exists: https://stackoverflow.com/questions/48655310/can-i-assume-that-sizeofuint8-t-1 * Run qmk-format on core C files touched in this branch Co-authored-by: Stefan Kerkmann --- quantum/process_keycode/process_leader.c | 2 +- quantum/process_keycode/process_unicode_common.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c index ae00b3227a..3593f75f0d 100644 --- a/quantum/process_keycode/process_leader.c +++ b/quantum/process_keycode/process_leader.c @@ -58,7 +58,7 @@ bool process_leader(uint16_t keycode, keyrecord_t *record) { keycode = keycode & 0xFF; } # endif // LEADER_KEY_STRICT_KEY_PROCESSING - if (leader_sequence_size < (sizeof(leader_sequence) / sizeof(leader_sequence[0]))) { + if (leader_sequence_size < ARRAY_SIZE(leader_sequence)) { leader_sequence[leader_sequence_size] = keycode; leader_sequence_size++; } else { diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c index 8de31c055c..1c1aab8f48 100644 --- a/quantum/process_keycode/process_unicode_common.c +++ b/quantum/process_keycode/process_unicode_common.c @@ -25,7 +25,7 @@ bool unicode_saved_num_lock; #if UNICODE_SELECTED_MODES != -1 static uint8_t selected[] = {UNICODE_SELECTED_MODES}; -static int8_t selected_count = sizeof selected / sizeof *selected; +static int8_t selected_count = ARRAY_SIZE(selected); static int8_t selected_index; #endif -- cgit v1.2.3 From e4bf8323688b56cd5fc0f4f27c531f3406d40f6d Mon Sep 17 00:00:00 2001 From: Joshua Diamond Date: Wed, 31 Aug 2022 19:39:16 -0400 Subject: Add unicode mode change callbacks (#18235) --- quantum/process_keycode/process_unicode_common.c | 17 +++++++++++++++++ quantum/process_keycode/process_unicode_common.h | 3 +++ 2 files changed, 20 insertions(+) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c index 1c1aab8f48..94809cf029 100644 --- a/quantum/process_keycode/process_unicode_common.c +++ b/quantum/process_keycode/process_unicode_common.c @@ -29,6 +29,20 @@ static int8_t selected_count = ARRAY_SIZE(selected); static int8_t selected_index; #endif +/** \brief Uunicode input mode set at user level + * + * Run user code on unicode input mode change + */ +__attribute__((weak)) void unicode_input_mode_set_user(uint8_t input_mode) {} + +/** \brief unicode input mode set at keyboard level + * + * Run keyboard code on unicode input mode change + */ +__attribute__((weak)) void unicode_input_mode_set_kb(uint8_t input_mode) { + unicode_input_mode_set_user(input_mode); +} + void unicode_input_mode_init(void) { unicode_config.raw = eeprom_read_byte(EECONFIG_UNICODEMODE); #if UNICODE_SELECTED_MODES != -1 @@ -50,6 +64,7 @@ void unicode_input_mode_init(void) { unicode_config.input_mode = selected[selected_index = 0]; # endif #endif + unicode_input_mode_set_kb(unicode_config.input_mode); dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode); } @@ -60,6 +75,7 @@ uint8_t get_unicode_input_mode(void) { void set_unicode_input_mode(uint8_t mode) { unicode_config.input_mode = mode; persist_unicode_input_mode(); + unicode_input_mode_set_kb(mode); dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode); } @@ -73,6 +89,7 @@ void cycle_unicode_input_mode(int8_t offset) { # if UNICODE_CYCLE_PERSIST persist_unicode_input_mode(); # endif + unicode_input_mode_set_kb(unicode_config.input_mode); dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode); #endif } diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h index 15e798dbb3..bdc7a1dedd 100644 --- a/quantum/process_keycode/process_unicode_common.h +++ b/quantum/process_keycode/process_unicode_common.h @@ -87,6 +87,9 @@ void unicode_input_start(void); void unicode_input_finish(void); void unicode_input_cancel(void); +void unicode_input_mode_set_user(uint8_t input_mode); +void unicode_input_mode_set_kb(uint8_t input_mode); + void register_hex(uint16_t hex); void register_hex32(uint32_t hex); void register_unicode(uint32_t code_point); -- cgit v1.2.3 From 8833b283610ce34e9be65ed3fc2c477258188de7 Mon Sep 17 00:00:00 2001 From: Ryan Date: Wed, 7 Sep 2022 03:07:08 +1000 Subject: Remove `UNICODE_KEY_OSX` and `UC_OSX` (#18290) --- quantum/process_keycode/process_unicode_common.h | 9 --------- 1 file changed, 9 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h index bdc7a1dedd..0fe672d26a 100644 --- a/quantum/process_keycode/process_unicode_common.h +++ b/quantum/process_keycode/process_unicode_common.h @@ -49,15 +49,6 @@ # define UNICODE_TYPE_DELAY 10 #endif -// Deprecated aliases -#if !defined(UNICODE_KEY_MAC) && defined(UNICODE_KEY_OSX) -# define UNICODE_KEY_MAC UNICODE_KEY_OSX -#endif -#if !defined(UNICODE_SONG_MAC) && defined(UNICODE_SONG_OSX) -# define UNICODE_SONG_MAC UNICODE_SONG_OSX -#endif -#define UC_OSX UC_MAC - enum unicode_input_modes { UC_MAC, // macOS using Unicode Hex Input UC_LNX, // Linux using IBus -- cgit v1.2.3 From 3d667f09705fa780bd5881cfa3b3cb10fa41b1fe Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 13 Sep 2022 01:49:04 +1000 Subject: Refactor Unicode feature (#18333) --- quantum/process_keycode/process_ucis.c | 17 +- quantum/process_keycode/process_ucis.h | 6 +- quantum/process_keycode/process_unicode.c | 12 +- quantum/process_keycode/process_unicode.h | 5 +- quantum/process_keycode/process_unicode_common.c | 315 +---------------------- quantum/process_keycode/process_unicode_common.h | 178 +------------ quantum/process_keycode/process_unicodemap.c | 5 + quantum/process_keycode/process_unicodemap.h | 6 +- 8 files changed, 42 insertions(+), 502 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_ucis.c b/quantum/process_keycode/process_ucis.c index 6a8d8f0ff6..646471bc4d 100644 --- a/quantum/process_keycode/process_ucis.c +++ b/quantum/process_keycode/process_ucis.c @@ -15,6 +15,9 @@ */ #include "process_ucis.h" +#include "unicode.h" +#include "keycode.h" +#include "wait.h" qk_ucis_state_t qk_ucis_state; @@ -26,9 +29,7 @@ void qk_ucis_start(void) { } __attribute__((weak)) void qk_ucis_start_user(void) { - unicode_input_start(); - register_hex(0x2328); // ⌨ - unicode_input_finish(); + register_unicode(0x2328); // ⌨ } __attribute__((weak)) void qk_ucis_success(uint8_t symbol_index) {} @@ -51,10 +52,7 @@ static bool is_uni_seq(char *seq) { __attribute__((weak)) void qk_ucis_symbol_fallback(void) { for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { - uint8_t keycode = qk_ucis_state.codes[i]; - register_code(keycode); - unregister_code(keycode); - wait_ms(UNICODE_TYPE_DELAY); + tap_code(qk_ucis_state.codes[i]); } } @@ -63,7 +61,6 @@ __attribute__((weak)) void qk_ucis_cancel(void) {} void register_ucis(const uint32_t *code_points) { for (int i = 0; i < UCIS_MAX_CODE_POINTS && code_points[i]; i++) { register_unicode(code_points[i]); - wait_ms(UNICODE_TYPE_DELAY); } } @@ -94,9 +91,7 @@ bool process_ucis(uint16_t keycode, keyrecord_t *record) { case KC_ENTER: case KC_ESCAPE: for (uint8_t i = 0; i < qk_ucis_state.count; i++) { - register_code(KC_BACKSPACE); - unregister_code(KC_BACKSPACE); - wait_ms(UNICODE_TYPE_DELAY); + tap_code(KC_BACKSPACE); } if (keycode == KC_ESCAPE) { diff --git a/quantum/process_keycode/process_ucis.h b/quantum/process_keycode/process_ucis.h index a667430bda..3de0707762 100644 --- a/quantum/process_keycode/process_ucis.h +++ b/quantum/process_keycode/process_ucis.h @@ -16,8 +16,10 @@ #pragma once -#include "quantum.h" -#include "process_unicode_common.h" +#include +#include + +#include "action.h" #ifndef UCIS_MAX_SYMBOL_LENGTH # define UCIS_MAX_SYMBOL_LENGTH 32 diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c index 18a1d8bc1f..99cc2f5f26 100644 --- a/quantum/process_keycode/process_unicode.c +++ b/quantum/process_keycode/process_unicode.c @@ -15,14 +15,14 @@ */ #include "process_unicode.h" -#include "action_util.h" -#include "eeprom.h" +#include "unicode.h" +#include "quantum_keycodes.h" bool process_unicode(uint16_t keycode, keyrecord_t *record) { - if (keycode >= QK_UNICODE && keycode <= QK_UNICODE_MAX && record->event.pressed) { - unicode_input_start(); - register_hex(keycode & 0x7FFF); - unicode_input_finish(); + if (record->event.pressed) { + if (keycode >= QK_UNICODE && keycode <= QK_UNICODE_MAX) { + register_unicode(keycode & 0x7FFF); + } } return true; } diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h index 22765ad560..341bc8d861 100644 --- a/quantum/process_keycode/process_unicode.h +++ b/quantum/process_keycode/process_unicode.h @@ -16,6 +16,9 @@ #pragma once -#include "process_unicode_common.h" +#include +#include + +#include "action.h" bool process_unicode(uint16_t keycode, keyrecord_t *record); diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c index 94809cf029..bd5fc560f3 100644 --- a/quantum/process_keycode/process_unicode_common.c +++ b/quantum/process_keycode/process_unicode_common.c @@ -15,306 +15,17 @@ */ #include "process_unicode_common.h" -#include "eeprom.h" -#include "utf8.h" +#include "unicode.h" +#include "action_util.h" +#include "keycode.h" -unicode_config_t unicode_config; -uint8_t unicode_saved_mods; -bool unicode_saved_caps_lock; -bool unicode_saved_num_lock; - -#if UNICODE_SELECTED_MODES != -1 -static uint8_t selected[] = {UNICODE_SELECTED_MODES}; -static int8_t selected_count = ARRAY_SIZE(selected); -static int8_t selected_index; -#endif - -/** \brief Uunicode input mode set at user level - * - * Run user code on unicode input mode change - */ -__attribute__((weak)) void unicode_input_mode_set_user(uint8_t input_mode) {} - -/** \brief unicode input mode set at keyboard level - * - * Run keyboard code on unicode input mode change - */ -__attribute__((weak)) void unicode_input_mode_set_kb(uint8_t input_mode) { - unicode_input_mode_set_user(input_mode); -} - -void unicode_input_mode_init(void) { - unicode_config.raw = eeprom_read_byte(EECONFIG_UNICODEMODE); -#if UNICODE_SELECTED_MODES != -1 -# if UNICODE_CYCLE_PERSIST - // Find input_mode in selected modes - int8_t i; - for (i = 0; i < selected_count; i++) { - if (selected[i] == unicode_config.input_mode) { - selected_index = i; - break; - } - } - if (i == selected_count) { - // Not found: input_mode isn't selected, change to one that is - unicode_config.input_mode = selected[selected_index = 0]; - } -# else - // Always change to the first selected input mode - unicode_config.input_mode = selected[selected_index = 0]; -# endif -#endif - unicode_input_mode_set_kb(unicode_config.input_mode); - dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode); -} - -uint8_t get_unicode_input_mode(void) { - return unicode_config.input_mode; -} - -void set_unicode_input_mode(uint8_t mode) { - unicode_config.input_mode = mode; - persist_unicode_input_mode(); - unicode_input_mode_set_kb(mode); - dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode); -} - -void cycle_unicode_input_mode(int8_t offset) { -#if UNICODE_SELECTED_MODES != -1 - selected_index = (selected_index + offset) % selected_count; - if (selected_index < 0) { - selected_index += selected_count; - } - unicode_config.input_mode = selected[selected_index]; -# if UNICODE_CYCLE_PERSIST - persist_unicode_input_mode(); -# endif - unicode_input_mode_set_kb(unicode_config.input_mode); - dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode); -#endif -} - -void persist_unicode_input_mode(void) { - eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode); -} - -__attribute__((weak)) void unicode_input_start(void) { - unicode_saved_caps_lock = host_keyboard_led_state().caps_lock; - unicode_saved_num_lock = host_keyboard_led_state().num_lock; - - // Note the order matters here! - // Need to do this before we mess around with the mods, or else - // UNICODE_KEY_LNX (which is usually Ctrl-Shift-U) might not work - // correctly in the shifted case. - if (unicode_config.input_mode == UC_LNX && unicode_saved_caps_lock) { - tap_code(KC_CAPS_LOCK); - } - - unicode_saved_mods = get_mods(); // Save current mods - clear_mods(); // Unregister mods to start from a clean state - clear_weak_mods(); - - switch (unicode_config.input_mode) { - case UC_MAC: - register_code(UNICODE_KEY_MAC); - break; - case UC_LNX: - tap_code16(UNICODE_KEY_LNX); - break; - case UC_WIN: - // For increased reliability, use numpad keys for inputting digits - if (!unicode_saved_num_lock) { - tap_code(KC_NUM_LOCK); - } - register_code(KC_LEFT_ALT); - wait_ms(UNICODE_TYPE_DELAY); - tap_code(KC_KP_PLUS); - break; - case UC_WINC: - tap_code(UNICODE_KEY_WINC); - tap_code(KC_U); - break; - case UC_EMACS: - // The usual way to type unicode in emacs is C-x-8 then the unicode number in hex - tap_code16(LCTL(KC_X)); - tap_code16(KC_8); - tap_code16(KC_ENTER); - break; - } - - wait_ms(UNICODE_TYPE_DELAY); -} - -__attribute__((weak)) void unicode_input_finish(void) { - switch (unicode_config.input_mode) { - case UC_MAC: - unregister_code(UNICODE_KEY_MAC); - break; - case UC_LNX: - tap_code(KC_SPACE); - if (unicode_saved_caps_lock) { - tap_code(KC_CAPS_LOCK); - } - break; - case UC_WIN: - unregister_code(KC_LEFT_ALT); - if (!unicode_saved_num_lock) { - tap_code(KC_NUM_LOCK); - } - break; - case UC_WINC: - tap_code(KC_ENTER); - break; - case UC_EMACS: - tap_code16(KC_ENTER); - break; - } - - set_mods(unicode_saved_mods); // Reregister previously set mods -} - -__attribute__((weak)) void unicode_input_cancel(void) { - switch (unicode_config.input_mode) { - case UC_MAC: - unregister_code(UNICODE_KEY_MAC); - break; - case UC_LNX: - tap_code(KC_ESCAPE); - if (unicode_saved_caps_lock) { - tap_code(KC_CAPS_LOCK); - } - break; - case UC_WINC: - tap_code(KC_ESCAPE); - break; - case UC_WIN: - unregister_code(KC_LEFT_ALT); - if (!unicode_saved_num_lock) { - tap_code(KC_NUM_LOCK); - } - break; - case UC_EMACS: - tap_code16(LCTL(KC_G)); // C-g cancels - break; - } - - set_mods(unicode_saved_mods); // Reregister previously set mods -} - -// clang-format off - -static void send_nibble_wrapper(uint8_t digit) { - if (unicode_config.input_mode == UC_WIN) { - uint8_t kc = digit < 10 - ? KC_KP_1 + (10 + digit - 1) % 10 - : KC_A + (digit - 10); - tap_code(kc); - return; - } - send_nibble(digit); -} - -// clang-format on - -void register_hex(uint16_t hex) { - for (int i = 3; i >= 0; i--) { - uint8_t digit = ((hex >> (i * 4)) & 0xF); - send_nibble_wrapper(digit); - } -} - -void register_hex32(uint32_t hex) { - bool onzerostart = true; - for (int i = 7; i >= 0; i--) { - if (i <= 3) { - onzerostart = false; - } - uint8_t digit = ((hex >> (i * 4)) & 0xF); - if (digit == 0) { - if (!onzerostart) { - send_nibble_wrapper(digit); - } - } else { - send_nibble_wrapper(digit); - onzerostart = false; - } - } -} - -void register_unicode(uint32_t code_point) { - if (code_point > 0x10FFFF || (code_point > 0xFFFF && unicode_config.input_mode == UC_WIN)) { - // Code point out of range, do nothing - return; - } - - unicode_input_start(); - if (code_point > 0xFFFF && unicode_config.input_mode == UC_MAC) { - // Convert code point to UTF-16 surrogate pair on macOS - code_point -= 0x10000; - uint32_t lo = code_point & 0x3FF, hi = (code_point & 0xFFC00) >> 10; - register_hex32(hi + 0xD800); - register_hex32(lo + 0xDC00); - } else { - register_hex32(code_point); - } - unicode_input_finish(); -} - -void send_unicode_string(const char *str) { - if (!str) { - return; - } - - while (*str) { - int32_t code_point = 0; - str = decode_utf8(str, &code_point); - - if (code_point >= 0) { - register_unicode(code_point); - } - } -} - -// clang-format off - -static void audio_helper(void) { -#ifdef AUDIO_ENABLE - switch (get_unicode_input_mode()) { -# ifdef UNICODE_SONG_MAC - static float song_mac[][2] = UNICODE_SONG_MAC; - case UC_MAC: - PLAY_SONG(song_mac); - break; -# endif -# ifdef UNICODE_SONG_LNX - static float song_lnx[][2] = UNICODE_SONG_LNX; - case UC_LNX: - PLAY_SONG(song_lnx); - break; -# endif -# ifdef UNICODE_SONG_WIN - static float song_win[][2] = UNICODE_SONG_WIN; - case UC_WIN: - PLAY_SONG(song_win); - break; -# endif -# ifdef UNICODE_SONG_BSD - static float song_bsd[][2] = UNICODE_SONG_BSD; - case UC_BSD: - PLAY_SONG(song_bsd); - break; -# endif -# ifdef UNICODE_SONG_WINC - static float song_winc[][2] = UNICODE_SONG_WINC; - case UC_WINC: - PLAY_SONG(song_winc); - break; -# endif - } +#if defined(UNICODE_ENABLE) +# include "process_unicode.h" +#elif defined(UNICODEMAP_ENABLE) +# include "process_unicodemap.h" +#elif defined(UCIS_ENABLE) +# include "process_ucis.h" #endif -} - -// clang-format on bool process_unicode_common(uint16_t keycode, keyrecord_t *record) { if (record->event.pressed) { @@ -322,35 +33,27 @@ bool process_unicode_common(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case UNICODE_MODE_FORWARD: cycle_unicode_input_mode(shifted ? -1 : +1); - audio_helper(); break; case UNICODE_MODE_REVERSE: cycle_unicode_input_mode(shifted ? +1 : -1); - audio_helper(); break; case UNICODE_MODE_MAC: set_unicode_input_mode(UC_MAC); - audio_helper(); break; case UNICODE_MODE_LNX: set_unicode_input_mode(UC_LNX); - audio_helper(); break; case UNICODE_MODE_WIN: set_unicode_input_mode(UC_WIN); - audio_helper(); break; case UNICODE_MODE_BSD: set_unicode_input_mode(UC_BSD); - audio_helper(); break; case UNICODE_MODE_WINC: set_unicode_input_mode(UC_WINC); - audio_helper(); break; case UNICODE_MODE_EMACS: set_unicode_input_mode(UC_EMACS); - audio_helper(); break; } } diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h index 0fe672d26a..fd09a41818 100644 --- a/quantum/process_keycode/process_unicode_common.h +++ b/quantum/process_keycode/process_unicode_common.h @@ -16,181 +16,9 @@ #pragma once -#include "quantum.h" +#include +#include -#if defined(UNICODE_ENABLE) + defined(UNICODEMAP_ENABLE) + defined(UCIS_ENABLE) > 1 -# error "Cannot enable more than one Unicode method (UNICODE, UNICODEMAP, UCIS) at the same time" -#endif - -// Keycodes used for starting Unicode input on different platforms -#ifndef UNICODE_KEY_MAC -# define UNICODE_KEY_MAC KC_LEFT_ALT -#endif -#ifndef UNICODE_KEY_LNX -# define UNICODE_KEY_LNX LCTL(LSFT(KC_U)) -#endif -#ifndef UNICODE_KEY_WINC -# define UNICODE_KEY_WINC KC_RIGHT_ALT -#endif - -// Comma-delimited, ordered list of input modes selected for use (e.g. in cycle) -// Example: #define UNICODE_SELECTED_MODES UC_WINC, UC_LNX -#ifndef UNICODE_SELECTED_MODES -# define UNICODE_SELECTED_MODES -1 -#endif - -// Whether input mode changes in cycle should be written to EEPROM -#ifndef UNICODE_CYCLE_PERSIST -# define UNICODE_CYCLE_PERSIST true -#endif - -// Delay between starting Unicode input and sending a sequence, in ms -#ifndef UNICODE_TYPE_DELAY -# define UNICODE_TYPE_DELAY 10 -#endif - -enum unicode_input_modes { - UC_MAC, // macOS using Unicode Hex Input - UC_LNX, // Linux using IBus - UC_WIN, // Windows using EnableHexNumpad - UC_BSD, // BSD (not implemented) - UC_WINC, // Windows using WinCompose (https://github.com/samhocevar/wincompose) - UC_EMACS, // Emacs is an operating system in search of a good text editor - UC__COUNT // Number of available input modes (always leave at the end) -}; - -typedef union { - uint32_t raw; - struct { - uint8_t input_mode : 8; - }; -} unicode_config_t; - -extern unicode_config_t unicode_config; - -void unicode_input_mode_init(void); -uint8_t get_unicode_input_mode(void); -void set_unicode_input_mode(uint8_t mode); -void cycle_unicode_input_mode(int8_t offset); -void persist_unicode_input_mode(void); - -void unicode_input_start(void); -void unicode_input_finish(void); -void unicode_input_cancel(void); - -void unicode_input_mode_set_user(uint8_t input_mode); -void unicode_input_mode_set_kb(uint8_t input_mode); - -void register_hex(uint16_t hex); -void register_hex32(uint32_t hex); -void register_unicode(uint32_t code_point); - -void send_unicode_string(const char *str); +#include "action.h" bool process_unicode_common(uint16_t keycode, keyrecord_t *record); - -#define UC_BSPC UC(0x0008) -#define UC_SPC UC(0x0020) - -#define UC_EXLM UC(0x0021) -#define UC_DQUT UC(0x0022) -#define UC_HASH UC(0x0023) -#define UC_DLR UC(0x0024) -#define UC_PERC UC(0x0025) -#define UC_AMPR UC(0x0026) -#define UC_QUOT UC(0x0027) -#define UC_LPRN UC(0x0028) -#define UC_RPRN UC(0x0029) -#define UC_ASTR UC(0x002A) -#define UC_PLUS UC(0x002B) -#define UC_COMM UC(0x002C) -#define UC_DASH UC(0x002D) -#define UC_DOT UC(0x002E) -#define UC_SLSH UC(0x002F) - -#define UC_0 UC(0x0030) -#define UC_1 UC(0x0031) -#define UC_2 UC(0x0032) -#define UC_3 UC(0x0033) -#define UC_4 UC(0x0034) -#define UC_5 UC(0x0035) -#define UC_6 UC(0x0036) -#define UC_7 UC(0x0037) -#define UC_8 UC(0x0038) -#define UC_9 UC(0x0039) - -#define UC_COLN UC(0x003A) -#define UC_SCLN UC(0x003B) -#define UC_LT UC(0x003C) -#define UC_EQL UC(0x003D) -#define UC_GT UC(0x003E) -#define UC_QUES UC(0x003F) -#define UC_AT UC(0x0040) - -#define UC_A UC(0x0041) -#define UC_B UC(0x0042) -#define UC_C UC(0x0043) -#define UC_D UC(0x0044) -#define UC_E UC(0x0045) -#define UC_F UC(0x0046) -#define UC_G UC(0x0047) -#define UC_H UC(0x0048) -#define UC_I UC(0x0049) -#define UC_J UC(0x004A) -#define UC_K UC(0x004B) -#define UC_L UC(0x004C) -#define UC_M UC(0x004D) -#define UC_N UC(0x004E) -#define UC_O UC(0x004F) -#define UC_P UC(0x0050) -#define UC_Q UC(0x0051) -#define UC_R UC(0x0052) -#define UC_S UC(0x0053) -#define UC_T UC(0x0054) -#define UC_U UC(0x0055) -#define UC_V UC(0x0056) -#define UC_W UC(0x0057) -#define UC_X UC(0x0058) -#define UC_Y UC(0x0059) -#define UC_Z UC(0x005A) - -#define UC_LBRC UC(0x005B) -#define UC_BSLS UC(0x005C) -#define UC_RBRC UC(0x005D) -#define UC_CIRM UC(0x005E) -#define UC_UNDR UC(0x005F) - -#define UC_GRV UC(0x0060) - -#define UC_a UC(0x0061) -#define UC_b UC(0x0062) -#define UC_c UC(0x0063) -#define UC_d UC(0x0064) -#define UC_e UC(0x0065) -#define UC_f UC(0x0066) -#define UC_g UC(0x0067) -#define UC_h UC(0x0068) -#define UC_i UC(0x0069) -#define UC_j UC(0x006A) -#define UC_k UC(0x006B) -#define UC_l UC(0x006C) -#define UC_m UC(0x006D) -#define UC_n UC(0x006E) -#define UC_o UC(0x006F) -#define UC_p UC(0x0070) -#define UC_q UC(0x0071) -#define UC_r UC(0x0072) -#define UC_s UC(0x0073) -#define UC_t UC(0x0074) -#define UC_u UC(0x0075) -#define UC_v UC(0x0076) -#define UC_w UC(0x0077) -#define UC_x UC(0x0078) -#define UC_y UC(0x0079) -#define UC_z UC(0x007A) - -#define UC_LCBR UC(0x007B) -#define UC_PIPE UC(0x007C) -#define UC_RCBR UC(0x007D) -#define UC_TILD UC(0x007E) -#define UC_DEL UC(0x007F) diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c index 459397014d..979d773b05 100644 --- a/quantum/process_keycode/process_unicodemap.c +++ b/quantum/process_keycode/process_unicodemap.c @@ -15,6 +15,11 @@ */ #include "process_unicodemap.h" +#include "unicode.h" +#include "quantum_keycodes.h" +#include "keycode.h" +#include "action_util.h" +#include "host.h" __attribute__((weak)) uint16_t unicodemap_index(uint16_t keycode) { if (keycode >= QK_UNICODEMAP_PAIR) { diff --git a/quantum/process_keycode/process_unicodemap.h b/quantum/process_keycode/process_unicodemap.h index c429859bbb..73f5449864 100644 --- a/quantum/process_keycode/process_unicodemap.h +++ b/quantum/process_keycode/process_unicodemap.h @@ -16,7 +16,11 @@ #pragma once -#include "process_unicode_common.h" +#include +#include + +#include "action.h" +#include "progmem.h" extern const uint32_t PROGMEM unicode_map[]; -- cgit v1.2.3 From fb29c0ae53e32fb049516fcbe0f7863882ca9173 Mon Sep 17 00:00:00 2001 From: Drashna Jaelre Date: Sat, 17 Sep 2022 00:50:54 -0700 Subject: [Core] Add getreuer's Autocorrect feature to core (#15699) Co-authored-by: Albert Y <76888457+filterpaper@users.noreply.github.com> --- quantum/process_keycode/autocorrect_data_default.h | 85 ++++++ quantum/process_keycode/process_autocorrect.c | 287 +++++++++++++++++++++ quantum/process_keycode/process_autocorrect.h | 17 ++ 3 files changed, 389 insertions(+) create mode 100644 quantum/process_keycode/autocorrect_data_default.h create mode 100644 quantum/process_keycode/process_autocorrect.c create mode 100644 quantum/process_keycode/process_autocorrect.h (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/autocorrect_data_default.h b/quantum/process_keycode/autocorrect_data_default.h new file mode 100644 index 0000000000..bfc29666df --- /dev/null +++ b/quantum/process_keycode/autocorrect_data_default.h @@ -0,0 +1,85 @@ +// Generated code. + +// Autocorrection dictionary (70 entries): +// :guage -> gauge +// :the:the: -> the +// :thier -> their +// :ture -> true +// accomodate -> accommodate +// acommodate -> accommodate +// aparent -> apparent +// aparrent -> apparent +// apparant -> apparent +// apparrent -> apparent +// aquire -> acquire +// becuase -> because +// cauhgt -> caught +// cheif -> chief +// choosen -> chosen +// cieling -> ceiling +// collegue -> colleague +// concensus -> consensus +// contians -> contains +// cosnt -> const +// dervied -> derived +// fales -> false +// fasle -> false +// fitler -> filter +// flase -> false +// foward -> forward +// frequecy -> frequency +// gaurantee -> guarantee +// guaratee -> guarantee +// heigth -> height +// heirarchy -> hierarchy +// inclued -> include +// interator -> iterator +// intput -> input +// invliad -> invalid +// lenght -> length +// liasion -> liaison +// libary -> library +// listner -> listener +// looses: -> loses +// looup -> lookup +// manefist -> manifest +// namesapce -> namespace +// namespcae -> namespace +// occassion -> occasion +// occured -> occurred +// ouptut -> output +// ouput -> output +// overide -> override +// postion -> position +// priviledge -> privilege +// psuedo -> pseudo +// recieve -> receive +// refered -> referred +// relevent -> relevant +// repitition -> repetition +// retrun -> return +// retun -> return +// reuslt -> result +// reutrn -> return +// saftey -> safety +// seperate -> separate +// singed -> signed +// stirng -> string +// strign -> string +// swithc -> switch +// swtich -> switch +// thresold -> threshold +// udpate -> update +// widht -> width + +#define AUTOCORRECT_MIN_LENGTH 5 // ":ture" +#define AUTOCORRECT_MAX_LENGTH 10 // "accomodate" + +#define DICTIONARY_SIZE 1104 + +static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {108, 43, 0, 6, 71, 0, 7, 81, 0, 8, 199, 0, 9, 240, 1, 10, 250, 1, 11, 26, 2, 17, 53, 2, 18, 190, 2, 19, 202, 2, 21, 212, 2, 22, 20, 3, 23, 67, 3, 28, 16, 4, 0, 72, 50, 0, 22, 60, 0, 0, 11, 23, 44, 8, 11, 23, 44, 0, 132, 0, 8, 22, 18, 18, 15, 0, 132, 115, 101, 115, 0, 11, 23, 12, 26, 22, 0, 129, 99, 104, 0, 68, 94, 0, 8, 106, 0, 15, 174, 0, 21, 187, 0, 0, 12, 15, 25, 17, 12, 0, 131, 97, 108, 105, 100, 0, 74, 119, 0, 12, 129, 0, 21, 140, 0, 24, 165, 0, 0, 17, 12, 22, 0, 131, 103, 110, 101, 100, 0, 25, 21, 8, 7, 0, 131, 105, 118, 101, 100, 0, 72, 147, 0, 24, 156, 0, 0, 9, 8, 21, 0, 129, 114, 101, 100, 0, 6, 6, 18, 0, 129, 114, 101, 100, 0, 15, 6, 17, 12, 0, 129, 100, 101, 0, 18, 22, 8, 21, 11, 23, 0, 130, 104, 111, + 108, 100, 0, 4, 26, 18, 9, 0, 131, 114, 119, 97, 114, 100, 0, 68, 233, 0, 6, 246, 0, 7, 4, 1, 8, 16, 1, 10, 52, 1, 15, 81, 1, 21, 90, 1, 22, 117, 1, 23, 144, 1, 24, 215, 1, 25, 228, 1, 0, 6, 19, 22, 8, 16, 4, 17, 0, 130, 97, 99, 101, 0, 19, 4, 22, 8, 16, 4, 17, 0, 131, 112, 97, 99, 101, 0, 12, 21, 8, 25, 18, 0, 130, 114, 105, 100, 101, 0, 23, 0, 68, 25, 1, 17, 36, 1, 0, 21, 4, 24, 10, 0, 130, 110, 116, 101, 101, 0, 4, 21, 24, 4, 10, 0, 135, 117, 97, 114, 97, 110, 116, 101, 101, 0, 68, 59, 1, 7, 69, 1, 0, 24, 10, 44, 0, 131, 97, 117, 103, 101, 0, 8, 15, 12, 25, 12, 21, 19, 0, 130, 103, 101, 0, 22, 4, 9, 0, 130, 108, 115, 101, 0, 76, 97, 1, 24, 109, 1, 0, 24, 20, 4, 0, 132, 99, 113, 117, 105, 114, 101, 0, 23, 44, 0, + 130, 114, 117, 101, 0, 4, 0, 79, 126, 1, 24, 134, 1, 0, 9, 0, 131, 97, 108, 115, 101, 0, 6, 8, 5, 0, 131, 97, 117, 115, 101, 0, 4, 0, 71, 156, 1, 19, 193, 1, 21, 203, 1, 0, 18, 16, 0, 80, 166, 1, 18, 181, 1, 0, 18, 6, 4, 0, 135, 99, 111, 109, 109, 111, 100, 97, 116, 101, 0, 6, 6, 4, 0, 132, 109, 111, 100, 97, 116, 101, 0, 7, 24, 0, 132, 112, 100, 97, 116, 101, 0, 8, 19, 8, 22, 0, 132, 97, 114, 97, 116, 101, 0, 10, 8, 15, 15, 18, 6, 0, 130, 97, 103, 117, 101, 0, 8, 12, 6, 8, 21, 0, 131, 101, 105, 118, 101, 0, 12, 8, 11, 6, 0, 130, 105, 101, 102, 0, 17, 0, 76, 3, 2, 21, 16, 2, 0, 15, 8, 12, 6, 0, 133, 101, 105, 108, 105, 110, 103, 0, 12, 23, 22, 0, 131, 114, 105, 110, 103, 0, 70, 33, 2, 23, 44, 2, 0, 12, 23, 26, 22, 0, 131, 105, + 116, 99, 104, 0, 10, 12, 8, 11, 0, 129, 104, 116, 0, 72, 69, 2, 10, 80, 2, 18, 89, 2, 21, 156, 2, 24, 167, 2, 0, 22, 18, 18, 11, 6, 0, 131, 115, 101, 110, 0, 12, 21, 23, 22, 0, 129, 110, 103, 0, 12, 0, 86, 98, 2, 23, 124, 2, 0, 68, 105, 2, 22, 114, 2, 0, 12, 15, 0, 131, 105, 115, 111, 110, 0, 4, 6, 6, 18, 0, 131, 105, 111, 110, 0, 76, 131, 2, 22, 146, 2, 0, 23, 12, 19, 8, 21, 0, 134, 101, 116, 105, 116, 105, 111, 110, 0, 18, 19, 0, 131, 105, 116, 105, 111, 110, 0, 23, 24, 8, 21, 0, 131, 116, 117, 114, 110, 0, 85, 174, 2, 23, 183, 2, 0, 23, 8, 21, 0, 130, 117, 114, 110, 0, 8, 21, 0, 128, 114, 110, 0, 7, 8, 24, 22, 19, 0, 131, 101, 117, 100, 111, 0, 24, 18, 18, 15, 0, 129, 107, 117, 112, 0, 72, 219, 2, 18, 3, 3, 0, 76, 229, 2, 15, 238, + 2, 17, 248, 2, 0, 11, 23, 44, 0, 130, 101, 105, 114, 0, 23, 12, 9, 0, 131, 108, 116, 101, 114, 0, 23, 22, 12, 15, 0, 130, 101, 110, 101, 114, 0, 23, 4, 21, 8, 23, 17, 12, 0, 135, 116, 101, 114, 97, 116, 111, 114, 0, 72, 30, 3, 17, 38, 3, 24, 51, 3, 0, 15, 4, 9, 0, 129, 115, 101, 0, 4, 12, 23, 17, 18, 6, 0, 131, 97, 105, 110, 115, 0, 22, 17, 8, 6, 17, 18, 6, 0, 133, 115, 101, 110, 115, 117, 115, 0, 74, 86, 3, 11, 96, 3, 15, 118, 3, 17, 129, 3, 22, 218, 3, 24, 232, 3, 0, 11, 24, 4, 6, 0, 130, 103, 104, 116, 0, 71, 103, 3, 10, 110, 3, 0, 12, 26, 0, 129, 116, 104, 0, 17, 8, 15, 0, 129, 116, 104, 0, 22, 24, 8, 21, 0, 131, 115, 117, 108, 116, 0, 68, 139, 3, 8, 150, 3, 22, 210, 3, 0, 21, 4, 19, 19, 4, 0, 130, 101, 110, 116, 0, 85, 157, + 3, 25, 200, 3, 0, 68, 164, 3, 21, 175, 3, 0, 19, 4, 0, 132, 112, 97, 114, 101, 110, 116, 0, 4, 19, 0, 68, 185, 3, 19, 193, 3, 0, 133, 112, 97, 114, 101, 110, 116, 0, 4, 0, 131, 101, 110, 116, 0, 8, 15, 8, 21, 0, 130, 97, 110, 116, 0, 18, 6, 0, 130, 110, 115, 116, 0, 12, 9, 8, 17, 4, 16, 0, 132, 105, 102, 101, 115, 116, 0, 83, 239, 3, 23, 6, 4, 0, 87, 246, 3, 24, 254, 3, 0, 17, 12, 0, 131, 112, 117, 116, 0, 18, 0, 130, 116, 112, 117, 116, 0, 19, 24, 18, 0, 131, 116, 112, 117, 116, 0, 70, 29, 4, 8, 41, 4, 11, 51, 4, 21, 69, 4, 0, 8, 24, 20, 8, 21, 9, 0, 129, 110, 99, 121, 0, 23, 9, 4, 22, 0, 130, 101, 116, 121, 0, 6, 21, 4, 21, 12, 8, 11, 0, 135, 105, 101, 114, 97, 114, 99, 104, 121, 0, 4, 5, 12, 15, 0, 130, 114, 97, 114, 121, 0}; diff --git a/quantum/process_keycode/process_autocorrect.c b/quantum/process_keycode/process_autocorrect.c new file mode 100644 index 0000000000..abae5e7811 --- /dev/null +++ b/quantum/process_keycode/process_autocorrect.c @@ -0,0 +1,287 @@ +// Copyright 2021 Google LLC +// Copyright 2021 @filterpaper +// SPDX-License-Identifier: Apache-2.0 +// Original source: https://getreuer.info/posts/keyboards/autocorrection + +#include "process_autocorrect.h" +#include +#include "keycode_config.h" + +#if __has_include("autocorrect_data.h") +# include "autocorrect_data.h" +#else +# pragma message "Autocorrect is using the default library." +# include "autocorrect_data_default.h" +#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 keymap_config.autocorrect_enable; +} + +/** + * @brief Enables autocorrect and saves state to eeprom + * + */ +void autocorrect_enable(void) { + keymap_config.autocorrect_enable = true; + eeconfig_update_keymap(keymap_config.raw); +} + +/** + * @brief Disables autocorrect and saves state to eeprom + * + */ +void autocorrect_disable(void) { + keymap_config.autocorrect_enable = false; + typo_buffer_size = 0; + eeconfig_update_keymap(keymap_config.raw); +} + +/** + * @brief Toggles autocorrect's status and save state to eeprom + * + */ +void autocorrect_toggle(void) { + keymap_config.autocorrect_enable = !keymap_config.autocorrect_enable; + typo_buffer_size = 0; + eeconfig_update_keymap(keymap_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 + * + * @param keycode Keycode registered by matrix press, per keymap + * @param record keyrecord_t structure + * @return true Continue processing keycodes, and send to host + * @return false Stop processing keycodes, and don't send to host + */ +bool process_autocorrect(uint16_t keycode, keyrecord_t *record) { + uint8_t mods = get_mods(); +#ifndef NO_ACTION_ONESHOT + mods |= get_oneshot_mods(); +#endif + + 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 (!keymap_config.autocorrect_enable) { + 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_A ... KC_Z: + // process normally + break; + 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; + 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; + case KC_QUOTE: + // Treat " (shifted ') as a word boundary. + if ((mods & MOD_MASK_SHIFT) != 0) { + keycode = KC_SPC; + } + 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 >= 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 < AUTOCORRECT_MIN_LENGTH) { + return true; + } + + // Check for typo in buffer using a trie stored in `autocorrect_data`. + uint16_t state = 0; + 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. + code &= 63; + 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(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(autocorrect_data + (++state)))) { + ++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 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)); + } + + if (keycode == KC_SPC) { + typo_buffer[0] = KC_SPC; + typo_buffer_size = 1; + return true; + } else { + typo_buffer_size = 0; + return false; + } + } + } + return true; +} diff --git a/quantum/process_keycode/process_autocorrect.h b/quantum/process_keycode/process_autocorrect.h new file mode 100644 index 0000000000..c7596107e5 --- /dev/null +++ b/quantum/process_keycode/process_autocorrect.h @@ -0,0 +1,17 @@ +// Copyright 2021 Google LLC +// Copyright 2021 @filterpaper +// SPDX-License-Identifier: Apache-2.0 +// Original source: https://getreuer.info/posts/keyboards/autocorrection + +#pragma once + +#include "quantum.h" + +bool process_autocorrect(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); -- cgit v1.2.3 From be8907d634ac8967de1ae2ac8346b845f738c9e6 Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 27 Sep 2022 18:37:13 +1000 Subject: Further refactoring of joystick feature (#18437) --- quantum/process_keycode/process_joystick.c | 152 ++++------------------------- quantum/process_keycode/process_joystick.h | 21 +++- 2 files changed, 33 insertions(+), 140 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_joystick.c b/quantum/process_keycode/process_joystick.c index e867606074..af69d3aa05 100644 --- a/quantum/process_keycode/process_joystick.c +++ b/quantum/process_keycode/process_joystick.c @@ -1,10 +1,21 @@ -#include "joystick.h" -#include "process_joystick.h" - -#include "analog.h" +/* Copyright 2022 + * + * 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 . + */ -#include -#include +#include "process_joystick.h" +#include "joystick.h" bool process_joystick(uint16_t keycode, keyrecord_t *record) { switch (keycode) { @@ -18,132 +29,3 @@ bool process_joystick(uint16_t keycode, keyrecord_t *record) { } return true; } - -__attribute__((weak)) void joystick_task(void) { - if (process_joystick_analogread()) { - joystick_flush(); - } -} - -uint16_t savePinState(pin_t pin) { -#ifdef __AVR__ - uint8_t pinNumber = pin & 0xF; - return ((PORTx_ADDRESS(pin) >> pinNumber) & 0x1) << 1 | ((DDRx_ADDRESS(pin) >> pinNumber) & 0x1); -#elif defined(PROTOCOL_CHIBIOS) - /* - The pin configuration is backed up in the following format : - bit 15 9 8 7 6 5 4 3 2 1 0 - |unused|ODR|IDR|PUPDR|OSPEEDR|OTYPER|MODER| - */ - return ((PAL_PORT(pin)->MODER >> (2 * PAL_PAD(pin))) & 0x3) | (((PAL_PORT(pin)->OTYPER >> (1 * PAL_PAD(pin))) & 0x1) << 2) | (((PAL_PORT(pin)->OSPEEDR >> (2 * PAL_PAD(pin))) & 0x3) << 3) | (((PAL_PORT(pin)->PUPDR >> (2 * PAL_PAD(pin))) & 0x3) << 5) | (((PAL_PORT(pin)->IDR >> (1 * PAL_PAD(pin))) & 0x1) << 7) | (((PAL_PORT(pin)->ODR >> (1 * PAL_PAD(pin))) & 0x1) << 8); -#else - return 0; -#endif -} - -void restorePinState(pin_t pin, uint16_t restoreState) { -#if defined(PROTOCOL_LUFA) - uint8_t pinNumber = pin & 0xF; - PORTx_ADDRESS(pin) = (PORTx_ADDRESS(pin) & ~_BV(pinNumber)) | (((restoreState >> 1) & 0x1) << pinNumber); - DDRx_ADDRESS(pin) = (DDRx_ADDRESS(pin) & ~_BV(pinNumber)) | ((restoreState & 0x1) << pinNumber); -#elif defined(PROTOCOL_CHIBIOS) - PAL_PORT(pin)->MODER = (PAL_PORT(pin)->MODER & ~(0x3 << (2 * PAL_PAD(pin)))) | (restoreState & 0x3) << (2 * PAL_PAD(pin)); - PAL_PORT(pin)->OTYPER = (PAL_PORT(pin)->OTYPER & ~(0x1 << (1 * PAL_PAD(pin)))) | ((restoreState >> 2) & 0x1) << (1 * PAL_PAD(pin)); - PAL_PORT(pin)->OSPEEDR = (PAL_PORT(pin)->OSPEEDR & ~(0x3 << (2 * PAL_PAD(pin)))) | ((restoreState >> 3) & 0x3) << (2 * PAL_PAD(pin)); - PAL_PORT(pin)->PUPDR = (PAL_PORT(pin)->PUPDR & ~(0x3 << (2 * PAL_PAD(pin)))) | ((restoreState >> 5) & 0x3) << (2 * PAL_PAD(pin)); - PAL_PORT(pin)->IDR = (PAL_PORT(pin)->IDR & ~(0x1 << (1 * PAL_PAD(pin)))) | ((restoreState >> 7) & 0x1) << (1 * PAL_PAD(pin)); - PAL_PORT(pin)->ODR = (PAL_PORT(pin)->ODR & ~(0x1 << (1 * PAL_PAD(pin)))) | ((restoreState >> 8) & 0x1) << (1 * PAL_PAD(pin)); -#else - return; -#endif -} - -__attribute__((weak)) bool process_joystick_analogread() { - return process_joystick_analogread_quantum(); -} - -bool process_joystick_analogread_quantum() { -#if JOYSTICK_AXES_COUNT > 0 - for (int axis_index = 0; axis_index < JOYSTICK_AXES_COUNT; ++axis_index) { - if (joystick_axes[axis_index].input_pin == JS_VIRTUAL_AXIS) { - continue; - } - - // save previous input pin status as well - uint16_t inputSavedState = savePinState(joystick_axes[axis_index].input_pin); - - // disable pull-up resistor - writePinLow(joystick_axes[axis_index].input_pin); - - // if pin was a pull-up input, we need to uncharge it by turning it low - // before making it a low input - setPinOutput(joystick_axes[axis_index].input_pin); - - wait_us(10); - - // save and apply output pin status - uint16_t outputSavedState = 0; - if (joystick_axes[axis_index].output_pin != JS_VIRTUAL_AXIS) { - // save previous output pin status - outputSavedState = savePinState(joystick_axes[axis_index].output_pin); - - setPinOutput(joystick_axes[axis_index].output_pin); - writePinHigh(joystick_axes[axis_index].output_pin); - } - - uint16_t groundSavedState = 0; - if (joystick_axes[axis_index].ground_pin != JS_VIRTUAL_AXIS) { - // save previous output pin status - groundSavedState = savePinState(joystick_axes[axis_index].ground_pin); - - setPinOutput(joystick_axes[axis_index].ground_pin); - writePinLow(joystick_axes[axis_index].ground_pin); - } - - wait_us(10); - - setPinInput(joystick_axes[axis_index].input_pin); - - wait_us(10); - -# if defined(ANALOG_JOYSTICK_ENABLE) && (defined(__AVR__) || defined(PROTOCOL_CHIBIOS)) - int16_t axis_val = analogReadPin(joystick_axes[axis_index].input_pin); -# else - // default to resting position - int16_t axis_val = joystick_axes[axis_index].mid_digit; -# endif - - // test the converted value against the lower range - int32_t ref = joystick_axes[axis_index].mid_digit; - int32_t range = joystick_axes[axis_index].min_digit; - int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_RESOLUTION) / (range - ref); - - if (ranged_val > 0) { - // the value is in the higher range - range = joystick_axes[axis_index].max_digit; - ranged_val = ((axis_val - ref) * JOYSTICK_RESOLUTION) / (range - ref); - } - - // clamp the result in the valid range - ranged_val = ranged_val < -JOYSTICK_RESOLUTION ? -JOYSTICK_RESOLUTION : ranged_val; - ranged_val = ranged_val > JOYSTICK_RESOLUTION ? JOYSTICK_RESOLUTION : ranged_val; - - if (ranged_val != joystick_status.axes[axis_index]) { - joystick_status.axes[axis_index] = ranged_val; - joystick_status.status |= JS_UPDATED; - } - - // restore output, ground and input status - if (joystick_axes[axis_index].output_pin != JS_VIRTUAL_AXIS) { - restorePinState(joystick_axes[axis_index].output_pin, outputSavedState); - } - if (joystick_axes[axis_index].ground_pin != JS_VIRTUAL_AXIS) { - restorePinState(joystick_axes[axis_index].ground_pin, groundSavedState); - } - - restorePinState(joystick_axes[axis_index].input_pin, inputSavedState); - } - -#endif - return true; -} diff --git a/quantum/process_keycode/process_joystick.h b/quantum/process_keycode/process_joystick.h index 7a8b82913a..1fb8757708 100644 --- a/quantum/process_keycode/process_joystick.h +++ b/quantum/process_keycode/process_joystick.h @@ -1,11 +1,22 @@ +/* Copyright 2022 + * + * 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 . + */ + #pragma once #include #include "quantum.h" bool process_joystick(uint16_t keycode, keyrecord_t *record); - -void joystick_task(void); - -bool process_joystick_analogread(void); -bool process_joystick_analogread_quantum(void); -- cgit v1.2.3 From c0e6a28bc62f659b0564a203df670d81a89a3bb4 Mon Sep 17 00:00:00 2001 From: Jason Ken Adhinarta <35003073+jasonkena@users.noreply.github.com> Date: Mon, 3 Oct 2022 03:26:47 -0400 Subject: Prevent tap dance from wiping dynamic macros (#17880) --- quantum/process_keycode/process_dynamic_macro.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_dynamic_macro.c b/quantum/process_keycode/process_dynamic_macro.c index a7555fdd40..41207092a9 100644 --- a/quantum/process_keycode/process_dynamic_macro.c +++ b/quantum/process_keycode/process_dynamic_macro.c @@ -45,6 +45,10 @@ __attribute__((weak)) void dynamic_macro_record_end_user(int8_t direction) { dynamic_macro_led_blink(); } +__attribute__((weak)) bool dynamic_macro_valid_key_user(uint16_t keycode, keyrecord_t *record) { + return true; +} + /* Convenience macros used for retrieving the debug info. All of them * need a `direction` variable accessible at the call site. */ @@ -252,14 +256,16 @@ bool process_dynamic_macro(uint16_t keycode, keyrecord_t *record) { return false; #endif default: - /* Store the key in the macro buffer and process it normally. */ - switch (macro_id) { - case 1: - dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record); - break; - case 2: - dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record); - break; + if (dynamic_macro_valid_key_user(keycode, record)) { + /* Store the key in the macro buffer and process it normally. */ + switch (macro_id) { + case 1: + dynamic_macro_record_key(macro_buffer, ¯o_pointer, r_macro_end, +1, record); + break; + case 2: + dynamic_macro_record_key(r_macro_buffer, ¯o_pointer, macro_end, -1, record); + break; + } } return true; break; -- cgit v1.2.3 From ca0c12847a97a62f887fd4625673395104a7257b Mon Sep 17 00:00:00 2001 From: Sergey Vlasov Date: Mon, 3 Oct 2022 12:48:16 +0300 Subject: Fix layer switching from tap dances by redoing the keymap lookup (#17935) --- quantum/process_keycode/process_tap_dance.c | 12 +++++++++--- quantum/process_keycode/process_tap_dance.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c index 3270a1b000..6e8e596673 100644 --- a/quantum/process_keycode/process_tap_dance.c +++ b/quantum/process_keycode/process_tap_dance.c @@ -115,12 +115,12 @@ static inline void process_tap_dance_action_on_dance_finished(qk_tap_dance_actio } } -void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) { +bool preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) { qk_tap_dance_action_t *action; - if (!record->event.pressed) return; + if (!record->event.pressed) return false; - if (!active_td || keycode == active_td) return; + if (!active_td || keycode == active_td) return false; action = &tap_dance_actions[TD_INDEX(active_td)]; action->state.interrupted = true; @@ -130,6 +130,12 @@ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) { // Tap dance actions can leave some weak mods active (e.g., if the tap dance is mapped to a keycode with // modifiers), but these weak mods should not affect the keypress which interrupted the tap dance. clear_weak_mods(); + + // Signal that a tap dance has been finished due to being interrupted, + // therefore the keymap lookup for the currently processed event needs to + // be repeated with the current layer state that might have been updated by + // the finished tap dance. + return true; } bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h index d97900d96b..d6d6c136dc 100644 --- a/quantum/process_keycode/process_tap_dance.h +++ b/quantum/process_keycode/process_tap_dance.h @@ -81,7 +81,7 @@ void reset_tap_dance(qk_tap_dance_state_t *state); /* To be used internally */ -void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record); +bool preprocess_tap_dance(uint16_t keycode, keyrecord_t *record); bool process_tap_dance(uint16_t keycode, keyrecord_t *record); void tap_dance_task(void); -- cgit v1.2.3 From 49030e3e5bdd412f44a886be6349ebfd2c05bbf2 Mon Sep 17 00:00:00 2001 From: precondition <57645186+precondition@users.noreply.github.com> Date: Wed, 5 Oct 2022 19:42:05 +0200 Subject: Use get_u16_str instead of snprintf in autoshift_timer_report (#18606) --- quantum/process_keycode/process_auto_shift.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 3ff188ba7e..644ad2cbaf 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -17,7 +17,6 @@ #ifdef AUTO_SHIFT_ENABLE # include -# include # include "process_auto_shift.h" # ifndef AUTO_SHIFT_DISABLED_AT_STARTUP @@ -331,11 +330,12 @@ void autoshift_disable(void) { # ifndef AUTO_SHIFT_NO_SETUP void autoshift_timer_report(void) { # ifdef SEND_STRING_ENABLE - char display[8]; - - snprintf(display, 8, "\n%d\n", autoshift_timeout); - - send_string((const char *)display); + const char *autoshift_timeout_str = get_u16_str(autoshift_timeout, ' '); + // Skip padding spaces + while (*autoshift_timeout_str == ' ') { + autoshift_timeout_str++; + } + send_string(autoshift_timeout_str); # endif } # endif -- cgit v1.2.3 From f0b2bfd5ca5b416a9c7c9bef8c2850f1084bd106 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sat, 15 Oct 2022 14:33:24 +1100 Subject: Programmable Button API refactor and improve docs (#18641) --- quantum/process_keycode/process_programmable_button.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_programmable_button.c b/quantum/process_keycode/process_programmable_button.c index c6e77faacc..6379698848 100644 --- a/quantum/process_keycode/process_programmable_button.c +++ b/quantum/process_keycode/process_programmable_button.c @@ -22,9 +22,9 @@ bool process_programmable_button(uint16_t keycode, keyrecord_t *record) { if (keycode >= PROGRAMMABLE_BUTTON_MIN && keycode <= PROGRAMMABLE_BUTTON_MAX) { uint8_t button = keycode - PROGRAMMABLE_BUTTON_MIN + 1; if (record->event.pressed) { - programmable_button_on(button); + programmable_button_register(button); } else { - programmable_button_off(button); + programmable_button_unregister(button); } } return true; -- cgit v1.2.3 From b33fc349671148bff6f0a60172b53c51e59cda49 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sat, 22 Oct 2022 00:25:54 +1100 Subject: Deprecate `KC_LEAD` for `QK_LEAD` (#18792) --- quantum/process_keycode/process_leader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quantum/process_keycode') diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c index 3593f75f0d..7e6f3ad73c 100644 --- a/quantum/process_keycode/process_leader.c +++ b/quantum/process_keycode/process_leader.c @@ -72,7 +72,7 @@ bool process_leader(uint16_t keycode, keyrecord_t *record) { return false; } } else { - if (keycode == KC_LEAD) { + if (keycode == QK_LEADER) { qk_leader_start(); } } -- cgit v1.2.3 From 7cbff9d921879ef3c54837cb2ffc455e019f45b4 Mon Sep 17 00:00:00 2001 From: