Custom Caps Word behavior for ZMK v0.3.x that works better with Russian typing and avoids accidental Ctrl+Shift+….
This module provides &caps_word_ru — a drop-in alternative to ZMK’s built-in &caps_word, implemented as an out-of-tree ZMK/Zephyr module (no ZMK fork required).
ZMK’s built-in &caps_word is great, but it has two practical limitations for RU users:
- Only
A..Zare treated as “letters” for auto-shift.- On a Russian OS layout, letters like
ХЪЖЭБЮare produced by keys that are punctuation in US layout ([ ] ; ' , .), so&caps_worddoes not auto-shift them.
- On a Russian OS layout, letters like
- Modifiers do not deactivate Caps Word.
- With Caps Word active, pressing
Ctrl+Zmay becomeCtrl+Shift+Z(undo → redo).
- With Caps Word active, pressing
caps_word_ru solves both.
In addition to A..Z, caps_word_ru treats these keycodes as alphabetic targets:
[];',.
On a Russian OS layout these correspond to ХЪЖЭБЮ (ЙЦУКЕН), so Caps Word will auto-shift them too.
Note: On an English OS layout, this means those punctuation keys will also get Shift while Caps Word is active (e.g.
[→{). This is a trade-off because the firmware cannot know the OS layout.
While caps_word_ru is active:
- Shift is allowed (held explicitly, or applied implicitly).
- Any involvement of Ctrl / Alt / GUI will immediately deactivate
caps_word_ru.
This includes:
&kp LC(X)/&kp LA(X)style bindings (mods are implicit on the key event)- Manual sequences like holding Ctrl and pressing a key (
explicit mods)
This is an out-of-tree module you add via west.yml.
- Designed for ZMK v0.3.0 and expected to work across v0.3.x.
- Tested as a behavior module compiled into
apptarget.
If you use a significantly newer ZMK version, API changes may require small updates.
In your zmk-config repository, edit config/west.yml and add this project.
Example:
manifest:
remotes:
- name: zmkfirmware
url-base: https://github.com/zmkfirmware
- name: idefant
url-base: https://github.com/idefant
projects:
- name: zmk
remote: zmkfirmware
revision: v0.3.0
import: app/west.yml
- name: zmk-caps-word-ru
remote: idefant
revision: main
self:
path: configCommit and push.
In your <keyboard>.keymap (or whichever .keymap file you use), add:
#include <behaviors/caps_word_ru.dtsi>This declares a default &caps_word_ru instance in the /behaviors node.
Example:
/ {
keymap {
compatible = "zmk,keymap";
default_layer {
bindings = <
&caps_word_ru &kp A &kp B
>;
};
};
};
You can override the defaults in your keymap:
&caps_word_ru {
mods = <(MOD_LSFT)>;
/* Keys that do not deactivate caps word
* (besides alphas/numerics which always continue).
*/
continue-list = <UNDERSCORE BACKSPACE DELETE>;
};
The default instance from dts/behaviors/caps_word_ru.dtsi uses:
mods = MOD_LSFTcontinue-list = UNDERSCORE BACKSPACE DELETE
-
Listens to
zmk_keycode_state_changedevents. -
When active, it:
- Cancels itself if
Ctrl/Alt/GUIare involved (implicit or explicit) - Cancels itself if a modifier key is pressed (except Shift)
- Adds
Shiftto “alphabetic” keys (A–Z plus[ ] ; ' , .) - Deactivates on keys not considered “continuations”
- Cancels itself if
Your module must add sources to the app target, not build as a standalone Zephyr library.
This module’s CMakeLists.txt uses:
target_sources(app PRIVATE …)
If you copied code into another module, make sure you do the same.
ZMK v0.3.x uses long HID names like:
HID_USAGE_KEY_KEYBOARD_LEFT_BRACKET_AND_LEFT_BRACEHID_USAGE_KEY_KEYBOARD_APOSTROPHE_AND_QUOTE
If you see “undeclared” errors, check the exact symbol names in your ZMK version.
MIT (same spirit as ZMK). See LICENSE if present in your fork/repo.
- Based on ZMK’s upstream
behavior_caps_word.c(v0.3.0), adapted for RU typing and modifier-safe behavior.