#ifdef BETA_ENABLE_SPELLCHECK #include "features/spellcheck.h" #include "features/beta_rawhid.h" uint8_t spellcheck_buffer[SPELLCHECK_BUFFER_MAX] = {0}; uint8_t spellcheck_buffer_size = 0; bool process_spellcheck(uint16_t keycode, keyrecord_t* record) { // Ignore key release; we only process key presses. if (!record->event.pressed) { return true; } #ifndef NO_ACTION_ONESHOT const uint8_t mods = get_mods() | get_oneshot_mods(); #else const uint8_t mods = get_mods(); #endif // Disable autocorrection while a mod other than shift is active. if ((mods & ~MOD_MASK_SHIFT) != 0) { spellcheck_buffer_size = 0; return true; } // The following switch cases address various kinds of keycodes. This logic is // split over two switches rather than merged into one. The first switch may // extract a basic keycode which is then further handled by the second switch, // e.g. a layer-tap key with Caps Lock `LT(layer, KC_CAPS)`. switch (keycode) { #ifndef NO_ACTION_TAPPING case QK_MOD_TAP ... QK_MOD_TAP_MAX: // Tap-hold keys. #ifndef NO_ACTION_LAYER case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: #endif // Ignore when tap-hold keys are held. if (record->tap.count == 0) { return true; } // Otherwise when tapped, get the basic keycode. // Fallthrough intended. #endif // Handle shifted keys, e.g. symbols like KC_EXLM = S(KC_1). case QK_LSFT ... QK_LSFT + 255: case QK_RSFT ... QK_RSFT + 255: keycode &= 0xff; // Get the basic keycode. break; // NOTE: Space Cadet keys expose no info to check whether they are being // tapped vs. held. This makes autocorrection ambiguous, e.g. KC_LCPO might // be '(', which we would treat as a word break, or it might be shift, which // we would treat as having no effect. To behave cautiously, we allow Space // Cadet keycodes to fall to the logic below and clear autocorrection state. } switch (keycode) { // Ignore shifts, Caps Lock, one-shot mods, and layer switch keys. case KC_NO: case KC_LSFT: case KC_RSFT: case KC_CAPS: case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX: case QK_TO ... QK_TO_MAX: case QK_MOMENTARY ... QK_MOMENTARY_MAX: case QK_DEF_LAYER ... QK_DEF_LAYER_MAX: case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX: case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX: case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: return true; // Ignore these keys. } if (keycode == KC_QUOT) { // Treat " (shifted ') as a word boundary. if ((mods & MOD_MASK_SHIFT) != 0) { keycode = KC_SPC; } } else if (!(KC_A <= keycode && keycode <= KC_Z)) { if (keycode == KC_BSPC) { // Remove last character from the buffer. if (spellcheck_buffer_size > 0) { --spellcheck_buffer_size; } return true; } else if (KC_1 <= keycode && keycode <= KC_SLSH && keycode != KC_ESC) { // Set a word boundary if space, period, digit, etc. is pressed. // Behave more conservatively for the enter key. Reset, so that enter // can't be used on a word ending. if (keycode == KC_ENT) { spellcheck_buffer_size = 0; } keycode = KC_SPC; } else { // Clear state if some other non-alpha key is pressed. spellcheck_buffer_size = 0; return true; } } // If the buffer is full, rotate it to discard the oldest character. if (spellcheck_buffer_size >= SPELLCHECK_BUFFER_MAX) { memmove(spellcheck_buffer, spellcheck_buffer + 1, SPELLCHECK_BUFFER_MAX - 1); spellcheck_buffer_size = SPELLCHECK_BUFFER_MAX - 1; } // NOTE: `keycode` must be a basic keycode (0-255) by this point. // A to Z keycodes if (keycode >= 0x04 && keycode <= 0x1D) { spellcheck_buffer[spellcheck_buffer_size++] = (uint8_t) keycode; } else if (spellcheck_buffer_size > 0) { hid_send_word(); spellcheck_buffer_size = 0; } return true; } #endif