Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Enhancement] More info on apply_autocorrect #21056

Merged
merged 5 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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