diff options
Diffstat (limited to 'quantum/process_keycode')
| -rw-r--r-- | quantum/process_keycode/process_auto_shift.c | 10 | ||||
| -rw-r--r-- | quantum/process_keycode/process_auto_shift.h | 8 | ||||
| -rw-r--r-- | quantum/process_keycode/process_autocorrect.c | 74 | ||||
| -rw-r--r-- | quantum/process_keycode/process_autocorrect.h | 4 | ||||
| -rw-r--r-- | quantum/process_keycode/process_dynamic_macro.c | 117 | ||||
| -rw-r--r-- | quantum/process_keycode/process_dynamic_macro.h | 1 | ||||
| -rw-r--r-- | quantum/process_keycode/process_key_override.c | 9 | 
7 files changed, 160 insertions, 63 deletions
| diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c index 62c347ae0c..63e893fc18 100644 --- a/quantum/process_keycode/process_auto_shift.c +++ b/quantum/process_keycode/process_auto_shift.c @@ -75,7 +75,15 @@ __attribute__((weak)) bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *r          case AUTO_SHIFT_NUMERIC:  #    endif  #    ifndef NO_AUTO_SHIFT_SPECIAL -        case AUTO_SHIFT_SPECIAL: +#        ifndef NO_AUTO_SHIFT_TAB +        case KC_TAB: +#        endif +#        ifndef NO_AUTO_SHIFT_SYMBOLS +        case AUTO_SHIFT_SYMBOLS: +#        endif +#    endif +#    ifdef AUTO_SHIFT_ENTER +        case KC_ENT:  #    endif              return true;      } diff --git a/quantum/process_keycode/process_auto_shift.h b/quantum/process_keycode/process_auto_shift.h index 66a4b3138a..780177d2ff 100644 --- a/quantum/process_keycode/process_auto_shift.h +++ b/quantum/process_keycode/process_auto_shift.h @@ -28,10 +28,14 @@  // clang-format off  #define AUTO_SHIFT_ALPHA KC_A ... KC_Z  #define AUTO_SHIFT_NUMERIC KC_1 ... KC_0 +#define AUTO_SHIFT_SYMBOLS          \ +             KC_MINUS ... KC_SLASH: \ +        case KC_NONUS_BACKSLASH + +// Kept to avoid breaking existing keymaps.  #define AUTO_SHIFT_SPECIAL          \               KC_TAB:                \ -        case KC_MINUS ... KC_SLASH: \ -        case KC_NONUS_BACKSLASH +        case AUTO_SHIFT_SYMBOLS  // clang-format on  bool process_auto_shift(uint16_t keycode, keyrecord_t *record); diff --git a/quantum/process_keycode/process_autocorrect.c b/quantum/process_keycode/process_autocorrect.c index 1376788266..cc1f19e4f9 100644 --- a/quantum/process_keycode/process_autocorrect.c +++ b/quantum/process_keycode/process_autocorrect.c @@ -1,5 +1,6 @@  // Copyright 2021 Google LLC  // Copyright 2021 @filterpaper +// Copyright 2023 Pablo Martinez (@elpekenin) <[email protected]>  // SPDX-License-Identifier: Apache-2.0  // Original source: https://getreuer.info/posts/keyboards/autocorrection @@ -57,7 +58,7 @@ void autocorrect_toggle(void) {  }  /** - * @brief handler for determining if autocorrect should process keypress + * @brief handler for user to override whether autocorrect should process this keypress   *   * @param keycode Keycode registered by matrix press, per keymap   * @param record keyrecord_t structure @@ -67,6 +68,23 @@ void autocorrect_toggle(void) {   * @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) { +    return process_autocorrect_default_handler(keycode, record, typo_buffer_size, mods); +} + +/** + * @brief fallback handler for determining if autocorrect should process this keypress + *        can be used by user callback to get the basic keycode being "wrapped" + * + * NOTE: These values may have been edited by user callback before getting here + * + * @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. + */ +bool process_autocorrect_default_handler(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. @@ -157,10 +175,12 @@ __attribute__((weak)) bool process_autocorrect_user(uint16_t *keycode, keyrecord   *   * @param backspaces number of characters to remove   * @param str pointer to PROGMEM string to replace mistyped seletion with + * @param typo the wrong string that triggered a correction + * @param correct what it would become after the changes   * @return true apply correction   * @return false user handled replacement   */ -__attribute__((weak)) bool apply_autocorrect(uint8_t backspaces, const char *str) { +__attribute__((weak)) bool apply_autocorrect(uint8_t backspaces, const char *str, char *typo, char *correct) {      return true;  } @@ -284,11 +304,57 @@ bool process_autocorrect(uint16_t keycode, keyrecord_t *record) {          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))) { +            const char *  changes    = (const char *)(autocorrect_data + state + 1); + +            /* Gather info about the typo'd word +             * +             * Since buffer may contain several words, delimited by spaces, we +             * iterate from the end to find the start and length of the typo +             */ +            char typo[AUTOCORRECT_MAX_LENGTH + 1] = {0}; // extra char for null terminator + +            uint8_t typo_len   = 0; +            uint8_t typo_start = 0; +            bool    space_last = typo_buffer[typo_buffer_size - 1] == KC_SPC; +            for (uint8_t i = typo_buffer_size; i > 0; --i) { +                // stop counting after finding space (unless it is the last thing) +                if (typo_buffer[i - 1] == KC_SPC && i != typo_buffer_size) { +                    typo_start = i; +                    break; +                } + +                ++typo_len; +            } + +            // when detecting 'typo:', reduce the length of the string by one +            if (space_last) { +                --typo_len; +            } + +            // convert buffer of keycodes into a string +            for (uint8_t i = 0; i < typo_len; ++i) { +                typo[i] = typo_buffer[typo_start + i] - KC_A + 'a'; +            } + +            /* Gather the corrected word +             * +             * A) Correction of 'typo:' -- Code takes into account +             * an extra backspace to delete the space (which we dont copy) +             * for this reason the offset is correct to "skip" the null terminator +             * +             * B) When correcting 'typo' -- Need extra offset for terminator +             */ +            char correct[AUTOCORRECT_MAX_LENGTH + 10] = {0}; // let's hope this is big enough + +            uint8_t offset = space_last ? backspaces : backspaces + 1; +            strcpy(correct, typo); +            strcpy_P(correct + typo_len - offset, changes); + +            if (apply_autocorrect(backspaces, changes, typo, correct)) {                  for (uint8_t i = 0; i < backspaces; ++i) {                      tap_code(KC_BSPC);                  } -                send_string_P((char const *)(autocorrect_data + state + 1)); +                send_string_P(changes);              }              if (keycode == KC_SPC) { diff --git a/quantum/process_keycode/process_autocorrect.h b/quantum/process_keycode/process_autocorrect.h index c7596107e5..9cc7d46a8b 100644 --- a/quantum/process_keycode/process_autocorrect.h +++ b/quantum/process_keycode/process_autocorrect.h @@ -1,5 +1,6 @@  // Copyright 2021 Google LLC  // Copyright 2021 @filterpaper +// Copyright 2023 Pablo Martinez (@elpekenin) <[email protected]>  // SPDX-License-Identifier: Apache-2.0  // Original source: https://getreuer.info/posts/keyboards/autocorrection @@ -9,7 +10,8 @@  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 process_autocorrect_default_handler(uint16_t *keycode, keyrecord_t *record, uint8_t *typo_buffer_size, uint8_t *mods); +bool apply_autocorrect(uint8_t backspaces, const char *str, char *typo, char *correct);  bool autocorrect_is_enabled(void);  void autocorrect_enable(void); diff --git a/quantum/process_keycode/process_dynamic_macro.c b/quantum/process_keycode/process_dynamic_macro.c index bf6af566e2..a022949d3d 100644 --- a/quantum/process_keycode/process_dynamic_macro.c +++ b/quantum/process_keycode/process_dynamic_macro.c @@ -151,6 +151,67 @@ void dynamic_macro_record_end(keyrecord_t *macro_buffer, keyrecord_t *macro_poin      *macro_end = macro_pointer;  } +/* Both macros use the same buffer but read/write on different + * ends of it. + * + * Macro1 is written left-to-right starting from the beginning of + * the buffer. + * + * Macro2 is written right-to-left starting from the end of the + * buffer. + * + * ¯o_buffer   macro_end + *  v                   v + * +------------------------------------------------------------+ + * |>>>>>> MACRO1 >>>>>>      <<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| + * +------------------------------------------------------------+ + *                           ^                                 ^ + *                         r_macro_end                  r_macro_buffer + * + * During the recording when one macro encounters the end of the + * other macro, the recording is stopped. Apart from this, there + * are no arbitrary limits for the macros' length in relation to + * each other: for example one can either have two medium sized + * macros or one long macro and one short macro. Or even one empty + * and one using the whole buffer. + */ +static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE]; + +/* Pointer to the first buffer element after the first macro. + * Initially points to the very beginning of the buffer since the + * macro is empty. */ +static keyrecord_t *macro_end = macro_buffer; + +/* The other end of the macro buffer. Serves as the beginning of + * the second macro. */ +static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1; + +/* Like macro_end but for the second macro. */ +static keyrecord_t *r_macro_end = r_macro_buffer; + +/* A persistent pointer to the current macro position (iterator) + * used during the recording. */ +static keyrecord_t *macro_pointer = NULL; + +/* 0   - no macro is being recorded right now + * 1,2 - either macro 1 or 2 is being recorded */ +static uint8_t macro_id = 0; + +/** + * If a dynamic macro is currently being recorded, stop recording. + */ +void dynamic_macro_stop_recording(void) { +    switch (macro_id) { +        case 1: +            dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end); +            break; +        case 2: +            dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end); +            break; +    } +    macro_id = 0; +} +  /* Handle the key events related to the dynamic macros. Should be   * called from process_record_user() like this:   * @@ -162,52 +223,6 @@ void dynamic_macro_record_end(keyrecord_t *macro_buffer, keyrecord_t *macro_poin   *   }   */  bool process_dynamic_macro(uint16_t keycode, keyrecord_t *record) { -    /* Both macros use the same buffer but read/write on different -     * ends of it. -     * -     * Macro1 is written left-to-right starting from the beginning of -     * the buffer. -     * -     * Macro2 is written right-to-left starting from the end of the -     * buffer. -     * -     * ¯o_buffer   macro_end -     *  v                   v -     * +------------------------------------------------------------+ -     * |>>>>>> MACRO1 >>>>>>      <<<<<<<<<<<<< MACRO2 <<<<<<<<<<<<<| -     * +------------------------------------------------------------+ -     *                           ^                                 ^ -     *                         r_macro_end                  r_macro_buffer -     * -     * During the recording when one macro encounters the end of the -     * other macro, the recording is stopped. Apart from this, there -     * are no arbitrary limits for the macros' length in relation to -     * each other: for example one can either have two medium sized -     * macros or one long macro and one short macro. Or even one empty -     * and one using the whole buffer. -     */ -    static keyrecord_t macro_buffer[DYNAMIC_MACRO_SIZE]; - -    /* Pointer to the first buffer element after the first macro. -     * Initially points to the very beginning of the buffer since the -     * macro is empty. */ -    static keyrecord_t *macro_end = macro_buffer; - -    /* The other end of the macro buffer. Serves as the beginning of -     * the second macro. */ -    static keyrecord_t *const r_macro_buffer = macro_buffer + DYNAMIC_MACRO_SIZE - 1; - -    /* Like macro_end but for the second macro. */ -    static keyrecord_t *r_macro_end = r_macro_buffer; - -    /* A persistent pointer to the current macro position (iterator) -     * used during the recording. */ -    static keyrecord_t *macro_pointer = NULL; - -    /* 0   - no macro is being recorded right now -     * 1,2 - either macro 1 or 2 is being recorded */ -    static uint8_t macro_id = 0; -      if (macro_id == 0) {          /* No macro recording in progress. */          if (!record->event.pressed) { @@ -238,15 +253,7 @@ bool process_dynamic_macro(uint16_t keycode, keyrecord_t *record) {                  if (record->event.pressed ^ (keycode != QK_DYNAMIC_MACRO_RECORD_STOP)) { /* Ignore the initial release                                                                                            * just after the recording                                                                                            * starts for DM_RSTP. */ -                    switch (macro_id) { -                        case 1: -                            dynamic_macro_record_end(macro_buffer, macro_pointer, +1, ¯o_end); -                            break; -                        case 2: -                            dynamic_macro_record_end(r_macro_buffer, macro_pointer, -1, &r_macro_end); -                            break; -                    } -                    macro_id = 0; +                    dynamic_macro_stop_recording();                  }                  return false;  #ifdef DYNAMIC_MACRO_NO_NESTING diff --git a/quantum/process_keycode/process_dynamic_macro.h b/quantum/process_keycode/process_dynamic_macro.h index ab70726897..9841254af4 100644 --- a/quantum/process_keycode/process_dynamic_macro.h +++ b/quantum/process_keycode/process_dynamic_macro.h @@ -39,3 +39,4 @@ void dynamic_macro_record_start_user(int8_t direction);  void dynamic_macro_play_user(int8_t direction);  void dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record);  void dynamic_macro_record_end_user(int8_t direction); +void dynamic_macro_stop_recording(void); diff --git a/quantum/process_keycode/process_key_override.c b/quantum/process_keycode/process_key_override.c index 17e490e67a..de628d3fec 100644 --- a/quantum/process_keycode/process_key_override.c +++ b/quantum/process_keycode/process_key_override.c @@ -322,6 +322,15 @@ static bool try_activating_override(const uint16_t keycode, const uint8_t layer,          clear_active_override(false); +#ifdef DUMMY_MOD_NEUTRALIZER_KEYCODE +        // Send a dummy keycode before unregistering the modifier(s) +        // so that suppressing the modifier(s) doesn't falsely get interpreted +        // by the host OS as a tap of a modifier key. +        // For example, unintended activations of the start menu on Windows when +        // using a GUI+<kc> key override with suppressed mods. +        neutralize_flashing_modifiers(active_mods); +#endif +          active_override                 = override;          active_override_trigger_is_down = true; | 
