summary refs log tree commit diff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/process_keycode')
-rw-r--r--quantum/process_keycode/autocorrect_data_default.h85
-rw-r--r--quantum/process_keycode/process_autocorrect.c287
-rw-r--r--quantum/process_keycode/process_autocorrect.h17
3 files changed, 389 insertions, 0 deletions
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 <string.h>
+#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);