Skip to content

Commit

Permalink
[Enhancement] More info on apply_autocorrect (#21056)
Browse files Browse the repository at this point in the history
Co-authored-by: Drashna Jaelre <drashna@live.com>
  • Loading branch information
elpekenin and drashna authored Jul 7, 2023
1 parent 2126343 commit 55295ed
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 9 deletions.
13 changes: 9 additions & 4 deletions docs/feature_autocorrect.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,9 @@ bool process_autocorrect_user(uint16_t *keycode, keyrecord_t *record, uint8_t *t

### Apply Autocorrect

Additionally, `apply_autocorrect(uint8_t backspaces, const char *str)` allows for users to add additional handling to the autocorrection, or replace the functionality entirely. This passes on the number of backspaces needed to replace the words, as well as the replacement string (partial word, not the full word).
Additionally, `apply_autocorrect(uint8_t backspaces, const char *str, char *typo, char *correct)` allows for users to add additional handling to the autocorrection, or replace the functionality entirely. This passes on the number of backspaces needed to replace the words, as well as the replacement string (partial word, not the full word), and the typo and corrected strings (complete words).

?> Due to the way code works (no notion of words, just a stream of letters), the `typo` and `correct` strings are a best bet and could be "wrong". For example you may get `wordtpyo` & `wordtypo` instead of the expected `tpyo` & `typo`.

#### Apply Autocorrect Example

Expand All @@ -209,7 +211,7 @@ This following example will play a sound when a typo is autocorrected and execut
float autocorrect_song[][2] = SONG(TERMINAL_SOUND);
#endif

bool apply_autocorrect(uint8_t backspaces, const char *str) {
bool apply_autocorrect(uint8_t backspaces, const char *str, char *typo, char *correct) {
#ifdef AUDIO_ENABLE
PLAY_SONG(autocorrect_song);
#endif
Expand All @@ -223,14 +225,17 @@ bool apply_autocorrect(uint8_t backspaces, const char *str) {
?> In this callback function, `return false` will stop the normal processing of autocorrect, which requires manually handling of removing the "bad" characters and typing the new characters.
!> ***IMPORTANT***: `str` is a pointer to `PROGMEM` data for the autocorrection. If you return false, and want to send the string, this needs to use `send_string_P` and not `send_string` or `SEND_STRING`.
!> ***IMPORTANT***: `str` is a pointer to `PROGMEM` data for the autocorrection. If you return false, and want to send the string, this needs to use `send_string_P` and not `send_string` nor `SEND_STRING`.
You can also use `apply_autocorrect` to detect and display the event but allow internal code to execute the autocorrection with `return true`:
```c
bool apply_autocorrect(uint8_t backspaces, const char *str) {
bool apply_autocorrect(uint8_t backspaces, const char *str, char *typo, char *correct) {
#ifdef OLED_ENABLE
oled_write_P(PSTR("Auto-corrected"), false);
#endif
#ifdef CONSOLE_ENABLE
printf("'%s' was corrected to '%s'\n", typo, correct);
#endif
return true;
}
Expand Down
55 changes: 52 additions & 3 deletions quantum/process_keycode/process_autocorrect.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2021 Google LLC
// Copyright 2021 @filterpaper
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev>
// SPDX-License-Identifier: Apache-2.0
// Original source: https://getreuer.info/posts/keyboards/autocorrection

Expand Down Expand Up @@ -174,10 +175,12 @@ bool process_autocorrect_default_handler(uint16_t *keycode, keyrecord_t *record,
*
* @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;
}

Expand Down Expand Up @@ -301,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) {
Expand Down
3 changes: 2 additions & 1 deletion quantum/process_keycode/process_autocorrect.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2021 Google LLC
// Copyright 2021 @filterpaper
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev>
// SPDX-License-Identifier: Apache-2.0
// Original source: https://getreuer.info/posts/keyboards/autocorrection

Expand All @@ -10,7 +11,7 @@
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 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);
bool apply_autocorrect(uint8_t backspaces, const char *str, char *typo, char *correct);

bool autocorrect_is_enabled(void);
void autocorrect_enable(void);
Expand Down
2 changes: 1 addition & 1 deletion users/drashna/drashna.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ float autocorrect_song[][2] = SONG(PLOVER_GOODBYE_SOUND);
# endif
# endif

bool apply_autocorrect(uint8_t backspaces, const char *str) {
bool apply_autocorrect(uint8_t backspaces, const char* str, char *typo, char *correct) {
if (layer_state_is(_GAMEPAD)) {
return false;
}
Expand Down

0 comments on commit 55295ed

Please sign in to comment.