Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[Core] Caps Word "Invert on shift" option: pressing Shift inverts the shift state. #20092

Merged
merged 9 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/mappings/info_config.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"BOOTMAGIC_LITE_COLUMN_RIGHT": {"info_key": "split.bootmagic.matrix.1", "value_type": "int"},
"BOTH_SHIFTS_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.both_shifts_turns_on", "value_type": "bool"},
"CAPS_WORD_IDLE_TIMEOUT": {"info_key": "caps_word.idle_timeout", "value_type": "int"},
"CAPS_WORD_INVERT_ON_SHIFT": {"info_key": "caps_word.invert_on_shift", "value_type": "bool"},
"COMBO_COUNT": {"info_key": "combo.count", "value_type": "int"},
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"},
Expand Down
3 changes: 2 additions & 1 deletion data/schemas/keyboard.jsonschema
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@
"enabled": {"type": "boolean"},
"both_shifts_turns_on": {"type": "boolean"},
"double_tap_shift_turns_on": {"type": "boolean"},
"idle_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
"idle_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"},
"invert_on_shift": {"type": "boolean"}
}
},
"combo": {
Expand Down
20 changes: 20 additions & 0 deletions docs/feature_caps_word.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ by defining `IS_COMMAND()` in config.h:
## Customizing Caps Word :id=customizing-caps-word
### Invert on shift :id=invert-on-shift
By default, Caps Word turns off when Shift keys are pressed, considering them as
word-breaking. Alternatively with the `CAPS_WORD_INVERT_ON_SHIFT` option,
pressing the Shift key continues Caps Word and inverts the shift state. This
is convenient for uncapitalizing one or a few letters within a word, for
example with Caps Word on, typing "D, B, Shift+A, Shift+A, S" produces "DBaaS",
or typing "P, D, F, Shift+S" produces "PDFs".
Enable it by adding in config.h
```c
#define CAPS_WORD_INVERT_ON_SHIFT
```

This option works with regular Shift keys `KC_LSFT` and `KC_RSFT`, mod-tap Shift
keys, and one-shot Shift keys. Note that while Caps Word is on, one-shot Shift
keys behave like regular Shift keys, and have effect only while they are held.


### Idle timeout :id=idle-timeout

Caps Word turns off automatically if no keys are pressed for
Expand Down
66 changes: 66 additions & 0 deletions quantum/process_keycode/process_caps_word.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,66 @@

#include "process_caps_word.h"

#ifdef CAPS_WORD_INVERT_ON_SHIFT
static uint8_t held_mods = 0;

static bool handle_shift(uint16_t keycode, keyrecord_t* record) {
getreuer marked this conversation as resolved.
Show resolved Hide resolved
switch (keycode) {
case OSM(MOD_LSFT):
keycode = KC_LSFT;
break;
case OSM(MOD_RSFT):
keycode = KC_RSFT;
break;

# ifndef NO_ACTION_TAPPING
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
if (record->tap.count == 0) { // Mod-tap key is held.
switch (QK_MOD_TAP_GET_MODS(keycode)) {
case MOD_LSFT:
keycode = KC_LSFT;
break;
case MOD_RSFT:
keycode = KC_RSFT;
break;
}
}
# endif // NO_ACTION_TAPPING
}

if (keycode == KC_LSFT || keycode == KC_RSFT) {
const uint8_t mod = MOD_BIT(keycode);

if (is_caps_word_on()) {
if (record->event.pressed) {
held_mods |= mod;
} else {
held_mods &= ~mod;
}
return false;
} else if ((held_mods & mod) != 0) {
held_mods &= ~mod;
del_mods(mod);
return record->event.pressed;
}
}

return true;
}
#endif // CAPS_WORD_INVERT_ON_SHIFT

bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
if (keycode == QK_CAPS_WORD_TOGGLE) {
if (record->event.pressed) {
caps_word_toggle();
}
return false;
}
#ifdef CAPS_WORD_INVERT_ON_SHIFT
if (!handle_shift(keycode, record)) {
return false;
}
#endif // CAPS_WORD_INVERT_ON_SHIFT

#ifndef NO_ACTION_ONESHOT
const uint8_t mods = get_mods() | get_oneshot_mods();
Expand Down Expand Up @@ -111,19 +164,24 @@ bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
if (record->tap.count == 0) { // Mod-tap key is held.
const uint8_t mods = QK_MOD_TAP_GET_MODS(keycode);
switch (mods) {
# ifndef CAPS_WORD_INVERT_ON_SHIFT
case MOD_LSFT:
keycode = KC_LSFT;
break;
case MOD_RSFT:
keycode = KC_RSFT;
break;
# endif // CAPS_WORD_INVERT_ON_SHIFT
case MOD_RSFT | MOD_RALT:
keycode = RSFT(KC_RALT);
break;
case MOD_RALT:
return true;
default:
caps_word_off();
# ifdef CAPS_WORD_INVERT_ON_SHIFT
add_mods(held_mods);
# endif // CAPS_WORD_INVERT_ON_SHIFT
return true;
}
} else {
Expand Down Expand Up @@ -163,12 +221,20 @@ bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
clear_weak_mods();
#endif // AUTO_SHIFT_ENABLE
if (caps_word_press_user(keycode)) {
#ifdef CAPS_WORD_INVERT_ON_SHIFT
if (held_mods) {
set_weak_mods(get_weak_mods() ^ MOD_BIT(KC_LSFT));
}
#endif // CAPS_WORD_INVERT_ON_SHIFT
send_keyboard_report();
return true;
}
}

caps_word_off();
#ifdef CAPS_WORD_INVERT_ON_SHIFT
add_mods(held_mods);
#endif // CAPS_WORD_INVERT_ON_SHIFT
return true;
}

Expand Down
21 changes: 21 additions & 0 deletions tests/caps_word/caps_word_invert_on_shift/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2023 Google LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#pragma once

#include "test_common.h"

#define CAPS_WORD_INVERT_ON_SHIFT
#define PERMISSIVE_HOLD
17 changes: 17 additions & 0 deletions tests/caps_word/caps_word_invert_on_shift/test.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright 2023 Google LLC
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

CAPS_WORD_ENABLE = yes

Loading