← More about keyboards

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:

Compatibility: I’ve tested that this implementation works with one-shot mods and Space Cadet Shift, and it predictably handles key repeating. If your shift keys are mod-taps, activate Caps Word by holding both shift mod-tap keys until the tapping term, release them, then begin typing.

Unlike some other QMK Caps Word implementations, this library does not use the Caps Lock (KC_CAPS) keycode. It works even if the OS remaps Caps Lock 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

Step 3: In the directory containing your keymap.c, create a features subdirectory and copy caps_word.h and caps_word.c there.

caps_word.h

// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include QMK_KEYBOARD_H

bool process_caps_word(uint16_t keycode, keyrecord_t* record);

caps_word.c

// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0

#include "caps_word.h"

bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
  static bool caps_word_enabled = false;
  static bool shifted = false;

  if (!caps_word_enabled) {
    // Pressing both shift keys at the same time enables caps word.
    if (((get_mods() | get_oneshot_mods()) & MOD_MASK_SHIFT)
        == MOD_MASK_SHIFT) {
      clear_mods();
      clear_oneshot_mods();
      shifted = false;
      caps_word_enabled = true;
      return false;
    }
    return true;
  }

  if (!record->event.pressed) { return true; }

  if (!((get_mods() | get_oneshot_mods()) & ~MOD_MASK_SHIFT)) {
    switch (keycode) {
      case QK_MOD_TAP ... QK_MOD_TAP_MAX:
      case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
        // Earlier return if this has not been considered tapped yet.
        if (record->tap.count == 0) { return true; }
        // Get the base tapping keycode of a mod- or layer-tap key.
        keycode &= 0xff;
    }

    switch (keycode) {
      // Letter keys should be shifted.
      case KC_A ... KC_Z:
        if (!shifted) { register_code(KC_LSFT); }
        shifted = true;
        return true;

      // Keycodes that continue caps word but shouldn't get shifted.
      case KC_1 ... KC_0:
      case KC_BSPC:
      case KC_MINS:
      case KC_UNDS:
        if (shifted) { unregister_code(KC_LSFT); }
        shifted = false;
        return true;

      // Any other keycode disables caps word.
    }
  }

  // Disable caps word.
  caps_word_enabled = false;
  if (shifted) { unregister_code(KC_LSFT); }
  shifted = false;
  return true;
}

Explanation

The code checks the mod bits on each key event, enabling Caps Word when both left and right shifts are active.

While enabled, Caps Word automatically presses and releases left shift (KC_LSFT) as needed so that letters are shifted and other keys are not. The word continues while typing az, 09, -, _, and backspace. Any other key is considered “word breaking” and disables Caps Word. You can edit the switch statement at the end of the function to adjust which keys count as word breaking.

← More about keyboards