From e23ba95afd6eac8459851f631471b3603051b812 Mon Sep 17 00:00:00 2001 From: Dialgatrainer02 Date: Wed, 31 Jul 2024 17:06:40 +0100 Subject: [PATCH] add basic keymap for framework --- .../ansi/keymaps/dialgatrainer02/config.h | 10 + .../dialgatrainer02/features/sentence_case.c | 346 ++++++++++++++++++ .../dialgatrainer02/features/sentence_case.h | 224 ++++++++++++ .../ansi/keymaps/dialgatrainer02/keymap.c | 123 +++++++ .../ansi/keymaps/dialgatrainer02/rules.mk | 14 + 5 files changed, 717 insertions(+) create mode 100644 keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/config.h create mode 100644 keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.c create mode 100644 keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.h create mode 100644 keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/keymap.c create mode 100644 keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/rules.mk diff --git a/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/config.h b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/config.h new file mode 100644 index 000000000000..4a0effa6b71b --- /dev/null +++ b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/config.h @@ -0,0 +1,10 @@ +//optimisations +#define NO_MUSIC_MODE +#undef LOCKING_SUPPORT_ENABLE +#undef LOCKING_RESYNC_ENABLE +#define LAYER_STATE_8BIT + +#define DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD +/*TODO +add snap tap and configire once implementation is ready +*/ diff --git a/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.c b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.c new file mode 100644 index 000000000000..60dbb9f4f466 --- /dev/null +++ b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.c @@ -0,0 +1,346 @@ +// 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 + +#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 "sentence_case: QMK version is too old to build. Please update QMK." +#elif defined(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; +} + +static void clear_state_history(void) { +#if SENTENCE_CASE_TIMEOUT > 0 + idle_timer = 0; +#endif // SENTENCE_CASE_TIMEOUT > 0 + memset(state_history, STATE_INIT, sizeof(state_history)); + if (sentence_state != STATE_DISABLED) { + set_sentence_state(STATE_INIT); + } +} + +void sentence_case_clear(void) { + clear_state_history(); + suppress_key = KC_NO; +#if SENTENCE_CASE_BUFFER_SIZE > 1 + memset(key_buffer, 0, sizeof(key_buffer)); +#endif // SENTENCE_CASE_BUFFER_SIZE > 1 +} + +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)) { + clear_state_history(); // 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/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.h b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.h new file mode 100644 index 000000000000..5b1ebbcc0980 --- /dev/null +++ b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/features/sentence_case.h @@ -0,0 +1,224 @@ +// 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/framework/laptop16/ansi/keymaps/dialgatrainer02/keymap.c b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/keymap.c new file mode 100644 index 000000000000..79240457b7e0 --- /dev/null +++ b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/keymap.c @@ -0,0 +1,123 @@ +// Copyright 2022 Framework Computer +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H +#include "framework.h" + +#include "features/sentence_case.h" + +// clang-format off +enum _layers { + _BASE, + _FN, + _FN_LOCK, + _FM +}; + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + /* + * ┌─────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬────┐ + * 14 keys │Esc │F1 │F2 │F3 │F4 │F5 │F6 │F7 │F8 │F9 │F10│F11│F12│ Del│ + * ├───┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┤ + * 14 keys │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │Backsp│ + * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬────┤ + * 14 keys │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ \ │ + * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴────┤ + * 13 keys │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ Enter │ + * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───────┤ + * 12 keys │ Shift │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │ Shift │ + * ├────┬───┼───┼───┼───┴───┴───┴───┴───┼───┼───┼───┴┬───┬────┤ + * │ │ │ │ │ │ │ │ │↑ │ │ + * 11 keys │Ctrl│FN │GUI│Alt│ │Alt│Ctl│ ← ├───┤ → │ + * │ │ │ │ │ │ │ │ │ ↓│ │ + * └────┴───┴───┴───┴───────────────────┴───┴───┴────┴───┴────┘ + * 78 total + */ + [_BASE] = LAYOUT( + KC_ESC, 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_DEL, + KC_GRV, 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, + CW_TOGG, 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, MO(_FN), KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RCTL, KC_LEFT, KC_UP, KC_DOWN, KC_RGHT + ), + /* + * Function layer + * ┌─────┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬────┐ + * 14 keys │FN lk│Mut│vDn│vUp│Prv│Ply│Nxt│bDn│bUp│Scn│Air│Prt│App│Ins │ + * ├───┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────┤ + * 14 keys │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ + * ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬────┤ + * 14 keys │ │ │RGB│Nxt│Hue│Sat│Spd│Brt│ │ │Pau│ │ │ │ + * ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴────┤ + * 13 keys │ │ │SRq│Prv│Hue│Sat│Spd│Brt│ScL│ │ │ │ │ + * ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴───────┤ + * 12 keys │ │ │ │ │ │ │Brk│ │ │ │ │ │ + * ├────┬───┼───┼───┼───┴───┴───┴───┴───┼───┼───┼───┴┬───┬────┤ + * │ │ │ │ │ │ │ │ │PgU│ │ + * 11 keys │ │ │ │ │ Toggle Backlight │ │ │Home├───┤End │ + * │ │ │ │ │ │ │ │ │PgD│ │ + * └────┴───┴───┴───┴───────────────────┴───┴───┴────┴───┴────┘ + * 78 total + */ + [_FN] = LAYOUT( + FN_LOCK, KC_MUTE, KC_VOLD, KC_VOLU, KC_MPRV, KC_MPLY, KC_MNXT, KC_BRID, KC_BRIU, G(KC_P), KC_AIRP, KC_PSCR, KC_MSEL, KC_INS, + QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, RGB_TOG, RGB_MOD, RGB_HUI, RGB_SAI, RGB_SPI, RGB_VAI, _______, _______, KC_PAUS, _______, _______, _______, + _______, _______, KC_SYRQ, RGB_RMOD,RGB_HUD, RGB_SAD, RGB_SPD, RGB_VAD, KC_SCRL, _______, _______, _______, _______, + _______, _______, _______, BL_BRTG, _______, KC_BRK, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, BL_STEP, _______, _______, KC_HOME, KC_PGUP, KC_PGDN, KC_END + ), + // Function lock layer + // Everything on F-row locked to function layer, except ESC and DEL + [_FN_LOCK] = LAYOUT( + _______, KC_MUTE, KC_VOLD, KC_VOLU, KC_MPRV, KC_MPLY, KC_MNXT, KC_BRID, KC_BRIU, G(KC_P), KC_AIRP, KC_PSCR, KC_MSEL, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, MO(_FM), _______, _______, _______, _______, _______, _______, _______, _______, _______ + ), + [_FM] = LAYOUT( + FN_LOCK, 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_INS, + _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, + _______, _______, RGB_TOG, RGB_MOD, RGB_HUI, RGB_SAI, RGB_SPI, RGB_VAI, _______, _______, KC_PAUS, _______, _______, _______, + _______, _______, KC_SYRQ, RGB_RMOD,RGB_HUD, RGB_SAD, RGB_SPD, RGB_VAD, KC_SCRL, _______, _______, _______, _______, + _______, _______, _______, BL_BRTG, _______, KC_BRK, _______, _______, _______, _______, _______, _______, + _______, _______, _______, _______, BL_STEP, _______, _______, KC_HOME, KC_PGUP, KC_PGDN, KC_END + ), +}; +// clang-format on + + +// Make sure to keep FN Lock even after reset +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + if (!process_sentence_case(keycode, record)) { return false; } + switch (keycode) { + case FN_LOCK: + if (record->event.pressed) { + if (layer_state_is(_FN)) { + set_single_persistent_default_layer(_FN_LOCK); + } + if (layer_state_is(_FM)) { + set_single_persistent_default_layer(_BASE); + } + } + return false; + break; + default: + break; + } + return true; +} + + +// shows when sentence case is active +void sentence_case_primed(bool primed) { + // Change B0 to the pin for the LED to use. + writePin(LED_CAPS_LOCK_PIN, primed); +}; +//shows when caps word is active +void caps_word_set_user(bool primed) { + writePin(LED_CAPS_LOCK_PIN, primed); +}; diff --git a/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/rules.mk b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/rules.mk new file mode 100644 index 000000000000..af866b719151 --- /dev/null +++ b/keyboards/framework/laptop16/ansi/keymaps/dialgatrainer02/rules.mk @@ -0,0 +1,14 @@ +LTO_ENABLE = yes +CONSOLE_ENABLE = no +COMMAND_ENABLE = no +MOUSEKEY_ENABLE = no +EXTRAKEY_ENABLE = no +SPACE_CADET_ENABLE = no +GRAVE_ESC_ENABLE = no + +CAPS_WORD_ENABLE = yes +VIA_ENABLE = yes +KEY_LOCK_ENABLE = yes +BOOTMAGIC_ENABLE = yes + +SRC += features/sentence_case.c