QMK: Caps Word
Pascal Getreuer, 2021-10-30 (updated 2023-03-11)
🚀 Launched
Caps Word is now a core QMK feature! It was released on 2022-05-28. Update your QMK set up and see QMK Caps Word. Or if you want, you may continue to use the userspace implementation described in this page.
🚀 Launched
Caps Word is available for ZSA keyboards in Oryx! Assign Caps WORD to a key (announcement).
Overview
All-caps identifiers like “MOD_MASK_ALT
” are awkward to
type.
Caps Lock would be the standard solution to this problem, but it is awkward: it needs a dedicated key to toggle it (an imposition on smaller keyboards), and we need to remember to toggle it off after typing the word. Or with normal shifting, we either perform finger gymnastics or need to stop typing in the middle of the word to release shift with one hand to switch to holding shift with the other hand. In my experience, this is a nuisance especially if your shift keys are mod-taps, as in home row mods.
Caps Word, implemented here, is a modern alternative to Caps Lock:
Caps Word is activated by pressing the left and right shift keys at the same time (see also the customization options below). This way you don’t need a dedicated key for using Caps Word.
Caps Word automatically disables itself at the end of the word, that is, once space or any key other than
a
–z
,0
–9
,-
,_
, or backspace is pressed (this is configurable, see below).
Compatibility: I’ve tested that this implementation works with one-shot mods and Space Cadet Shift, and it predictably handles key repeating.
Unlike some other QMK Caps Word implementations, this library does
not use the Caps Lock (KC_CAPS
) keycode. It works even if
you’re remapping Caps Lock at the OS level to Ctrl or something else, as
Emacs and Vim users often do.
Add Caps Word to your keymap
Step 1: In your keymap.c
, call Caps
Word from your process_record_user()
function as
#include "features/caps_word.h"
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
if (!process_caps_word(keycode, record)) { return false; }
// Your macros ...
return true;
}
Step 2: In your rules.mk, add
SRC += features/caps_word.c
# Disable QMK core's Caps Word implementation.
CAPS_WORD_ENABLE = no
Step 3: In the directory containing your
keymap.c
, create a features
subdirectory and
copy caps_word.h
and caps_word.c
there.
Also, your keymap needs both a left and right shift key
KC_LSFT
and KC_RSFT
or one-shot or mod-tap
equivalents. Alternatively, use the customization options below to add
another method of activating Caps Word.
Troubleshooting: Command
You might see a compile message “Caps Word and Command should not be enabled at the same time, since both use the Left Shift + Right Shift key combination.”
Many keyboards enable the Command feature, which by default is also activated using the Left Shift + Right Shift key combination. To avoid conflict, disable Command by adding in rules.mk:
COMMAND_ENABLE = no
Or configure Command to use another key combination like Left Ctrl +
Right Ctrl by defining IS_COMMAND()
in config.h:
// Activate Command with Left Ctrl + Right Ctrl.
#define IS_COMMAND() (get_mods() == MOD_MASK_CTRL)
Using Caps Word
With the above flashed to your keyboard:
Activating: Press and release both left and right shift keys at the same time. If your shift keys are mod-taps, activate Caps Word by holding both shift mod-tap keys until the tapping term, then release them.
Then begin typing to get capitalized letters.
Disabling: Caps Word disables itself when the next word breaking key is typed.
If you want to explicitly stop Caps Word, press and release Ctrl or another modifier. Or in many programs, it may be acceptable to press space and then backspace. Any of these actions disables Caps Word.
Customization options
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 your config.h
#define CAPS_WORD_INVERT_ON_SHIFT
This option works with regular Shift keys KC_LSFT
and
KC_RSFT
and mod-tap Shift keys.
Idle timeout
Optionally, Caps Word may be configured to deactivate if the keyboard
is idle for some time. This is useful to mitigate unintended shifting
when you get interrupted or switch to the mouse while Caps Word is
active. In your config.h, define CAPS_WORD_IDLE_TIMEOUT
with a time in milliseconds:
#define CAPS_WORD_IDLE_TIMEOUT 5000 // Turn off Caps Word after 5 seconds.
and in your keymap.c, define (or add to)
matrix_scan_user()
as
void matrix_scan_user(void) {
();
caps_word_task// Other tasks...
}
The default behavior (when CAPS_WORD_IDLE_TIMEOUT
isn’t
set, or set to 0) is that Caps Word never times out, and in this case it
isn’t necessary to call caps_word_task()
. Caps Word remains
active indefinitely until a word breaking key is pressed.
Functions
Functions to manipulate Caps Word:
Function | Description |
---|---|
caps_word_on() |
Turns Caps Word on. |
caps_word_off() |
Turns Caps Word off. |
caps_word_toggle() |
Toggles Caps Word. |
is_caps_word_on() |
Returns true if Caps Word is currently on. |
These functions can be used to activate, deactivate, or toggle Caps Word from your keymap with a macro, combo, tap dance, or whatever means.
Activate Caps Word with a combo
In my keymap, I
activate Caps Word with a
combo of simultaneously pressing .
and
C
:
enum combo_events {
,
CAPS_COMBO// Other combos...
COMBO_LENGTH};
uint16_t COMBO_LEN = COMBO_LENGTH;
const uint16_t caps_combo[] PROGMEM = {KC_DOT, KC_C, COMBO_END};
[] = {
combo_t key_combos[CAPS_COMBO] = COMBO_ACTION(caps_combo),
// Other combos...
};
void process_combo_event(uint16_t combo_index, bool pressed) {
switch(combo_index) {
case CAPS_COMBO:
if (pressed) {
(); // Activate Caps Word!
caps_word_on}
break;
// Other combos...
}
}
And if you haven’t yet enabled combos, add
COMBO_ENABLE = yes
in rules.mk.
Activate Caps Word by pressing a key
First, enable the toggle key by adding in config.h:
#define CAPS_WORD_TOGGLE_KEY
Then use the CW_TOGG
keycode in your keymap. Pressing
this key toggles Caps Word.
We repurpose the CW_TOGG
keycode from QMK’s Caps Word so
that there is no need to define a keycode yourself. This keycode was
formerly CAPSWRD
, but it was renamed to
CW_TOGG
in QMK on 2022-11-26. Please update
your QMK set up to pick up this change.
Configure which keys are “word breaking”
You can define the
caps_word_press_user(uint16_t keycode)
callback to
configure which keys should be shifted and which keys are considered
“word breaking” and stop Caps Word.
The callback is called on every key press while Caps Word is active.
When the key should be shifted (that is, a letter key), the callback
should call add_weak_mods(MOD_BIT(KC_LSFT))
to shift the
key. Returning true continues the current “word,” while returning false
is “word breaking” and deactivates Caps Word. The default callback
is
bool caps_word_press_user(uint16_t keycode) {
switch (keycode) {
// Keycodes that continue Caps Word, with shift applied.
case KC_A ... KC_Z:
case KC_MINS:
(MOD_BIT(KC_LSFT)); // Apply shift to the next key.
add_weak_modsreturn true;
// Keycodes that continue Caps Word, without shifting.
case KC_1 ... KC_0:
case KC_BSPC:
case KC_DEL:
case KC_UNDS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
To customize, copy the above function into your keymap.c and add or
remove keycodes to the cases. For instance, by default, pressing Shift
keys will stop Caps Word, but you could add cases to return true for
KC_LSFT
and KC_RSFT
to allow using Shift keys
while using Caps Word.
NOTE: Outside of this callback, you can use
caps_word_off()
to turn off Caps Word.
Representing the current Caps Word state
You can define caps_word_set_user(bool active)
to get
callbacks when Caps Word turns on or off. This is useful to represent
the current Caps Word state, e.g. by setting an LED or playing a sound.
In your keymap, define
void caps_word_set_user(bool active) {
if (active) {
// Do something when Caps Word activates.
} else {
// Do something when Caps Word deactivates.
}
}
For instance on the ZSA Moonlander, the following indicates the Caps Word state on LEDs 1 and 4:
#include "moonlander.h"
void keyboard_post_init_user(void) {
// I want to control the Moonlander's LEDs myself.
.led_level = false;
keyboard_config}
void caps_word_set_user(bool active) {
(active);
ML_LED_1(active);
ML_LED_4}
Other implementations
I’m aware of a few other QMK implementations of Caps Word:
Caps Word is a core QMK feature since 2022-05-28. It is functionally the same as the userspace implementation here, though there are a few differences in default settings and API naming.
andrewjrae’s Case Modes makes an extension of the Caps Word idea. In addition to Caps Word, it has modes for easily typing
snake_case_name
,camelCase
,kebab-case
, andpath/to/file
. The Space key is modified, e.g. to type_
for snake case or set one-shot shift for camel case, and pressing Space twice ends the mode.rafaelromao’s Smart Case implements Caps Word and Case Modes functionality, including an idle timeout.
replicaJunction’s QMK users folder has a Caps Word implementation. There is also a matching “Num Word” library applying the same idea to using a number layer.
Ga68’s multi-mode Caps Word implements Case Modes functionality by using QMK Core’s Caps Word with a strategic definition of
caps_word_press_user()
.
Beyond QMK, Caps Word is a core feature in ZMK.
Explanation
Here is a brief explanation of how this Caps Word implementation works. The code checks the mod bits on each key event, activating Caps Word when both left and right shifts are pressed.
While active, Caps Word automatically applies shift as a weak mod as
needed so that letters are shifted and other keys are not. The word
continues while caps_word_press_user
returns true (by
default, for a
–z
,
0
–9
, -
, _
, and
backspace). Additionally, most layer switch keys (MO
,
TO
, TG
, TT
, OSL
,
LT
) are ignored so that Caps Word may be used across
layers. Any other key is considered “word breaking” and disables Caps
Word.
Acknowledgements
Thanks to @drashna, @wheredoesyourmindgo, and @ujl123 on GitHub and u/uolot, u/Dutchnesss1, u/WishCow, and u/IdealParking4462 on Reddit for feedback, bug fixes, and improvements to make Caps Word better. I couldn’t have done it alone!