diff --git a/keyboards/crkbd/keymaps/sajenim/combos.def b/keyboards/crkbd/keymaps/sajenim/combos.def index c324987..27e3d8d 100644 --- a/keyboards/crkbd/keymaps/sajenim/combos.def +++ b/keyboards/crkbd/keymaps/sajenim/combos.def @@ -1,18 +1,11 @@ // clang-format off -// name result chord keys +// name result 1st chord key 2nd chord key COMB(NE_ESC, KC_ESC, RCTL_T(KC_N), RSFT_T(KC_E)) COMB(SE_CAP, CW_TOGG, LSFT_T(KC_S), RSFT_T(KC_E)) COMB(THUMB_SLEEP, KC_SLEP, LT(NAV, KC_SPC), LSFT_T(KC_ENT)) -COMB(FN_MAGIC, QK_AREP, KC_F, RCTL_T(KC_N)) - -// substitutions -SUBS(YP_HOME, "~/", KC_Y, KC_P) -SUBS(FO_UPDIR, "../", KC_F, KC_O) - -// toggle layers -TOGG(ST_MOD, MOD, LSFT_T(KC_S), LCTL_T(KC_T)) -TOGG(TP_NUM, NUM, LCTL_T(KC_T), KC_P) +SUBS(YP_HOME, "~/", KC_Y, KC_P) +SUBS(FO_UPDIR, "../", KC_F, KC_O) /* vim: set filetype=c: */ diff --git a/keyboards/crkbd/keymaps/sajenim/config.h b/keyboards/crkbd/keymaps/sajenim/config.h index 5ce78f7..eb86762 100644 --- a/keyboards/crkbd/keymaps/sajenim/config.h +++ b/keyboards/crkbd/keymaps/sajenim/config.h @@ -1,51 +1,24 @@ #pragma once -// By default, the firmware does not know which side is which; it needs some -// help to determine that. +// By default, the firmware does not know which side is which. #define MASTER_LEFT -// Alternate way in QMK to enter the embedded mass storage UF2 boot-loader of -// the RP2040. +// Alternate way in QMK to enter the embedded mass storage UF2 boot-loader. #define RP2040_BOOTLOADER_DOUBLE_TAP_RESET #define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U -#define OLED_FONT_H "keyboards/crkbd/lib/glcdfont.c" - -// Enable QK_MAKE keycode -#define ENABLE_COMPILE_KEYCODE - // Tap-Hold configuration for home row mods. -#define TAPPING_TERM \ - 175 // time window in which you need to release the key in order to register a - // tap -#define PERMISSIVE_HOLD // activates the modifier when another key is pressed - // and released while the mod-tap is held, regardless of - // the tapping term -#define QUICK_TAP_TERM 0 // disable the auto-repeat feature entirely -#define ACHORDION_STREAK // disables hold behaviors when in a typing streak +#define TAPPING_TERM 175 +#define PERMISSIVE_HOLD +#define QUICK_TAP_TERM 0 +#define ACHORDION_STREAK // Timeouts -#define ONESHOT_TIMEOUT 3000 +#define ONESHOT_TIMEOUT 3000 #define CAPS_WORD_IDlE_TIMEOUT 3000 -// combos' keys are always checked from layer 0 +// Combo keys are always checked from layer 0. #define COMBO_ONLY_FROM_LAYER 0 -// RGB -#ifdef RGBLIGHT_ENABLE -#define RGBLIGHT_SLEEP -#define RGBLIGHT_EFFECT_BREATHING -#define RGBLIGHT_EFFECT_RAINBOW_MOOD -#define RGBLIGHT_EFFECT_RAINBOW_SWIRL -#define RGBLIGHT_EFFECT_SNAKE -#define RGBLIGHT_EFFECT_KNIGHT -#define RGBLIGHT_EFFECT_CHRISTMAS -#define RGBLIGHT_EFFECT_STATIC_GRADIENT -#define RGBLIGHT_EFFECT_RGB_TEST -#define RGBLIGHT_EFFECT_ALTERNATING -#define RGBLIGHT_EFFECT_TWINKLE -#define RGBLIGHT_LIMIT_VAL 120 -#define RGBLIGHT_HUE_STEP 10 -#define RGBLIGHT_SAT_STEP 17 -#define RGBLIGHT_VAL_STEP 17 -#endif +// Oled font to use. +#define OLED_FONT_H "keyboards/crkbd/lib/glcdfont.c" diff --git a/keyboards/crkbd/keymaps/sajenim/features/layer_lock.c b/keyboards/crkbd/keymaps/sajenim/features/layer_lock.c deleted file mode 100644 index 2c23e84..0000000 --- a/keyboards/crkbd/keymaps/sajenim/features/layer_lock.c +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2022-2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @file layer_lock.c - * @brief Layer Lock implementation - * - * For full documentation, see - * - */ - -#include "layer_lock.h" - -// The current lock state. The kth bit is on if layer k is locked. -static layer_state_t locked_layers = 0; - -// Layer Lock timer to disable layer lock after X seconds inactivity -#if LAYER_LOCK_IDLE_TIMEOUT > 0 -static uint32_t layer_lock_timer = 0; - -void layer_lock_task(void) { - if (locked_layers && - timer_elapsed32(layer_lock_timer) > LAYER_LOCK_IDLE_TIMEOUT) { - layer_lock_all_off(); - layer_lock_timer = timer_read32(); - } -} -#endif // LAYER_LOCK_IDLE_TIMEOUT > 0 - -// Handles an event on an `MO` or `TT` layer switch key. -static bool handle_mo_or_tt(uint8_t layer, keyrecord_t* record) { - if (is_layer_locked(layer)) { - if (record->event.pressed) { // On press, unlock the layer. - layer_lock_invert(layer); - } - return false; // Skip default handling. - } - return true; -} - -bool process_layer_lock(uint16_t keycode, keyrecord_t* record, - uint16_t lock_keycode) { -#if LAYER_LOCK_IDLE_TIMEOUT > 0 - layer_lock_timer = timer_read32(); -#endif // LAYER_LOCK_IDLE_TIMEOUT > 0 - - // The intention is that locked layers remain on. If something outside of - // this feature turned any locked layers off, unlock them. - if ((locked_layers & ~layer_state) != 0) { - layer_lock_set_user(locked_layers &= layer_state); - } - - if (keycode == lock_keycode) { - if (record->event.pressed) { // The layer lock key was pressed. - layer_lock_invert(get_highest_layer(layer_state)); - } - return false; - } - - switch (keycode) { - case QK_MOMENTARY ... QK_MOMENTARY_MAX: // `MO(layer)` keys. - return handle_mo_or_tt(QK_MOMENTARY_GET_LAYER(keycode), record); - - case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX: // `TT(layer)`. - return handle_mo_or_tt(QK_LAYER_TAP_TOGGLE_GET_LAYER(keycode), record); - - case QK_LAYER_MOD ... QK_LAYER_MOD_MAX: { // `LM(layer, mod)`. - uint8_t layer = QK_LAYER_MOD_GET_LAYER(keycode); - if (is_layer_locked(layer)) { - if (record->event.pressed) { // On press, unlock the layer. - layer_lock_invert(layer); - } else { // On release, clear the mods. - clear_mods(); - send_keyboard_report(); - } - return false; // Skip default handling. - } - } break; - -#ifndef NO_ACTION_TAPPING - case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: // `LT(layer, key)` keys. - if (record->tap.count == 0 && !record->event.pressed && - is_layer_locked(QK_LAYER_TAP_GET_LAYER(keycode))) { - // Release event on a held layer-tap key where the layer is locked. - return false; // Skip default handling so that layer stays on. - } - break; -#endif // NO_ACTION_TAPPING - } - - return true; -} - -bool is_layer_locked(uint8_t layer) { - return locked_layers & ((layer_state_t)1 << layer); -} - -void layer_lock_invert(uint8_t layer) { - const layer_state_t mask = (layer_state_t)1 << layer; - if ((locked_layers & mask) == 0) { // Layer is being locked. -#ifndef NO_ACTION_ONESHOT - if (layer == get_oneshot_layer()) { - reset_oneshot_layer(); // Reset so that OSL doesn't turn layer off. - } -#endif // NO_ACTION_ONESHOT - layer_on(layer); -#if LAYER_LOCK_IDLE_TIMEOUT > 0 - layer_lock_timer = timer_read32(); -#endif // LAYER_LOCK_IDLE_TIMEOUT > 0 - } else { // Layer is being unlocked. - layer_off(layer); - } - layer_lock_set_user(locked_layers ^= mask); -} - -// Implement layer_lock_on/off by deferring to layer_lock_invert. -void layer_lock_on(uint8_t layer) { - if (!is_layer_locked(layer)) { - layer_lock_invert(layer); - } -} - -void layer_lock_off(uint8_t layer) { - if (is_layer_locked(layer)) { - layer_lock_invert(layer); - } -} - -void layer_lock_all_off(void) { - layer_and(~locked_layers); - locked_layers = 0; - layer_lock_set_user(locked_layers); -} - -__attribute__((weak)) void layer_lock_set_user(layer_state_t locked_layers) {} - diff --git a/keyboards/crkbd/keymaps/sajenim/features/layer_lock.h b/keyboards/crkbd/keymaps/sajenim/features/layer_lock.h deleted file mode 100644 index eafc184..0000000 --- a/keyboards/crkbd/keymaps/sajenim/features/layer_lock.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2022-2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @file layer_lock.h - * @brief Layer Lock, a key to stay in the current layer. - * - * Overview - * -------- - * - * Layers are often accessed by holding a button, e.g. with a momentary layer - * switch `MO(layer)` or layer tap `LT(layer, key)` key. But you may sometimes - * want to "lock" or "toggle" the layer so that it stays on without having to - * hold down a button. One way to do that is with a tap-toggle `TT` layer key, - * but here is an alternative. - * - * This library implements a "Layer Lock key". When tapped, it "locks" the - * highest layer to stay active, assuming the layer was activated by one of the - * following keys: - * - * * `MO(layer)` momentary layer switch - * * `LT(layer, key)` layer tap - * * `OSL(layer)` one-shot layer - * * `TT(layer)` layer tap toggle - * * `LM(layer, mod)` layer-mod key (the layer is locked, but not the mods) - * - * Tapping the Layer Lock key again unlocks and turns off the layer. - * - * @note When a layer is "locked", other layer keys such as `TO(layer)` or - * manually calling `layer_off(layer)` will override and unlock the layer. - * - * Configuration - * ------------- - * - * Optionally, a timeout may be defined so that Layer Lock disables - * automatically if not keys are pressed for `LAYER_LOCK_IDLE_TIMEOUT` - * milliseconds. Define `LAYER_LOCK_IDLE_TIMEOUT` in your config.h, for instance - * - * #define LAYER_LOCK_IDLE_TIMEOUT 60000 // Turn off after 60 seconds. - * - * and call `layer_lock_task()` from your `matrix_scan_user()` in keymap.c: - * - * void matrix_scan_user(void) { - * layer_lock_task(); - * // Other tasks... - * } - * - * For full documentation, see - * - */ - -#pragma once - -#include "quantum.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Handler function for Layer Lock. - * - * In your keymap, define a custom keycode to use for Layer Lock. Then handle - * Layer Lock from your `process_record_user` function by calling - * `process_layer_lock`, passing your custom keycode for the `lock_keycode` arg: - * - * #include "features/layer_lock.h" - * - * bool process_record_user(uint16_t keycode, keyrecord_t* record) { - * if (!process_layer_lock(keycode, record, LLOCK)) { return false; } - * // Your macros ... - * - * return true; - * } - */ -bool process_layer_lock(uint16_t keycode, keyrecord_t* record, - uint16_t lock_keycode); - -/** Returns true if `layer` is currently locked. */ -bool is_layer_locked(uint8_t layer); - -/** Locks and turns on `layer`. */ -void layer_lock_on(uint8_t layer); - -/** Unlocks and turns off `layer`. */ -void layer_lock_off(uint8_t layer); - -/** Unlocks and turns off all locked layers. */ -void layer_lock_all_off(void); - -/** Toggles whether `layer` is locked. */ -void layer_lock_invert(uint8_t layer); - -/** - * Optional callback that gets called when a layer is locked or unlocked. - * - * This is useful to represent the current lock state, e.g. by setting an LED or - * playing a sound. In your keymap, define - * - * void layer_lock_set_user(layer_state_t locked_layers) { - * // Do something like `set_led(is_layer_locked(NAV));` - * } - * - * @param locked_layers Bitfield in which the kth bit represents whether the - * kth layer is on. - */ -void layer_lock_set_user(layer_state_t locked_layers); - -/** - * @fn layer_lock_task(void) - * Matrix task function for Layer Lock. - * - * If using `LAYER_LOCK_IDLE_TIMEOUT`, call this function from your - * `matrix_scan_user()` function in keymap.c. (If no timeout is set, calling - * `layer_lock_task()` has no effect.) - */ -#if LAYER_LOCK_IDLE_TIMEOUT > 0 -void layer_lock_task(void); -#else -static inline void layer_lock_task(void) {} -#endif // LAYER_LOCK_IDLE_TIMEOUT > 0 - -#ifdef __cplusplus -} -#endif - diff --git a/keyboards/crkbd/keymaps/sajenim/features/select_word.c b/keyboards/crkbd/keymaps/sajenim/features/select_word.c deleted file mode 100644 index a1bf939..0000000 --- a/keyboards/crkbd/keymaps/sajenim/features/select_word.c +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2021-2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @file select_word.c - * @brief Select word implementation - * - * For full documentation, see - * - */ - -#include "select_word.h" - -// Mac users, uncomment this line: -// #define MAC_HOTKEYS - -// clang-format off -enum { - STATE_NONE, // No selection. - STATE_SELECTED, // Macro released with something selected. - STATE_WORD, // Macro held with word(s) selected. - STATE_FIRST_LINE, // Macro held with one line selected. - STATE_LINE // Macro held with multiple lines selected. -}; -// clang-format on -static uint8_t state = STATE_NONE; - -// Idle timeout timer to disable Select Word after a period of inactivity. -#if SELECT_WORD_TIMEOUT > 0 -static uint16_t idle_timer = 0; - -void select_word_task(void) { - if (state && timer_expired(timer_read(), idle_timer)) { - state = STATE_NONE; - } -} -#endif // SELECT_WORD_TIMEOUT > 0 - -bool process_select_word(uint16_t keycode, keyrecord_t* record, - uint16_t sel_keycode) { - if (keycode == KC_LSFT || keycode == KC_RSFT) { - return true; - } - -#if SELECT_WORD_TIMEOUT > 0 - idle_timer = record->event.time + SELECT_WORD_TIMEOUT; -#endif // SELECT_WORD_TIMEOUT > 0 - - if (keycode == sel_keycode && record->event.pressed) { // On key press. - const uint8_t mods = get_mods(); -#ifndef NO_ACTION_ONESHOT - const bool shifted = (mods | get_oneshot_mods()) & MOD_MASK_SHIFT; - clear_oneshot_mods(); -#else - const bool shifted = mods & MOD_MASK_SHIFT; -#endif // NO_ACTION_ONESHOT - - if (!shifted) { // Select word. -#ifdef MAC_HOTKEYS - set_mods(MOD_BIT(KC_LALT)); // Hold Left Alt (Option). -#else - set_mods(MOD_BIT(KC_LCTL)); // Hold Left Ctrl. -#endif // MAC_HOTKEYS - if (state == STATE_NONE) { - // On first use, tap Ctrl+Right then Ctrl+Left (or with Alt on Mac) to - // ensure the cursor is positioned at the beginning of the word. - send_keyboard_report(); - tap_code(KC_RGHT); - tap_code(KC_LEFT); - } - register_mods(MOD_BIT(KC_LSFT)); - register_code(KC_RGHT); - state = STATE_WORD; - } else { // Select line. - if (state == STATE_NONE) { -#ifdef MAC_HOTKEYS - // Tap GUI (Command) + Left, then Shift + GUI + Right. - set_mods(MOD_BIT(KC_LGUI)); - send_keyboard_report(); - tap_code(KC_LEFT); - register_mods(MOD_BIT(KC_LSFT)); - tap_code(KC_RGHT); -#else - // Tap Home, then Shift + End. - clear_mods(); - send_keyboard_report(); - tap_code(KC_HOME); - register_mods(MOD_BIT(KC_LSFT)); - tap_code(KC_END); -#endif // MAC_HOTKEYS - set_mods(mods); - state = STATE_FIRST_LINE; - } else { - register_code(KC_DOWN); - state = STATE_LINE; - } - } - return false; - } - - // `sel_keycode` was released, or another key was pressed. - switch (state) { - case STATE_WORD: - unregister_code(KC_RGHT); -#ifdef MAC_HOTKEYS - unregister_mods(MOD_BIT(KC_LSFT) | MOD_BIT(KC_LALT)); -#else - unregister_mods(MOD_BIT(KC_LSFT) | MOD_BIT(KC_LCTL)); -#endif // MAC_HOTKEYS - state = STATE_SELECTED; - break; - - case STATE_FIRST_LINE: - state = STATE_SELECTED; - break; - - case STATE_LINE: - unregister_code(KC_DOWN); - state = STATE_SELECTED; - break; - - case STATE_SELECTED: - if (keycode == KC_ESC) { - tap_code(KC_RGHT); - state = STATE_NONE; - return false; - } - // Fallthrough intended. - default: - state = STATE_NONE; - } - - return true; -} - diff --git a/keyboards/crkbd/keymaps/sajenim/features/select_word.h b/keyboards/crkbd/keymaps/sajenim/features/select_word.h deleted file mode 100644 index 82f07e2..0000000 --- a/keyboards/crkbd/keymaps/sajenim/features/select_word.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2021-2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @file select_word.h - * @brief Select word/line macro. - * - * Overview - * -------- - * - * Implements a button that selects the current word, assuming conventional text - * editor hotkeys. Pressing it again extends the selection to the following - * word. The effect is similar to word selection (W) in the Kakoune editor. - * - * Pressing the button with shift selects the current line, and pressing the - * button again extends the selection to the following line. - * - * @note Note for Mac users: Windows/Linux editing hotkeys are assumed by - * default. Uncomment the `#define MAC_HOTKEYS` line in select_word.c for Mac - * hotkeys. The Mac implementation is untested, let me know if it has problems. - * - * For full documentation, see - * - */ - -#pragma once - -#include "quantum.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** Handler function for select word. */ -bool process_select_word(uint16_t keycode, keyrecord_t* record, - uint16_t sel_keycode); - -/** - * @fn select_word_task(void) - * Matrix task function for Select Word. - * - * If using `SELECT_WORD_TIMEOUT`, call this function from your - * `matrix_scan_user()` function in keymap.c. (If no timeout is set, calling - * `select_word_task()` has no effect.) - */ -#if SELECT_WORD_TIMEOUT > 0 -void select_word_task(void); -#else -static inline void select_word_task(void) {} -#endif // SELECT_WORD_TIMEOUT > 0 - -#ifdef __cplusplus -} -#endif - diff --git a/keyboards/crkbd/keymaps/sajenim/features/sentence_case.c b/keyboards/crkbd/keymaps/sajenim/features/sentence_case.c deleted file mode 100644 index f1a9e98..0000000 --- a/keyboards/crkbd/keymaps/sajenim/features/sentence_case.c +++ /dev/null @@ -1,338 +0,0 @@ -// Copyright 2022-2023 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @file sentence_case.c - * @brief Sentence Case implementation - * - * For full documentation, see - * - */ - -#include "sentence_case.h" - -#include - -#ifdef NO_ACTION_ONESHOT -// One-shot keys must be enabled for Sentence Case. One-shot keys are enabled -// by default, but are disabled by `#define NO_ACTION_ONESHOT` in config.h. If -// your config.h includes such a line, please remove it. -#error "Sentence case: Please enable oneshot." -#else - -// Number of keys of state history to retain for backspacing. -#define STATE_HISTORY_SIZE 6 - -// clang-format off -/** States in matching the beginning of a sentence. */ -enum { - STATE_INIT, /**< Initial enabled state. */ - STATE_WORD, /**< Within a word. */ - STATE_ABBREV, /**< Within an abbreviation like "e.g.". */ - STATE_ENDING, /**< Sentence ended. */ - STATE_PRIMED, /**< "Primed" state, in the space following an ending. */ - STATE_DISABLED, /**< Sentence Case is disabled. */ -}; -// clang-format on - -#if SENTENCE_CASE_TIMEOUT > 0 -static uint16_t idle_timer = 0; -#endif // SENTENCE_CASE_TIMEOUT > 0 -#if SENTENCE_CASE_BUFFER_SIZE > 1 -static uint16_t key_buffer[SENTENCE_CASE_BUFFER_SIZE] = {0}; -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 -static uint8_t state_history[STATE_HISTORY_SIZE]; -static uint16_t suppress_key = KC_NO; -static uint8_t sentence_state = STATE_INIT; - -// Sets the current state to `new_state`. -static void set_sentence_state(uint8_t new_state) { -#ifndef NO_DEBUG - if (debug_enable && sentence_state != new_state) { - static const char* state_names[] = { - "INIT", "WORD", "ABBREV", "ENDING", "PRIMED", "DISABLED", - }; - dprintf("Sentence case: %s\n", state_names[new_state]); - } -#endif // NO_DEBUG - - const bool primed = (new_state == STATE_PRIMED); - if (primed != (sentence_state == STATE_PRIMED)) { - sentence_case_primed(primed); - } - sentence_state = new_state; -} - -void sentence_case_clear(void) { -#if SENTENCE_CASE_TIMEOUT > 0 - idle_timer = 0; -#endif // SENTENCE_CASE_TIMEOUT > 0 -#if SENTENCE_CASE_BUFFER_SIZE > 1 - memset(key_buffer, 0, sizeof(key_buffer)); -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 - memset(state_history, 0, sizeof(state_history)); - suppress_key = KC_NO; - if (sentence_state != STATE_DISABLED) { - set_sentence_state(STATE_INIT); - } -} - -void sentence_case_on(void) { - if (sentence_state == STATE_DISABLED) { - sentence_state = STATE_INIT; - sentence_case_clear(); - } -} - -void sentence_case_off(void) { - if (sentence_state != STATE_DISABLED) { - set_sentence_state(STATE_DISABLED); - } -} - -void sentence_case_toggle(void) { - if (sentence_state != STATE_DISABLED) { - sentence_case_off(); - } else { - sentence_case_on(); - } -} - -bool is_sentence_case_on(void) { return sentence_state != STATE_DISABLED; } - -#if SENTENCE_CASE_TIMEOUT > 0 -#if SENTENCE_CASE_TIMEOUT < 100 || SENTENCE_CASE_TIMEOUT > 30000 -// Constrain timeout to a sensible range. With the 16-bit timer, the longest -// representable timeout is 32768 ms, rounded here to 30000 ms = half a minute. -#error "sentence_case: SENTENCE_CASE_TIMEOUT must be between 100 and 30000 ms" -#endif - -void sentence_case_task(void) { - if (idle_timer && timer_expired(timer_read(), idle_timer)) { - sentence_case_clear(); // Timed out; clear all state. - } -} -#endif // SENTENCE_CASE_TIMEOUT > 0 - -bool process_sentence_case(uint16_t keycode, keyrecord_t* record) { - // Only process while enabled, and only process press events. - if (sentence_state == STATE_DISABLED || !record->event.pressed) { - return true; - } - -#if SENTENCE_CASE_TIMEOUT > 0 - idle_timer = (record->event.time + SENTENCE_CASE_TIMEOUT) | 1; -#endif // SENTENCE_CASE_TIMEOUT > 0 - - switch (keycode) { -#ifndef NO_ACTION_TAPPING - case QK_MOD_TAP ... QK_MOD_TAP_MAX: - if (record->tap.count == 0) { - return true; - } - keycode = QK_MOD_TAP_GET_TAP_KEYCODE(keycode); - break; -#ifndef NO_ACTION_LAYER - case QK_LAYER_TAP ... QK_LAYER_TAP_MAX: -#endif // NO_ACTION_LAYER - if (record->tap.count == 0) { - return true; - } - keycode = QK_LAYER_TAP_GET_TAP_KEYCODE(keycode); - break; -#endif // NO_ACTION_TAPPING - -#ifdef SWAP_HANDS_ENABLE - case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX: - if (IS_SWAP_HANDS_KEYCODE(keycode) || record->tap.count == 0) { - return true; - } - keycode = QK_SWAP_HANDS_GET_TAP_KEYCODE(keycode); - break; -#endif // SWAP_HANDS_ENABLE - } - - if (keycode == KC_BSPC) { - // Backspace key pressed. Rewind the state and key buffers. - set_sentence_state(state_history[STATE_HISTORY_SIZE - 1]); - - memmove(state_history + 1, state_history, STATE_HISTORY_SIZE - 1); - state_history[0] = STATE_INIT; -#if SENTENCE_CASE_BUFFER_SIZE > 1 - memmove(key_buffer + 1, key_buffer, - (SENTENCE_CASE_BUFFER_SIZE - 1) * sizeof(uint16_t)); - key_buffer[0] = KC_NO; -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 - return true; - } - - const uint8_t mods = get_mods() | get_weak_mods() | get_oneshot_mods(); - uint8_t new_state = STATE_INIT; - - // We search for sentence beginnings using a simple finite state machine. It - // matches things like "a. a" and "a. a" but not "a.. a" or "a.a. a". The - // state transition matrix is: - // - // 'a' '.' ' ' '\'' - // +------------------------------------- - // INIT | WORD INIT INIT INIT - // WORD | WORD ENDING INIT WORD - // ABBREV | ABBREV ABBREV INIT ABBREV - // ENDING | ABBREV INIT PRIMED ENDING - // PRIMED | match! INIT PRIMED PRIMED - char code = sentence_case_press_user(keycode, record, mods); - dprintf("Sentence Case: code = '%c' (%d)\n", code, (int)code); - switch (code) { - case '\0': // Current key should be ignored. - return true; - - case 'a': // Current key is a letter. - switch (sentence_state) { - case STATE_ABBREV: - case STATE_ENDING: - new_state = STATE_ABBREV; - break; - - case STATE_PRIMED: - // This is the start of a sentence. - if (keycode != suppress_key) { - suppress_key = keycode; - set_oneshot_mods(MOD_BIT(KC_LSFT)); // Shift mod to capitalize. - new_state = STATE_WORD; - } - break; - - default: - new_state = STATE_WORD; - } - break; - - case '.': // Current key is sentence-ending punctuation. - switch (sentence_state) { - case STATE_WORD: - new_state = STATE_ENDING; - break; - - default: - new_state = STATE_ABBREV; - } - break; - - case ' ': // Current key is a space. - if (sentence_state == STATE_PRIMED || - (sentence_state == STATE_ENDING -#if SENTENCE_CASE_BUFFER_SIZE > 1 - && sentence_case_check_ending(key_buffer) -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 - )) { - new_state = STATE_PRIMED; - suppress_key = KC_NO; - } - break; - - case '\'': // Current key is a quote. - new_state = sentence_state; - break; - } - - // Slide key_buffer and state_history buffers one element to the left. - // Optimization note: Using manual loops instead of memmove() here saved - // ~100 bytes on AVR. -#if SENTENCE_CASE_BUFFER_SIZE > 1 - for (int8_t i = 0; i < SENTENCE_CASE_BUFFER_SIZE - 1; ++i) { - key_buffer[i] = key_buffer[i + 1]; - } -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 - for (int8_t i = 0; i < STATE_HISTORY_SIZE - 1; ++i) { - state_history[i] = state_history[i + 1]; - } - -#if SENTENCE_CASE_BUFFER_SIZE > 1 - key_buffer[SENTENCE_CASE_BUFFER_SIZE - 1] = keycode; - if (new_state == STATE_ENDING && !sentence_case_check_ending(key_buffer)) { - dprintf("Not a real ending.\n"); - new_state = STATE_INIT; - } -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 - state_history[STATE_HISTORY_SIZE - 1] = sentence_state; - - set_sentence_state(new_state); - return true; -} - -bool sentence_case_just_typed_P(const uint16_t* buffer, const uint16_t* pattern, - int8_t pattern_len) { -#if SENTENCE_CASE_BUFFER_SIZE > 1 - buffer += SENTENCE_CASE_BUFFER_SIZE - pattern_len; - for (int8_t i = 0; i < pattern_len; ++i) { - if (buffer[i] != pgm_read_word(pattern + i)) { - return false; - } - } - return true; -#else - return false; -#endif // SENTENCE_CASE_BUFFER_SIZE > 1 -} - -__attribute__((weak)) bool sentence_case_check_ending(const uint16_t* buffer) { -#if SENTENCE_CASE_BUFFER_SIZE >= 5 - // Don't consider the abbreviations "vs." and "etc." to end the sentence. - if (SENTENCE_CASE_JUST_TYPED(KC_SPC, KC_V, KC_S, KC_DOT) || - SENTENCE_CASE_JUST_TYPED(KC_SPC, KC_E, KC_T, KC_C, KC_DOT)) { - return false; // Not a real sentence ending. - } -#endif // SENTENCE_CASE_BUFFER_SIZE >= 5 - return true; // Real sentence ending; capitalize next letter. -} - -__attribute__((weak)) char sentence_case_press_user(uint16_t keycode, - keyrecord_t* record, - uint8_t mods) { - if ((mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) { - const bool shifted = mods & MOD_MASK_SHIFT; - switch (keycode) { - case KC_LCTL ... KC_RGUI: // Mod keys. - return '\0'; // These keys are ignored. - - case KC_A ... KC_Z: - return 'a'; // Letter key. - - case KC_DOT: // . is punctuation, Shift . is a symbol (>) - return !shifted ? '.' : '#'; - case KC_1: - case KC_SLSH: - return shifted ? '.' : '#'; - case KC_2 ... KC_0: // 2 3 4 5 6 7 8 9 0 - case KC_MINS ... KC_SCLN: // - = [ ] ; backslash - case KC_GRV: - case KC_COMM: - return '#'; // Symbol key. - - case KC_SPC: - return ' '; // Space key. - - case KC_QUOT: - return '\''; // Quote key. - } - } - - // Otherwise clear Sentence Case to initial state. - sentence_case_clear(); - return '\0'; -} - -__attribute__((weak)) void sentence_case_primed(bool primed) {} - -#endif // NO_ACTION_ONESHOT diff --git a/keyboards/crkbd/keymaps/sajenim/features/sentence_case.h b/keyboards/crkbd/keymaps/sajenim/features/sentence_case.h deleted file mode 100644 index 5b1ebbc..0000000 --- a/keyboards/crkbd/keymaps/sajenim/features/sentence_case.h +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2022 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -/** - * @file sentence_case.h - * @brief Sentence case: automatically capitalize the first letter of sentences. - * - * This library automatically capitalizes the first letter of sentences, - * reducing the need to explicitly use shift. To use it, you simply type as - * usual but without shifting at the start of sentences. The feature detects - * when new sentences begin and capitalizes automatically. - * - * Sentence Case matches patterns like - * - * "a. a" - * "a. a" - * "a? a" - * "a!' 'a" - * - * but not - * - * "a... a" - * "a.a. a" - * - * Additionally by default, abbreviations "vs." and "etc." are exceptionally - * detected as not real sentence endings. You can use the callback - * `sentence_case_check_ending()` to define other exceptions. - * - * @note One-shot keys must be enabled. - * - * For full documentation, see - * - */ - -#pragma once - -#include "quantum.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// The size of the keycode buffer for `sentence_case_check_ending()`. It must be -// at least as large as the longest pattern checked. If less than 2, buffering -// is disabled and the callback is not called. -#ifndef SENTENCE_CASE_BUFFER_SIZE -#define SENTENCE_CASE_BUFFER_SIZE 8 -#endif // SENTENCE_CASE_BUFFER_SIZE - -/** - * Handler function for Sentence Case. - * - * Call this function from `process_record_user()` to implement Sentence Case. - */ -bool process_sentence_case(uint16_t keycode, keyrecord_t* record); - -/** - * @fn sentence_case_task(void) - * Matrix task function for Sentence Case. - * - * If using `SENTENCE_CASE_TIMEOUT`, call this function from your - * `matrix_scan_user()` function in keymap.c. (If no timeout is set, calling - * `sentence_case_task()` has no effect.) - */ -#if SENTENCE_CASE_TIMEOUT > 0 -void sentence_case_task(void); -#else -static inline void sentence_case_task(void) {} -#endif - -void sentence_case_on(void); /**< Enables Sentence Case. */ -void sentence_case_off(void); /**< Disables Sentence Case. */ -void sentence_case_toggle(void); /**< Toggles Sentence Case. */ -bool is_sentence_case_on(void); /**< Gets whether currently enabled. */ -void sentence_case_clear(void); /**< Clears Sentence Case to initial state. */ - -/** - * Optional callback to indicate primed state. - * - * This callback gets called when Sentence Case changes to or from a "primed" - * state, useful to indicate with an LED or otherwise that the next letter typed - * will be capitalized. - */ -void sentence_case_primed(bool primed); - -/** - * Optional callback to determine whether there is a real sentence ending. - * - * When a sentence-ending punctuation key is typed, this callback is called to - * determine whether it is a real sentence ending, meaning the first letter of - * the following word should be capitalized. For instance, abbreviations like - * "vs." are usually not real sentence endings. The input argument is a buffer - * of the last SENTENCE_CASE_BUFFER_SIZE keycodes. Returning true means it is a - * real sentence ending; returning false means it is not. - * - * The default implementation checks for the abbreviations "vs." and "etc.": - * - * bool sentence_case_check_ending(const uint16_t* buffer) { - * // Don't consider "vs." and "etc." to end the sentence. - * if (SENTENCE_CASE_JUST_TYPED(KC_SPC, KC_V, KC_S, KC_DOT) || - * SENTENCE_CASE_JUST_TYPED(KC_SPC, KC_E, KC_T, KC_C, KC_DOT)) { - * return false; // Not a real sentence ending. - * } - * return true; // Real sentence ending; capitalize next letter. - * } - * - * @note This callback is used only if `SENTENCE_CASE_BUFFER_SIZE >= 2`. - * Otherwise it has no effect. - * - * @param buffer Buffer of the last `SENTENCE_CASE_BUFFER_SIZE` keycodes. - * @return whether there is a real sentence ending. - */ -bool sentence_case_check_ending(const uint16_t* buffer); - -/** - * Macro to be used in `sentence_case_check_ending()`. - * - * Returns true if a given pattern of keys was just typed by comparing with the - * keycode buffer. This is useful for defining exceptions in - * `sentence_case_check_ending()`. - * - * For example, `SENTENCE_CASE_JUST_TYPED(KC_SPC, KC_V, KC_S, KC_DOT)` returns - * true if " vs." were the last four keys typed. - * - * @note The pattern must be no longer than `SENTENCE_CASE_BUFFER_SIZE`. - */ -#define SENTENCE_CASE_JUST_TYPED(...) \ - ({ \ - static const uint16_t PROGMEM pattern[] = {__VA_ARGS__}; \ - sentence_case_just_typed_P(buffer, pattern, \ - sizeof(pattern) / sizeof(uint16_t)); \ - }) -bool sentence_case_just_typed_P(const uint16_t* buffer, const uint16_t* pattern, - int8_t pattern_len); - -/** - * Optional callback defining which keys are letter, punctuation, etc. - * - * This callback may be useful if you type non-US letters or have customized the - * shift behavior of the punctuation keys. The return value tells Sentence Case - * how to interpret the key: - * - * 'a' Key is a letter, by default KC_A to KC_Z. If occurring at the start of - * a sentence, Sentence Case applies shift to capitalize it. - * - * '.' Key is sentence-ending punctuation. Default: . ? ! - * - * '#' Key types a backspaceable character that isn't part of a word. - * Default: - = [ ] ; ' ` , < > / digits backslash - * - * ' ' Key is a space. Default: KC_SPC - * - * '\'' Key is a quote or double quote character. Default: KC_QUOT. - * - * '\0' Sentence Case should ignore this key. - * - * If a hotkey or navigation key is pressed (or another key that performs an - * action that backspace doesn't undo), then the callback should call - * `sentence_case_clear()` to clear the state and then return '\0'. - * - * The default callback is: - * - * char sentence_case_press_user(uint16_t keycode, - * keyrecord_t* record, - * uint8_t mods) { - * if ((mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) { - * const bool shifted = mods & MOD_MASK_SHIFT; - * switch (keycode) { - * case KC_LCTL ... KC_RGUI: // Mod keys. - * return '\0'; // These keys are ignored. - * - * case KC_A ... KC_Z: - * return 'a'; // Letter key. - * - * case KC_DOT: // . is punctuation, Shift . is a symbol (>) - * return !shifted ? '.' : '#'; - * case KC_1: - * case KC_SLSH: - * return shifted ? '.' : '#'; - * case KC_2 ... KC_0: // 2 3 4 5 6 7 8 9 0 - * case KC_MINS ... KC_SCLN: // - = [ ] ; backslash - * case KC_GRV: - * case KC_COMM: - * return '#'; // Symbol key. - * - * case KC_SPC: - * return ' '; // Space key. - * - * case KC_QUOT: - * return '\''; // Quote key. - * } - * } - * - * // Otherwise clear Sentence Case to initial state. - * sentence_case_clear(); - * return '\0'; - * } - * - * To customize, copy the above function into your keymap and add/remove - * keycodes to the above cases. - * - * @param keycode Current keycode. - * @param record record_t for the current press event. - * @param mods equal to `get_mods() | get_weak_mods() | get_oneshot_mods()` - * @return char code 'a', '.', '#', ' ', or '\0' indicating how the key is to be - * interpreted as described above. - */ -char sentence_case_press_user(uint16_t keycode, keyrecord_t* record, - uint8_t mods); - -#ifdef __cplusplus -} -#endif diff --git a/keyboards/crkbd/keymaps/sajenim/keymap.c b/keyboards/crkbd/keymaps/sajenim/keymap.c index 529f554..6a286f1 100644 --- a/keyboards/crkbd/keymaps/sajenim/keymap.c +++ b/keyboards/crkbd/keymaps/sajenim/keymap.c @@ -15,105 +15,57 @@ */ #include QMK_KEYBOARD_H - -// Awesome features created by getreuer #include "features/achordion.h" -#include "features/layer_lock.h" -#include "features/select_word.h" -#include "features/sentence_case.h" -// https://github.com/getreuer/qmk-keymap/tree/main/features -// Our super useful layers, why we run qmk exclusively. enum layers { - CANARY, // This layout is the result of collaboration between many of the top - // layout creators from the AKL community. - NAV, // Inspired by the colemak communities extend layer, Brings navigation - // and editing to the home position. - NUM, // Contains our numpad and function keys. - SYM, // Contains our symbols. - MOD, // Contains keyboard related modifications. + CANARY, + NAV, + NUM, + SYM, + MOD, }; -// Combo dictionary management (layer names must be defined before engine -// include) -#include "g/keymap_combo.h" +#include "g/keymap_combo.h" // layer names must be defined before engine include -// Our custom keycodes -enum custom_keycodes { - SC_TOGG = SAFE_RANGE, - LLOCK, - SELWORD, +/* Home Row Mods: + * https://precondition.github.io/home-row-mods */ - // Magic keycodes - MG_THE, - MG_BUT, - MG_BEFORE, - MG_JUST, - MG_MENT, - MG_NION, - MG_TMENT, - MG_WHICH, - MG_XES, -}; +#define MT_C LGUI_T(KC_C) +#define MT_R LALT_T(KC_R) +#define MT_S LSFT_T(KC_S) +#define MT_T LCTL_T(KC_T) +#define MT_N RCTL_T(KC_N) +#define MT_E RSFT_T(KC_E) +#define MT_I RALT_T(KC_I) +#define MT_A RGUI_T(KC_A) +#define LT_D LT(SYM, KC_D) +#define LT_H LT(SYM, KC_H) -// This keymap uses Magic Canary, it is inspired by Ikcelaks' Magic Sturdy -// layout. The magic key is triggered with the fn combo. Currently only SFB and -// some common words are considered. -// https://github.com/Ikcelaks/keyboard_layouts +/* One Shot Keys: + * https://github.com/qmk/qmk_firmware/blob/master/docs/one_shot_keys.md */ -// This keymap uses home row mods. In addition to mods, I have home row -// layer-tap keys for the SYM layer. The key arrangement is a variation on -// "GASC-order" home row mods: -// -// Left hand Right hand -// +-------+-------+-------+-------+ +-------+-------+-------+-------+ -// | Gui | Alt | Shift | Ctrl | | Ctrl | Shift | Alt | Gui | -// +-------+-------+-------+-------+ +-------+-------+-------+-------+ -// | Sym | | Sym | -// +-------+ +-------+ - -// Left hand home row mods for CANARY layer. -#define HRM_C LGUI_T(KC_C) -#define HRM_R LALT_T(KC_R) -#define HRM_S LSFT_T(KC_S) -#define HRM_T LCTL_T(KC_T) -// Right hand home row mods for CANARY layer. -#define HRM_N RCTL_T(KC_N) -#define HRM_E RSFT_T(KC_E) -#define HRM_I RALT_T(KC_I) -#define HRM_A RGUI_T(KC_A) -// Bottom row mods for CANARY layer. -#define HRM_D LT(SYM, KC_D) -#define HRM_H LT(SYM, KC_H) - -// Oneshot mods are available on our navigation layer. -// This allows easy chords with typical window manager and terminal -// bindings. Oneshot mods persist through layer changes. - -// Left hand one shot keys. #define OS_LCTL OSM(MOD_LCTL) #define OS_LSFT OSM(MOD_LSFT) #define OS_LALT OSM(MOD_LALT) #define OS_LGUI OSM(MOD_LGUI) -// Right hand one shot keys. #define OS_RCTL OSM(MOD_RCTL) #define OS_RSFT OSM(MOD_RSFT) #define OS_RALT OSM(MOD_RALT) #define OS_RGUI OSM(MOD_RGUI) -// Dual role keys allow us to save space on our keymap -// by having different functions in each the tap and hold slots. -// Excluded from bilateral combinations. +/* Mod Tap: + * https://github.com/qmk/qmk_firmware/blob/master/docs/mod_tap.md */ + #define SPC_NAV LT(NAV, KC_SPC) -#define ENT_SFT LSFT_T(KC_ENT) #define BAK_NUM LT(NUM, KC_BSPC) -// Shortcuts -#define CK_UNDO LCTL(KC_Z) // Undo -#define CK_CUT LCTL(KC_X) // Cut -#define CK_COPY LCTL(KC_C) // Copy -#define CK_PSTE LCTL(KC_V) // Paste +/* Shortcuts: + * Some useful shortcuts such as copy paste */ +#define CK_UNDO LCTL(KC_Z) // Undo +#define CK_CUT LCTL(KC_X) // Cut +#define CK_COPY LCTL(KC_C) // Copy +#define CK_PSTE LCTL(KC_V) // Paste #define DELWORD LCTL(KC_BSPC) // Delete word #define WZ_CMOD LCTL(LSFT(KC_X)) // Wezterm activate copy mode. #define WZ_PSTE LCTL(LSFT(KC_V)) // Wezterm paste from clipboard. @@ -125,11 +77,11 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //,-----------------------------------------------------. ,-----------------------------------------------------. KC_GRV, KC_W, KC_L, KC_Y, KC_P, KC_B, KC_Z, KC_F, KC_O, KC_U, KC_QUOT, DELWORD, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, HRM_C, HRM_R, HRM_S, HRM_T, KC_G, KC_M, HRM_N, HRM_E, HRM_I, HRM_A, KC_SCLN, + KC_TAB, MT_C, MT_R, MT_S, MT_T, KC_G, KC_M, MT_N, MT_E, MT_I, MT_A, KC_SCLN, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, KC_Q, KC_J, KC_V, HRM_D, KC_K, KC_X, HRM_H, KC_SLSH, KC_COMM, KC_DOT, XXXXXXX, + XXXXXXX, KC_Q, KC_J, KC_V, LT_D, KC_K, KC_X, LT_H, KC_SLSH, KC_COMM, KC_DOT, XXXXXXX, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - KC_TAB, BAK_NUM, SPC_NAV, ENT_SFT, QK_REP, SELWORD + QK_REP, BAK_NUM, SPC_NAV, KC_ENT, OS_LSFT, QK_AREP //`--------------------------' `--------------------------' ), @@ -139,9 +91,9 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| XXXXXXX, OS_LGUI, OS_LALT, OS_LSFT, OS_LCTL, KC_VOLD, WZ_PSTE, KC_LEFT, KC_DOWN, KC_RGHT, KC_PGDN, KC_BSPC, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, CK_UNDO, CK_CUT, CK_COPY, CK_PSTE, KC_CALC, KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, + XXXXXXX, CK_UNDO, CK_CUT, CK_COPY, CK_PSTE, KC_CALC, KC_0, KC_1, KC_2, KC_3, KC_4, KC_ENT, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, XXXXXXX, _______, _______, _______, _______ + XXXXXXX, XXXXXXX, _______, XXXXXXX, XXXXXXX, XXXXXXX //`--------------------------' `--------------------------' ), @@ -153,7 +105,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| XXXXXXX, KC_F10, KC_F1, KC_F2, KC_F3, KC_PAUS, KC_0, KC_1, KC_2, KC_3, KC_DOT, KC_ENT, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, _______, XXXXXXX, _______, _______, _______ + XXXXXXX, _______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX //`--------------------------' `--------------------------' ), [SYM] = LAYOUT_split_3x6_3( @@ -167,192 +119,71 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX //`--------------------------' `--------------------------' ), - - [MOD] = LAYOUT_split_3x6_3( - //,-----------------------------------------------------. ,-----------------------------------------------------. - QK_BOOT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, - //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - QK_MAKE, RGB_TOG, RGB_HUI, RGB_SAI, RGB_VAI, XXXXXXX, XXXXXXX, CM_TOGG, AS_TOGG, XXXXXXX, XXXXXXX, XXXXXXX, - //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - QK_RBT, RGB_MOD, RGB_HUD, RGB_SAD, RGB_VAD, XXXXXXX, XXXXXXX, SC_TOGG, AC_TOGG, XXXXXXX, XXXXXXX, XXXXXXX, - //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX - //`--------------------------' `--------------------------' - ), }; // clang-format on -// Bilateral combination exceptions -bool achordion_chord(uint16_t tap_hold_keycode, keyrecord_t *tap_hold_record, - uint16_t other_keycode, keyrecord_t *other_record) { - switch (tap_hold_keycode) { - // Excempt some mod/layer taps. - case SPC_NAV: - case ENT_SFT: - case BAK_NUM: - return true; - break; - } +/* Achordion: + * https://getreuer.info/posts/keyboards/achordion/index.html */ +bool achordion_chord(uint16_t tap_hold_keycode, keyrecord_t *tap_hold_record, uint16_t other_keycode, + keyrecord_t *other_record) { + switch (tap_hold_keycode) { + // Exceptionally consider the following chords as holds, even though they + // are on the same hand. + case SPC_NAV: + case BAK_NUM: return true; break; + } // Otherwise follow opposite hands rule. return achordion_opposite_hands(tap_hold_record, other_record); } -bool remember_last_key_user(uint16_t keycode, keyrecord_t *record, - uint8_t *remembered_mods) { - // Forget Shift on letter keys when Shift or AltGr are the only mods. - switch (keycode) { - case KC_A ... KC_Z: - if ((*remembered_mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) { - *remembered_mods &= ~MOD_MASK_SHIFT; - } - break; - } - return true; -} - -uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) { - switch (keycode) { - // Minimize SFB on canary layout - case HRM_R: - return KC_L; - case KC_V: - return KC_Y; - case HRM_S: - return KC_Y; - case KC_Y: - return KC_S; - case KC_P: - return KC_T; - case HRM_I: - return KC_U; - case KC_U: - return KC_I; - case KC_O: - return KC_E; - case HRM_E: - return KC_O; - // Remove problem scissors bigrams - case KC_L: - return KC_V; - - // Briefs - case SPC_NAV: - return MG_THE; - case KC_COMM: - return MG_BUT; - case KC_B: - return MG_BEFORE; - case KC_J: - return MG_JUST; - case KC_M: - return MG_MENT; - case HRM_N: - return MG_NION; - case HRM_T: - return MG_TMENT; - case KC_W: - return MG_WHICH; - case KC_X: - return MG_XES; - - // vim optimisations - case HRM_C: - return KC_W; // change word - case HRM_D: - return KC_W; // delete word - } - - return KC_TRNS; -} +/* Custom keycodes: + * Program the behaviour of any keycode */ bool process_record_user(uint16_t keycode, keyrecord_t *record) { - if (!process_sentence_case(keycode, record)) { - return false; - } if (!process_achordion(keycode, record)) { return false; } - if (!process_select_word(keycode, record, SELWORD)) { - return false; - } - if (!process_layer_lock(keycode, record, LLOCK)) { - return false; - } - - if (record->event.pressed) { - int rep_count = get_repeat_key_count(); - // Define the behaviour of our custom keycodes. - switch (keycode) { - case SC_TOGG: // Toggle sentence case on/off. - sentence_case_toggle(); - return false; - // Magic key briefs - case MG_THE: - SEND_STRING(/* */ "the"); - return false; - case MG_BUT: - SEND_STRING(/*,*/ " but"); - return false; - case MG_BEFORE: - SEND_STRING(/*b*/ "efore"); - return false; - case MG_JUST: - SEND_STRING(/*j*/ "ust"); - return false; - case MG_MENT: - SEND_STRING(/*m*/ "ent"); - return false; - case MG_NION: - SEND_STRING(/*n*/ "ion"); - return false; - case MG_TMENT: - SEND_STRING(/*t*/ "ment"); - return false; - case MG_WHICH: - SEND_STRING(/*w*/ "hich"); - return false; - case MG_XES: - SEND_STRING(/*x*/ "es"); - return false; - } - if (rep_count > 0) { - // Repeat key overrides. - switch (keycode) { - // Minimize SFB on canary layout - case HRM_N: - SEND_STRING(/*n*/ "f"); - return false; - // Briefs - case SPC_NAV: - SEND_STRING(/* */ "for"); - return false; - case KC_COMM: - SEND_STRING(/*,*/ " and"); - return false; - case HRM_A: - SEND_STRING(/*a*/ "nd"); - return false; - case HRM_I: - SEND_STRING(/*i*/ "ng"); - return false; - case KC_Y: - SEND_STRING(/*y*/ "ou"); - return false; - case KC_B: - SEND_STRING(/*b*/ "ecause"); - return false; - case KC_W: - SEND_STRING(/*w*/ "ould"); - return false; - } - } - } - return true; } +/* Repeat key: + * Configure additional keys to be ignored */ + +bool remember_last_key_user(uint16_t keycode, keyrecord_t *record, uint8_t *remembered_mods) { + // Forget Shift on letter keys when Shift or AltGr are the only mods. + switch (keycode) { + case KC_A ... KC_Z: + if ((*remembered_mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) { + *remembered_mods &= ~MOD_MASK_SHIFT; + } + break; + } + return true; +} + +/* Alternate repeat key: + * dynamically adjust output based on the most recent previous keycode */ + +uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) { + switch (keycode) { + case MT_R: return KC_L; // For "RL" bigram. + case KC_V: return KC_Y; // For "VY" bigram. + case MT_S: return KC_Y; // For "SY" bigram. + case KC_Y: return KC_S; // For "YS" bigram. + case KC_P: return KC_T; // For "PT" bigram. + case MT_I: return KC_U; // For "IU" bigram. + case KC_U: return KC_I; // For "UI" bigram. + case KC_O: return KC_E; // For "OE" bigram. + case MT_E: return KC_O; // For "EO" bigram. + } + return KC_TRNS; +} + +/* Custom matrix scanning: + * This function gets called at every matrix scan */ + void matrix_scan_user(void) { achordion_task(); } #ifdef OLED_ENABLE @@ -370,23 +201,11 @@ oled_rotation_t oled_init_user(oled_rotation_t rotation) { void oled_render_master(void) { // Layer Status switch (get_highest_layer(layer_state)) { - case CANARY: - oled_write(" BAS ", false); - break; - case NAV: - oled_write(" NAV ", false); - break; - case NUM: - oled_write(" NUM ", false); - break; - case SYM: - oled_write(" SYM ", false); - break; - case MOD: - oled_write(" MOD ", false); - break; - default: - oled_write(" UND ", false); + case CANARY: oled_write(" BAS ", false); break; + case NAV: oled_write(" NAV ", false); break; + case NUM: oled_write(" NUM ", false); break; + case SYM: oled_write(" SYM ", false); break; + default: oled_write(" UND ", false); } // Mod Status @@ -422,13 +241,6 @@ void oled_render_master(void) { // Feature Status oled_write("-----", false); - bool autoshift_enabled = get_autoshift_state(); - if (autoshift_enabled) { - oled_write("as: *", false); - } else { - oled_write("as: .", false); - } - bool autocorrect_enabled = autocorrect_is_enabled(); if (autocorrect_enabled) { oled_write("ac: *", false); @@ -443,13 +255,6 @@ void oled_render_master(void) { oled_write("cm: .", false); } - bool sentence_case_enabled = is_sentence_case_on(); - if (sentence_case_enabled) { - oled_write("sc: *", false); - } else { - oled_write("sc: .", false); - } - // WPM Status char wpm_str[4]; sprintf(wpm_str, "%03d", get_current_wpm()); @@ -461,12 +266,10 @@ void oled_render_master(void) { // Corne keyboard logo void oled_render_logo(void) { static const char PROGMEM crkbd_logo[] = { - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, - 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0xa0, - 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, - 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xc0, 0xc1, - 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, - 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0}; + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0}; oled_write_P(crkbd_logo, false); } diff --git a/keyboards/crkbd/keymaps/sajenim/rules.mk b/keyboards/crkbd/keymaps/sajenim/rules.mk index 34cf9c1..322f925 100644 --- a/keyboards/crkbd/keymaps/sajenim/rules.mk +++ b/keyboards/crkbd/keymaps/sajenim/rules.mk @@ -6,20 +6,14 @@ BOOTLOADER = rp2040 LTO_ENABLE = yes # Software features -AUTOCORRECT_ENABLE = yes -AUTO_SHIFT_ENABLE = yes -CAPS_WORD_ENABLE = yes -COMBO_ENABLE = yes -OLED_ENABLE = yes -REPEAT_KEY_ENABLE = yes -RGBLIGHT_ENABLE = yes - +AUTOCORRECT_ENABLE = yes +CAPS_WORD_ENABLE = yes +COMBO_ENABLE = yes +OLED_ENABLE = yes +REPEAT_KEY_ENABLE = yes # Feature libraries -SRC += features/sentence_case.c SRC += features/achordion.c -SRC += features/select_word.c -SRC += features/layer_lock.c # Oled display configuration ifeq ($(OLED_ENABLE),yes)