From 9310304efb34f18baee1b6875ffed540edd1656a Mon Sep 17 00:00:00 2001 From: sajenim Date: Thu, 14 Mar 2024 23:25:39 +0800 Subject: [PATCH] idk --- keyboards/crkbd/keymaps/sajenim/combos.def | 11 +- keyboards/crkbd/keymaps/sajenim/config.h | 25 +- .../keymaps/sajenim/features/achordion.c | 283 +++++++++++++++++ .../keymaps/sajenim/features/achordion.h | 186 ++++++++++++ .../keymaps/sajenim/features/select_word.c | 146 +++++++++ .../keymaps/sajenim/features/select_word.h | 66 ++++ keyboards/crkbd/keymaps/sajenim/keymap.c | 284 +++++++++++++++--- keyboards/crkbd/keymaps/sajenim/layers.h | 10 - keyboards/crkbd/keymaps/sajenim/leader.c | 16 - keyboards/crkbd/keymaps/sajenim/oled.c | 130 -------- .../crkbd/keymaps/sajenim/process_record.c | 47 --- .../crkbd/keymaps/sajenim/process_record.h | 39 --- keyboards/crkbd/keymaps/sajenim/readme.md | 0 keyboards/crkbd/keymaps/sajenim/rules.mk | 14 +- .../keychron/q4/ansi/keymaps/sajenim/keymap.c | 42 ++- 15 files changed, 956 insertions(+), 343 deletions(-) create mode 100644 keyboards/crkbd/keymaps/sajenim/features/achordion.c create mode 100644 keyboards/crkbd/keymaps/sajenim/features/achordion.h create mode 100644 keyboards/crkbd/keymaps/sajenim/features/select_word.c create mode 100644 keyboards/crkbd/keymaps/sajenim/features/select_word.h delete mode 100644 keyboards/crkbd/keymaps/sajenim/layers.h delete mode 100644 keyboards/crkbd/keymaps/sajenim/leader.c delete mode 100644 keyboards/crkbd/keymaps/sajenim/oled.c delete mode 100644 keyboards/crkbd/keymaps/sajenim/process_record.c delete mode 100644 keyboards/crkbd/keymaps/sajenim/process_record.h create mode 100644 keyboards/crkbd/keymaps/sajenim/readme.md diff --git a/keyboards/crkbd/keymaps/sajenim/combos.def b/keyboards/crkbd/keymaps/sajenim/combos.def index 2ed25e9..f73677a 100644 --- a/keyboards/crkbd/keymaps/sajenim/combos.def +++ b/keyboards/crkbd/keymaps/sajenim/combos.def @@ -1,9 +1,8 @@ // Dictionary management -// name result chord keys -COMB(NE_ESC, KC_ESC, KC_N, KC_E) -SUBS(YP_HOME, "~/", KC_Y, KC_P) -SUBS(FO_UPDIR, "../", KC_F, KC_O) - -/* vim: set filetype=c : */ +// name result chord keys +COMB(NE_ESC, KC_ESC, RSFT_T(KC_N), RGUI_T(KC_E)) +COMB(ST_TAB, KC_TAB, LGUI_T(KC_S), LSFT_T(KC_T)) +COMB(TN_CAP, CW_TOGG, LSFT_T(KC_T), RSFT_T(KC_N)) +/* vim: set filetype=c: */ diff --git a/keyboards/crkbd/keymaps/sajenim/config.h b/keyboards/crkbd/keymaps/sajenim/config.h index 44496f3..d43e481 100644 --- a/keyboards/crkbd/keymaps/sajenim/config.h +++ b/keyboards/crkbd/keymaps/sajenim/config.h @@ -12,26 +12,11 @@ // Enable QK_MAKE keycode #define ENABLE_COMPILE_KEYCODE -// Tap-Hold Configuration Options -#define TAPPING_TERM 200 - -// One Shot Keys -#define ONESHOT_TAP_TOGGLE 3 -#define ONESHOT_TIMEOUT 2000 - -// Auto Shift -#define AUTO_SHIFT_TIMEOUT 175 - -// Caps Word -#define BOTH_SHIFTS_TURNS_ON_CAPS_WORD -#define CAPS_WORD_IDLE_TIMEOUT 2000 - -// Combos -#define COMBO_TERM 50 - -// Leader key -#define LEADER_TIMEOUT 500 -#define LEADER_PER_KEY_TIMING +// 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 // RGB #ifdef RGBLIGHT_ENABLE diff --git a/keyboards/crkbd/keymaps/sajenim/features/achordion.c b/keyboards/crkbd/keymaps/sajenim/features/achordion.c new file mode 100644 index 0000000..3d62f6b --- /dev/null +++ b/keyboards/crkbd/keymaps/sajenim/features/achordion.c @@ -0,0 +1,283 @@ +// 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 achordion.c + * @brief Achordion implementation + * + * For full documentation, see + * + */ + +#include "achordion.h" + +#if !defined(IS_QK_MOD_TAP) +// Attempt to detect out-of-date QMK installation, which would fail with +// implicit-function-declaration errors in the code below. +#error "achordion: QMK version is too old to build. Please update QMK." +#else + +// Copy of the `record` and `keycode` args for the current active tap-hold key. +static keyrecord_t tap_hold_record; +static uint16_t tap_hold_keycode = KC_NO; +// Timeout timer. When it expires, the key is considered held. +static uint16_t hold_timer = 0; +// Eagerly applied mods, if any. +static uint8_t eager_mods = 0; +// Flag to determine whether another key is pressed within the timeout. +static bool pressed_another_key_before_release = false; + +#ifdef ACHORDION_STREAK +// Timer for typing streak +static uint16_t streak_timer = 0; +#else +// When disabled, is_streak is never true +#define is_streak false +#endif + +// Achordion's current state. +enum { + // A tap-hold key is pressed, but hasn't yet been settled as tapped or held. + STATE_UNSETTLED, + // Achordion is inactive. + STATE_RELEASED, + // Active tap-hold key has been settled as tapped. + STATE_TAPPING, + // Active tap-hold key has been settled as held. + STATE_HOLDING, + // This state is set while calling `process_record()`, which will recursively + // call `process_achordion()`. This state is checked so that we don't process + // events generated by Achordion and potentially create an infinite loop. + STATE_RECURSING, +}; +static uint8_t achordion_state = STATE_RELEASED; + +// Calls `process_record()` with state set to RECURSING. +static void recursively_process_record(keyrecord_t* record, uint8_t state) { + achordion_state = STATE_RECURSING; + process_record(record); + achordion_state = state; +} + +// Clears eagerly-applied mods. +static void clear_eager_mods(void) { + unregister_mods(eager_mods); + eager_mods = 0; +} + +// Sends hold press event and settles the active tap-hold key as held. +static void settle_as_hold(void) { + clear_eager_mods(); + // Create hold press event. + recursively_process_record(&tap_hold_record, STATE_HOLDING); +} + +bool process_achordion(uint16_t keycode, keyrecord_t* record) { + // Don't process events that Achordion generated. + if (achordion_state == STATE_RECURSING) { + return true; + } + + // If this is a keypress and if the key is different than the tap-hold key, + // this information is saved to a flag to be processed later when the tap-hold + // key is released. + if (!pressed_another_key_before_release && record->event.pressed && + tap_hold_keycode != KC_NO && tap_hold_keycode != keycode) { + pressed_another_key_before_release = true; + } + + // Determine whether the current event is for a mod-tap or layer-tap key. + const bool is_mt = IS_QK_MOD_TAP(keycode); + const bool is_tap_hold = is_mt || IS_QK_LAYER_TAP(keycode); + // Check that this is a normal key event, don't act on combos. +#ifdef IS_KEYEVENT + const bool is_key_event = IS_KEYEVENT(record->event); +#else + const bool is_key_event = + (record->event.key.row < 254 && record->event.key.col < 254); +#endif + + if (achordion_state == STATE_RELEASED) { + if (is_tap_hold && record->tap.count == 0 && record->event.pressed && + is_key_event) { + // A tap-hold key is pressed and considered by QMK as "held". + const uint16_t timeout = achordion_timeout(keycode); + if (timeout > 0) { + achordion_state = STATE_UNSETTLED; + // Save info about this key. + tap_hold_keycode = keycode; + tap_hold_record = *record; + hold_timer = record->event.time + timeout; + + if (is_mt) { // Apply mods immediately if they are "eager." + uint8_t mod = mod_config(QK_MOD_TAP_GET_MODS(tap_hold_keycode)); + if (achordion_eager_mod(mod)) { + eager_mods = ((mod & 0x10) == 0) ? mod : (mod << 4); + register_mods(eager_mods); + } + } + + dprintf("Achordion: Key 0x%04X pressed.%s\n", keycode, + eager_mods ? " Set eager mods." : ""); + return false; // Skip default handling. + } + } + +#ifdef ACHORDION_STREAK + streak_timer = (timer_read() + achordion_streak_timeout(keycode)) | 1; +#endif + return true; // Otherwise, continue with default handling. + } + + if (keycode == tap_hold_keycode && !record->event.pressed) { + // The active tap-hold key is being released. + if (achordion_state == STATE_HOLDING) { + dprintln("Achordion: Key released. Plumbing hold release."); + tap_hold_record.event.pressed = false; + // Plumb hold release event. + recursively_process_record(&tap_hold_record, STATE_RELEASED); + } else if (!pressed_another_key_before_release) { + // No other key was pressed between the press and release of the tap-hold + // key, simulate a hold and then a release without waiting for Achordion + // timeout to end. + dprintln("Achordion: Key released. Simulating hold and release."); + settle_as_hold(); + tap_hold_record.event.pressed = false; + // Plumb hold release event. + recursively_process_record(&tap_hold_record, STATE_RELEASED); + } else { + dprintf("Achordion: Key released.%s\n", + eager_mods ? " Clearing eager mods." : ""); + if (is_mt) { + clear_eager_mods(); + } + } + + achordion_state = STATE_RELEASED; + // The tap-hold key is released, clear the related keycode and the flag. + tap_hold_keycode = KC_NO; + pressed_another_key_before_release = false; + return false; + } + + if (achordion_state == STATE_UNSETTLED && record->event.pressed) { +#ifdef ACHORDION_STREAK + const bool is_streak = (streak_timer != 0); + streak_timer = (timer_read() + achordion_streak_timeout(keycode)) | 1; +#endif + + // Press event occurred on a key other than the active tap-hold key. + + // If the other key is *also* a tap-hold key and considered by QMK to be + // held, then we settle the active key as held. This way, things like + // chording multiple home row modifiers will work, but let's our logic + // consider simply a single tap-hold key as "active" at a time. + // + // Otherwise, we call `achordion_chord()` to determine whether to settle the + // tap-hold key as tapped vs. held. We implement the tap or hold by plumbing + // events back into the handling pipeline so that QMK features and other + // user code can see them. This is done by calling `process_record()`, which + // in turn calls most handlers including `process_record_user()`. + if (!is_streak && (!is_key_event || (is_tap_hold && record->tap.count == 0) || + achordion_chord(tap_hold_keycode, &tap_hold_record, keycode, record))) { + dprintln("Achordion: Plumbing hold press."); + settle_as_hold(); + } else { + clear_eager_mods(); // Clear in case eager mods were set. + + dprintln("Achordion: Plumbing tap press."); + tap_hold_record.tap.count = 1; // Revise event as a tap. + tap_hold_record.tap.interrupted = true; + // Plumb tap press event. + recursively_process_record(&tap_hold_record, STATE_TAPPING); + + send_keyboard_report(); +#if TAP_CODE_DELAY > 0 + wait_ms(TAP_CODE_DELAY); +#endif // TAP_CODE_DELAY > 0 + + dprintln("Achordion: Plumbing tap release."); + tap_hold_record.event.pressed = false; + // Plumb tap release event. + recursively_process_record(&tap_hold_record, STATE_TAPPING); + } + + recursively_process_record(record, achordion_state); // Re-process event. + return false; // Block the original event. + } + +#ifdef ACHORDION_STREAK + // update idle timer on regular keys event + streak_timer = (timer_read() + achordion_streak_timeout(keycode)) | 1; +#endif + return true; +} + +void achordion_task(void) { + if (achordion_state == STATE_UNSETTLED && + timer_expired(timer_read(), hold_timer)) { + dprintln("Achordion: Timeout. Plumbing hold press."); + settle_as_hold(); // Timeout expired, settle the key as held. + } + +#ifdef ACHORDION_STREAK + if (streak_timer && timer_expired(timer_read(), streak_timer)) { + streak_timer = 0; // Expired. + } +#endif +} + +// Returns true if `pos` on the left hand of the keyboard, false if right. +static bool on_left_hand(keypos_t pos) { +#ifdef SPLIT_KEYBOARD + return pos.row < MATRIX_ROWS / 2; +#else + return (MATRIX_COLS > MATRIX_ROWS) ? pos.col < MATRIX_COLS / 2 + : pos.row < MATRIX_ROWS / 2; +#endif +} + +bool achordion_opposite_hands(const keyrecord_t* tap_hold_record, + const keyrecord_t* other_record) { + return on_left_hand(tap_hold_record->event.key) != + on_left_hand(other_record->event.key); +} + +// By default, use the BILATERAL_COMBINATIONS rule to consider the tap-hold key +// "held" only when it and the other key are on opposite hands. +__attribute__((weak)) bool achordion_chord(uint16_t tap_hold_keycode, + keyrecord_t* tap_hold_record, + uint16_t other_keycode, + keyrecord_t* other_record) { + return achordion_opposite_hands(tap_hold_record, other_record); +} + +// By default, the timeout is 1000 ms for all keys. +__attribute__((weak)) uint16_t achordion_timeout(uint16_t tap_hold_keycode) { + return 1000; +} + +// By default, Shift and Ctrl mods are eager, and Alt and GUI are not. +__attribute__((weak)) bool achordion_eager_mod(uint8_t mod) { + return (mod & (MOD_LALT | MOD_LGUI)) == 0; +} + +#ifdef ACHORDION_STREAK +__attribute__((weak)) uint16_t achordion_streak_timeout(uint16_t tap_hold_keycode) { + return 100; // Default of 100 ms. +} +#endif + +#endif // version check + diff --git a/keyboards/crkbd/keymaps/sajenim/features/achordion.h b/keyboards/crkbd/keymaps/sajenim/features/achordion.h new file mode 100644 index 0000000..470f132 --- /dev/null +++ b/keyboards/crkbd/keymaps/sajenim/features/achordion.h @@ -0,0 +1,186 @@ +// 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 achordion.h + * @brief Achordion: Customizing the tap-hold decision. + * + * Overview + * -------- + * + * This library customizes when tap-hold keys are considered held vs. tapped + * based on the next pressed key, like Manna Harbour's Bilateral Combinations or + * ZMK's positional hold. The library works on top of QMK's existing tap-hold + * implementation. You define mod-tap and layer-tap keys as usual and use + * Achordion to fine-tune the behavior. + * + * When QMK settles a tap-hold key as held, Achordion intercepts the event. + * Achordion then revises the event as a tap or passes it along as a hold: + * + * * Chord condition: On the next key press, a customizable `achordion_chord()` + * function is called, which takes the tap-hold key and the next key pressed + * as args. When the function returns true, the tap-hold key is settled as + * held, and otherwise as tapped. + * + * * Timeout: If no other key press occurs within a timeout, the tap-hold key + * is settled as held. This is customizable with `achordion_timeout()`. + * + * Achordion only changes the behavior when QMK considered the key held. It + * changes some would-be holds to taps, but no taps to holds. + * + * @note Some QMK features handle events before the point where Achordion can + * intercept them, particularly: Combos, Key Lock, and Dynamic Macros. It's + * still possible to use these features and Achordion in your keymap, but beware + * they might behave poorly when used simultaneously with tap-hold keys. + * + * + * For full documentation, see + * + */ + +#pragma once + +#include "quantum.h" + +/** + * Suppress tap-hold mods within a *typing streak* by defining + * ACHORDION_STREAK. This can help preventing accidental mod + * activation when performing a fast tapping sequence. + * This is inspired by https://sunaku.github.io/home-row-mods.html#typing-streaks + * + * Enable with: + * + * #define ACHORDION_STREAK + * + * Adjust the maximum time between key events before modifiers can be enabled + * by defining the following callback in your keymap.c: + * + * uint16_t achordion_streak_timeout(uint16_t tap_hold_keycode) { + * return 100; // Default of 100 ms. + * } + */ +#ifdef ACHORDION_STREAK +uint16_t achordion_streak_timeout(uint16_t tap_hold_keycode); +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Handler function for Achordion. + * + * Call this function from `process_record_user()` as + * + * #include "features/achordion.h" + * + * bool process_record_user(uint16_t keycode, keyrecord_t* record) { + * if (!process_achordion(keycode, record)) { return false; } + * // Your macros... + * return true; + * } + */ +bool process_achordion(uint16_t keycode, keyrecord_t* record); + +/** + * Matrix task function for Achordion. + * + * Call this function from `matrix_scan_user()` as + * + * void matrix_scan_user(void) { + * achordion_task(); + * } + */ +void achordion_task(void); + +/** + * Optional callback to customize which key chords are considered "held". + * + * In your keymap.c, define the callback + * + * bool achordion_chord(uint16_t tap_hold_keycode, + * keyrecord_t* tap_hold_record, + * uint16_t other_keycode, + * keyrecord_t* other_record) { + * // Conditions... + * } + * + * This callback is called if while `tap_hold_keycode` is pressed, + * `other_keycode` is pressed. Return true if the tap-hold key should be + * considered held, or false to consider it tapped. + * + * @param tap_hold_keycode Keycode of the tap-hold key. + * @param tap_hold_record keyrecord_t from the tap-hold press event. + * @param other_keycode Keycode of the other key. + * @param other_record keyrecord_t from the other key's press event. + * @return True if the tap-hold key should be considered held. + */ +bool achordion_chord(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record, + uint16_t other_keycode, keyrecord_t* other_record); + +/** + * Optional callback to define a timeout duration per keycode. + * + * In your keymap.c, define the callback + * + * uint16_t achordion_timeout(uint16_t tap_hold_keycode) { + * // ... + * } + * + * The callback determines Achordion's timeout duration for `tap_hold_keycode` + * in units of milliseconds. The timeout be in the range 0 to 32767 ms (upper + * bound is due to 16-bit timer limitations). Use a timeout of 0 to bypass + * Achordion. + * + * @param tap_hold_keycode Keycode of the tap-hold key. + * @return Timeout duration in milliseconds in the range 0 to 32767. + */ +uint16_t achordion_timeout(uint16_t tap_hold_keycode); + +/** + * Optional callback defining which mods are "eagerly" applied. + * + * This callback defines which mods are "eagerly" applied while a mod-tap + * key is still being settled. This is helpful to reduce delay particularly when + * using mod-tap keys with an external mouse. + * + * Define this callback in your keymap.c. The default callback is eager for + * Shift and Ctrl, and not for Alt and GUI: + * + * bool achordion_eager_mod(uint8_t mod) { + * return (mod & (MOD_LALT | MOD_LGUI)) == 0; + * } + * + * @note `mod` should be compared with `MOD_` prefixed codes, not `KC_` codes, + * described at . + * + * @param mod Modifier `MOD_` code. + * @return True if the modifier should be eagerly applied. + */ +bool achordion_eager_mod(uint8_t mod); + +/** + * Returns true if the args come from keys on opposite hands. + * + * @param tap_hold_record keyrecord_t from the tap-hold key's event. + * @param other_record keyrecord_t from the other key's event. + * @return True if the keys are on opposite hands. + */ +bool achordion_opposite_hands(const keyrecord_t* tap_hold_record, + const keyrecord_t* other_record); + +#ifdef __cplusplus +} +#endif + diff --git a/keyboards/crkbd/keymaps/sajenim/features/select_word.c b/keyboards/crkbd/keymaps/sajenim/features/select_word.c new file mode 100644 index 0000000..a1bf939 --- /dev/null +++ b/keyboards/crkbd/keymaps/sajenim/features/select_word.c @@ -0,0 +1,146 @@ +// 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 new file mode 100644 index 0000000..82f07e2 --- /dev/null +++ b/keyboards/crkbd/keymaps/sajenim/features/select_word.h @@ -0,0 +1,66 @@ +// 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/keymap.c b/keyboards/crkbd/keymaps/sajenim/keymap.c index fa137db..480ce9d 100644 --- a/keyboards/crkbd/keymaps/sajenim/keymap.c +++ b/keyboards/crkbd/keymaps/sajenim/keymap.c @@ -15,53 +15,123 @@ */ #include QMK_KEYBOARD_H -#include -#include "config.h" -#include "features/sentence_case.h" -#include "process_record.h" + +// Combo dictionary management #include "g/keymap_combo.h" -#include "layers.h" -/* Keymaps */ +// Awesome features created by getreuer +#include "features/sentence_case.h" +#include "features/achordion.h" +#include "features/select_word.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 (and FKEYs :eyeroll:). +}; + +// Our custom keycodes +enum custom_keycodes { + SC_TOGG = SAFE_RANGE, + SELWORD, +}; + +// 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 +// "CAGS-order" home row mods: +// +// Left hand Right hand +// +-------+-------+-------+-------+ +-------+-------+-------+-------+ +// | Ctrl | Alt | Gui | Shift | | Shift | Gui | Alt | Ctrl | +// +-------+-------+-------+-------+ +-------+-------+-------+-------+ +// | Sym | | Sym | +// +-------+ +-------+ + +// Left hand home row mods for CANARY layer. +#define HRM_C LCTL_T(KC_C) +#define HRM_R LALT_T(KC_R) +#define HRM_S LGUI_T(KC_S) +#define HRM_T LSFT_T(KC_T) +// Right hand home row mods for CANARY layer. +#define HRM_N RSFT_T(KC_N) +#define HRM_E RGUI_T(KC_E) +#define HRM_I RALT_T(KC_I) +#define HRM_A RCTL_T(KC_A) +// Bottom row home row mods for CANARY layer. +#define HRM_Q LT(SYM, KC_Q) +#define HRM_DOT LT(SYM, KC_DOT) + +// Oneshot mods are available on our navigation and numbers 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 thumb keys allow us to save space on our keymap +// by having different functions in each the tap and hold slots. +#define SPC_NAV LT(NAV, KC_SPC) +#define ENT_NUM LT(NUM, KC_ENT) + +// 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 + +#define WZ_CMOD LCTL(LSFT(KC_X)) // Wezterm activate copy mode. +#define WZ_PSTE LCTL(LSFT(KC_V)) // Wezterm paste from clipboard. + +//Keymaps const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - [L_CANARY] = LAYOUT_split_3x6_3( + [CANARY] = LAYOUT_split_3x6_3( //,-----------------------------------------------------. ,-----------------------------------------------------. - QK_LEAD, KC_W, KC_L, KC_Y, KC_P, KC_B, KC_Z, KC_F, KC_O, KC_U, KC_QUOT, DELWORD, + KC_ESC, KC_W, KC_L, KC_Y, KC_P, KC_B, KC_Z, KC_F, KC_O, KC_U, KC_QUOT, KC_BSPC, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - TABCTRL, KC_C, KC_R, KC_S, KC_T, KC_G, KC_M, KC_N, KC_E, KC_I, KC_A, KC_SCLN, + KC_TAB, HRM_C, HRM_R, HRM_S, HRM_T, KC_G, KC_M, HRM_N, HRM_E, HRM_I, HRM_A, KC_SCLN, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - OS_LSFT, KC_Q, KC_J, KC_V, KC_D, KC_K, KC_X, KC_H, KC_SLSH, KC_COMM, KC_DOT, OS_RSFT, + OS_LSFT, HRM_Q, KC_J, KC_V, KC_D, KC_K, KC_X, KC_H, KC_SLSH, KC_COMM, HRM_DOT, OS_RSFT, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - OS_LGUI, BAK_LWR, SPACEFN, ENT_SFT, DEL_RSE, OS_RALT + QK_REP, KC_BSPC, SPC_NAV, ENT_NUM, OS_RSFT, QK_AREP //`--------------------------' `--------------------------' ), - [L_EXTEND] = LAYOUT_split_3x6_3( + [NAV] = LAYOUT_split_3x6_3( //,-----------------------------------------------------. ,-----------------------------------------------------. - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_HOME, KC_UP, KC_END, KC_DEL, _______, + XXXXXXX, XXXXXXX, KC_MPLY, KC_MPRV, KC_MNXT, KC_VOLU, KC_PGUP, KC_HOME, KC_UP, KC_END, KC_DEL, XXXXXXX, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, OS_LGUI, OS_LALT, OS_LSFT, OS_LCTL, XXXXXXX, XXXXXXX, KC_LEFT, KC_DOWN, KC_RGHT, KC_BSPC, XXXXXXX, + XXXXXXX, OS_LCTL, OS_LALT, OS_LGUI, OS_LSFT, KC_VOLD, KC_PGDN, KC_LEFT, KC_DOWN, KC_RGHT, KC_BSPC, XXXXXXX, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_PGUP, KC_PGDN, XXXXXXX, KC_ENT, XXXXXXX, + XXXXXXX, CK_UNDO, CK_CUT, CK_COPY, CK_PSTE, XXXXXXX, XXXXXXX, WZ_CMOD, WZ_PSTE, XXXXXXX, KC_ENT, XXXXXXX, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, XXXXXXX, _______, KC_SPC, WZ_CMOD, WZ_PSTE + XXXXXXX, XXXXXXX, _______, _______, _______, XXXXXXX //`--------------------------' `--------------------------' ), - [L_LOWER] = LAYOUT_split_3x6_3( + [NUM] = LAYOUT_split_3x6_3( //,-----------------------------------------------------. ,-----------------------------------------------------. - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_SLSH, KC_7, KC_8, KC_9, KC_MINS, _______, + XXXXXXX, KC_DEL, KC_7, KC_8, KC_9, XXXXXXX, XXXXXXX, KC_PLUS, XXXXXXX, KC_MINS, XXXXXXX, XXXXXXX, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, OS_LGUI, OS_LALT, OS_LSFT, OS_LCTL, XXXXXXX, KC_ASTR, KC_4, KC_5, KC_6, KC_PLUS, XXXXXXX, + XXXXXXX, KC_BSPC, KC_4, KC_5, KC_6, XXXXXXX, XXXXXXX, OS_RSFT, OS_RGUI, OS_RALT, OS_RCTL, XXXXXXX, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_0, KC_1, KC_2, KC_3, _______, XXXXXXX, + XXXXXXX, KC_ENT, KC_1, KC_2, KC_3, XXXXXXX, XXXXXXX, KC_ASTR, XXXXXXX, KC_BSLS, KC_DOT, XXXXXXX, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, _______, _______, _______, _______, XXXXXXX + XXXXXXX, _______, KC_0, _______, XXXXXXX, XXXXXXX //`--------------------------' `--------------------------' ), - - [L_RAISE] = LAYOUT_split_3x6_3( + [SYM] = LAYOUT_split_3x6_3( //,-----------------------------------------------------. ,-----------------------------------------------------. KC_GRV, XXXXXXX, KC_LABK, KC_DLR, KC_RABK, XXXXXXX, XXXXXXX, KC_LBRC, KC_UNDS, KC_RBRC, XXXXXXX, _______, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| @@ -69,39 +139,175 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| XXXXXXX, XXXXXXX, KC_COLN, KC_ASTR, KC_PLUS, XXXXXXX, XXXXXXX, KC_AMPR, KC_CIRC, KC_TILD, _______, XXXXXXX, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, _______, ALTREP2, _______, _______, XXXXXXX + XXXXXXX, _______, XXXXXXX, XXXXXXX, _______, XXXXXXX //`--------------------------' `--------------------------' ), - [L_ADJUST] = LAYOUT_split_3x6_3( + [MOD] = LAYOUT_split_3x6_3( //,-----------------------------------------------------. ,-----------------------------------------------------. KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - QK_BOOT, RGB_TOG, RGB_HUI, RGB_SAI, RGB_VAI, XXXXXXX, AS_TOGG, CM_TOGG, XXXXXXX, XXXXXXX, XXXXXXX, KC_SLEP, + QK_BOOT, RGB_TOG, RGB_HUI, RGB_SAI, RGB_VAI, XXXXXXX, XXXXXXX, CM_TOGG, AS_TOGG, XXXXXXX, XXXXXXX, KC_SLEP, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------| - QK_MAKE, RGB_MOD, RGB_HUD, RGB_SAD, RGB_VAD, XXXXXXX, AC_TOGG, SC_TOGG, XXXXXXX, XXXXXXX, XXXXXXX, KC_WAKE, + QK_MAKE, RGB_MOD, RGB_HUD, RGB_SAD, RGB_VAD, XXXXXXX, XXXXXXX, SC_TOGG, AC_TOGG, XXXXXXX, XXXXXXX, KC_WAKE, //|--------+--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------| - XXXXXXX, _______, XXXXXXX, XXXXXXX, _______, XXXXXXX + XXXXXXX, XXXXXXX, _______, _______, XXXXXXX, XXXXXXX //`--------------------------' `--------------------------' ), }; -/* Layer Change */ - +// Layer change layer_state_t layer_state_set_user(layer_state_t state) { - // Activate adjust layer - state = update_tri_layer_state(state, L_LOWER, L_RAISE, L_ADJUST); + // Activate MOD layer + state = update_tri_layer_state(state, NAV, NUM, MOD); return state; } +// Define the behaviour of our custom keycodes +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; } -/* Post Init */ + if (record->event.pressed) { + switch (keycode) { + case SC_TOGG: // Toggle sentence case on/off. + sentence_case_toggle(); + return false; + } + } -void keyboard_post_init_user(void) { - // Disable optional features on reboot - autoshift_disable(); - autocorrect_disable(); - combo_disable(); - sentence_case_off(); + return true; } +void matrix_scan_user(void) { + achordion_task(); +} + +#ifdef OLED_ENABLE +// Declare screen rotation for each half +oled_rotation_t oled_init_user(oled_rotation_t rotation) { + if (is_keyboard_master()) { + return OLED_ROTATION_270; + } else { + return OLED_ROTATION_180; + } + return rotation; +} + +// Setup the master screen +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); + } + + // Mod Status + uint8_t this_mod = get_mods(); + uint8_t this_osm = get_oneshot_mods(); + + oled_write("-----", false); + + if ((this_mod | this_osm) & MOD_MASK_GUI) { + oled_write("gui:*", false); + } else { + oled_write("gui:.", false); + } + + if ((this_mod | this_osm) & MOD_MASK_ALT) { + oled_write("alt:*", false); + } else { + oled_write("alt:.", false); + } + + if ((this_mod | this_osm) & MOD_MASK_SHIFT) { + oled_write("sft:*", false); + } else { + oled_write("sft:.", false); + } + + if ((this_mod | this_osm) & MOD_MASK_CTRL) { + oled_write("ctl:*", false); + } else { + oled_write("ctl:.", false); + } + + // 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); + } else { + oled_write("ac: .", false); + } + + bool combo_enabled = is_combo_enabled(); + if (combo_enabled) { + oled_write("cm: *", false); + } else { + 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()); + oled_set_cursor(1, 14); + oled_write_ln(wpm_str, false); + oled_write(" wpm", false); +} + + +// 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}; + oled_write_P(crkbd_logo, false); +} + +// Render our screens +bool oled_task_user(void) { + if (is_keyboard_master()) { + oled_render_master(); + } else { + oled_render_logo(); + } + return false; +} +#endif + +/* vim: set foldmarker=#ifdef,#endif: */ +/* vim: set foldmethod=marker: */ diff --git a/keyboards/crkbd/keymaps/sajenim/layers.h b/keyboards/crkbd/keymaps/sajenim/layers.h deleted file mode 100644 index 58efe29..0000000 --- a/keyboards/crkbd/keymaps/sajenim/layers.h +++ /dev/null @@ -1,10 +0,0 @@ -// Our super useful layers, why we run qmk exclusively. -enum layers { - L_CANARY, // This layout is the result of collaboration between many of the top layout creators from the AKL community. - L_LOWER, // OLKB naming convention, Contains our numpad and function keys. - L_RAISE, // OLKB naming convention, Contains our symbols. - L_ADJUST, // OLKB naming convention, Contains keyboard related settings. - L_EXTEND, // From the colemak community, Brings navigation and editing to the home position. - L_MACRO, // Extra extend functions, Brings mouse keys to the home position and contains our macros. -}; - diff --git a/keyboards/crkbd/keymaps/sajenim/leader.c b/keyboards/crkbd/keymaps/sajenim/leader.c deleted file mode 100644 index 9c73eb8..0000000 --- a/keyboards/crkbd/keymaps/sajenim/leader.c +++ /dev/null @@ -1,16 +0,0 @@ -/* If you’re a Vim user, you probably know what a Leader key is. */ -#include "quantum.h" - -void leader_end_user(void) { - /* Type some strings */ - - // (E)mail (O)utlook - if (leader_sequence_two_keys(KC_E, KC_O)) { - SEND_STRING("jasmine.wilson@outlook.com.au"); - } - // (E)mail (P)roton - else if (leader_sequence_two_keys(KC_E, KC_P)) { - SEND_STRING("its.jassy@pm.me"); - } -} - diff --git a/keyboards/crkbd/keymaps/sajenim/oled.c b/keyboards/crkbd/keymaps/sajenim/oled.c deleted file mode 100644 index ecb93f4..0000000 --- a/keyboards/crkbd/keymaps/sajenim/oled.c +++ /dev/null @@ -1,130 +0,0 @@ -#include QMK_KEYBOARD_H -#include "features/sentence_case.h" -#include "layers.h" -#include - -// Declare screen rotation for each half -oled_rotation_t oled_init_user(oled_rotation_t rotation) { - if (is_keyboard_master()) { - return OLED_ROTATION_270; - } else { - return OLED_ROTATION_180; - } - return rotation; -} - -// Setup the master screen -void oled_render_master(void) { - // Layer Status - switch (get_highest_layer(layer_state)) { - case L_CANARY: - oled_write(" BAS ", false); - break; - case L_LOWER: - oled_write(" LWR ", false); - break; - case L_RAISE: - oled_write(" RSE ", false); - break; - case L_ADJUST: - oled_write(" ADJ ", false); - break; - case L_EXTEND: - oled_write(" EXT ", false); - break; - case L_MACRO: - oled_write(" MAC ", false); - break; - default: - oled_write(" UND ", false); - } - - // Mod Status - uint8_t this_mod = get_mods(); - uint8_t this_osm = get_oneshot_mods(); - - oled_write("-----", false); - - if ((this_mod | this_osm) & MOD_MASK_GUI) { - oled_write("gui:*", false); - } else { - oled_write("gui:.", false); - } - - if ((this_mod | this_osm) & MOD_MASK_ALT) { - oled_write("alt:*", false); - } else { - oled_write("alt:.", false); - } - - if ((this_mod | this_osm) & MOD_MASK_SHIFT) { - oled_write("sft:*", false); - } else { - oled_write("sft:.", false); - } - - if ((this_mod | this_osm) & MOD_MASK_CTRL) { - oled_write("ctl:*", false); - } else { - oled_write("ctl:.", false); - } - - // 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); - } else { - oled_write("ac: .", false); - } - - bool combo_enabled = is_combo_enabled(); - if (combo_enabled) { - oled_write("cm: *", false); - } else { - 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()); - oled_set_cursor(1, 14); - oled_write_ln(wpm_str, false); - oled_write(" wpm", false); -} - - -// 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}; - oled_write_P(crkbd_logo, false); -} - -// Render our screens -bool oled_task_user(void) { - if (is_keyboard_master()) { - oled_render_master(); - } else { - oled_render_logo(); - } - return false; -} diff --git a/keyboards/crkbd/keymaps/sajenim/process_record.c b/keyboards/crkbd/keymaps/sajenim/process_record.c deleted file mode 100644 index 64bfd4a..0000000 --- a/keyboards/crkbd/keymaps/sajenim/process_record.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "process_record.h" -#include "features/sentence_case.h" - -// Use ALTREP2 and ALTREP3 in our layout... -bool remember_last_key_user(uint16_t keycode, keyrecord_t* record, uint8_t* remembered_mods) { - switch (keycode) { - case ALTREP2: - case ALTREP3: - return false; // ignore ALTREP keys. - } - return true; // other keys can be repeated. -} - -static void process_altrep2(uint16_t keycode, uint8_t mods) { - switch (keycode) { - // Expand and centre cursor - case KC_LPRN: SEND_STRING(")"SS_TAP(X_LEFT)); break; // () - case KC_LBRC: SEND_STRING("]"SS_TAP(X_LEFT)); break; // [] - case KC_LCBR: SEND_STRING("}"SS_TAP(X_LEFT)); break; // {} - case KC_DQUO: SEND_STRING("\""); break; // "" - // Complete - case KC_LABK: SEND_STRING("-"); break; // <- - case KC_RABK: SEND_STRING(SS_TAP(X_LEFT)"-"SS_TAP(X_RIGHT)); break; // -> - case KC_DOT: SEND_STRING("|."); break; // .|. - case KC_PIPE: SEND_STRING("||"); break; // ||| - case KC_COLN: SEND_STRING(":"); break; // :: - } -} - -// Define the behaviour of our custom keycodes -bool process_record_user(uint16_t keycode, keyrecord_t* record) { - if (!process_sentence_case(keycode, record)) { return false; } - - switch (keycode) { - case ALTREP2: - if (record->event.pressed) { - process_altrep2(get_last_keycode(), get_last_mods()); - } - return false; - case SC_TOGG: - if (record->event.pressed) { - sentence_case_toggle(); - } - return false; // Skip all further processing of this key - } - return true; -}; diff --git a/keyboards/crkbd/keymaps/sajenim/process_record.h b/keyboards/crkbd/keymaps/sajenim/process_record.h deleted file mode 100644 index 4d4a1c7..0000000 --- a/keyboards/crkbd/keymaps/sajenim/process_record.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include "quantum.h" - -// Our custom keycodes -enum custom_keycodes { - // Additional, distinct "Alternate Repeat"-like keys. - ALTREP2 = SAFE_RANGE, - ALTREP3, - // Toggle Sentence case - SC_TOGG, -}; - -/* Dual role keys */ -#define SPACEFN LT(L_EXTEND, KC_SPC) -// mod-tap -#define TABCTRL MT(MOD_LCTL, KC_TAB) -#define ENT_SFT MT(MOD_RSFT, KC_ENT) -// layer-tap -#define BAK_LWR LT(L_LOWER, KC_BSPC) -#define DEL_RSE LT(L_RAISE, KC_DEL) - -// 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) - -#define OS_RCTL OSM(MOD_RCTL) -#define OS_RSFT OSM(MOD_RSFT) -#define OS_RALT OSM(MOD_RALT) -#define OS_RGUI OSM(MOD_RGUI) - -// Shortcuts -#define DELWORD LCTL(KC_W) -#define WZ_CMOD LCTL(LSFT(KC_X)) -#define WZ_COPY LCTL(LSFT(KC_C)) -#define WZ_PSTE LCTL(LSFT(KC_V)) - diff --git a/keyboards/crkbd/keymaps/sajenim/readme.md b/keyboards/crkbd/keymaps/sajenim/readme.md new file mode 100644 index 0000000..e69de29 diff --git a/keyboards/crkbd/keymaps/sajenim/rules.mk b/keyboards/crkbd/keymaps/sajenim/rules.mk index ee7008f..8cf4840 100644 --- a/keyboards/crkbd/keymaps/sajenim/rules.mk +++ b/keyboards/crkbd/keymaps/sajenim/rules.mk @@ -10,22 +10,18 @@ AUTOCORRECT_ENABLE = yes AUTO_SHIFT_ENABLE = yes CAPS_WORD_ENABLE = yes COMBO_ENABLE = yes -DYNAMIC_MACRO_ENABLE = yes -LEADER_ENABLE = yes -MOUSEKEY_ENABLE = yes OLED_ENABLE = yes REPEAT_KEY_ENABLE = yes RGBLIGHT_ENABLE = yes + # Feature libraries SRC += features/sentence_case.c - -# Behaviour of our custom keycodes -SRC += process_record.c +SRC += features/achordion.c +SRC += features/select_word.c # Oled display configuration ifeq ($(OLED_ENABLE),yes) - SRC += ./oled.c OLED_DRIVER = ssd1306 WPM_ENABLE = yes endif @@ -35,7 +31,3 @@ ifeq ($(COMBO_ENABLE),yes) VPATH += keyboards/gboards endif -# Leader key dictionary -ifeq ($(LEADER_ENABLE),yes) - SRC += ./leader.c -endif diff --git a/keyboards/keychron/q4/ansi/keymaps/sajenim/keymap.c b/keyboards/keychron/q4/ansi/keymaps/sajenim/keymap.c index dd8669c..eba0053 100644 --- a/keyboards/keychron/q4/ansi/keymaps/sajenim/keymap.c +++ b/keyboards/keychron/q4/ansi/keymaps/sajenim/keymap.c @@ -19,48 +19,40 @@ // clang-format off enum layers { - MAC_BASE, - WIN_BASE, + _BASE, _FN1, _FN2, - _FN3 + _EXT, }; const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - [MAC_BASE] = LAYOUT_ansi_61( - KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, - KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, - KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, - KC_LCTL, KC_LOPT, KC_LCMD, KC_SPC, KC_RCMD, MO(_FN1), MO(_FN3), KC_RCTL), - - [WIN_BASE] = LAYOUT_ansi_61( - KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, - KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, - KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, - KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(_FN2), MO(_FN3), KC_RCTL), + [_BASE] = LAYOUT_ansi_61( + KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, + MO(_EXT), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, + KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(_FN1), MO(_FN2), KC_RCTL), [_FN1] = LAYOUT_ansi_61( - KC_GRV, KC_BRID, KC_BRIU, KC_NO, KC_NO, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, RGB_MOD, - RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, KC_INS, KC_PGUP, KC_HOME, _______, - _______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, KC_UP, KC_NO, KC_PGDN, KC_END, _______, - _______, _______, _______, _______, _______, _______, NK_TOGG, KC_LEFT, KC_DOWN, KC_RIGHT, KC_DEL, _______, - _______, _______, _______, _______, _______, _______, _______, _______), - - [_FN2] = LAYOUT_ansi_61( KC_GRV, KC_BRID, KC_BRIU, KC_NO, KC_NO, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, RGB_MOD, RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, KC_APP, KC_SCRL, KC_INS, KC_PGUP, KC_HOME, _______, _______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, KC_UP, KC_PSCR, KC_PGDN, KC_END, _______, _______, _______, _______, _______, _______, _______, NK_TOGG, KC_LEFT, KC_DOWN, KC_RIGHT, KC_DEL, _______, _______, _______, _______, _______, _______, _______, _______, _______), - [_FN3] = LAYOUT_ansi_61( + [_FN2] = LAYOUT_ansi_61( KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, _______, _______, _______, _______, _______, _______, _______, _______, _______, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______), + + [_EXT] = LAYOUT_ansi_61( + QK_BOOT, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_SLEP, + _______, _______, _______, _______, _______, _______, _______, KC_HOME, KC_UP, KC_END, KC_DEL, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, KC_LEFT, KC_DOWN, KC_RGHT, KC_BSPC, _______, _______, + _______, _______, _______, _______, _______, _______, KC_PGUP, KC_PGDN, _______, KC_ENT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______) }; -// clang-format on \ No newline at end of file +// clang-format on