Skip to content

stasmarkin/sm_td

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SM_TD (QMK user library)

CI Discord QMK

SM Tap Dance Logo

What is SM_TD?

SM_TD is a QMK user library that makes Home Row Modifiers (HRMs) and Tap Dance reliable during fast typing. It improves tap vs. hold decisions by analyzing key releases (not just presses).

Why SM_TD?

Typing often involves overlapping keypresses. For example:

↓h ↓i ↑h ↑i

This happens when you type "hi" quickly. But QMK’s default behavior may misinterpret ↓h as a hold, not a tap, because ↓i occurred before ↑h.

This leads to bugs when using keys like LT(1, KC_H) for home row mods — triggering layer_move(1) instead of typing h.

SM_TD solves this by:

  • Interpreting keys based on release timing
  • Respecting natural typing habits
  • Avoiding false holds during fast sequences

Background

This library follows the natural overlap that happens when we type quickly. In the hi example, most people press i before releasing h — i.e., ↓h, ↓i, ↑h, ↑i. Stock QMK often interprets these in strict press order, which can misclassify a tap-hold key (e.g., LT(1, KC_H)) as a hold, leading to layer_move(1) instead of a tap.

SM_TD respects your habits rather than forcing you to change them. It pays attention to the time between key releases and interprets them accordingly:

  • ↓h, ↓i, ↑h (tiny pause), ↑i → treat as a combo-like overlap: hold/action on h + tap i
  • ↓h, ↓i, ↑h (long pause), ↑i → treat as sequential taps: tap h + tap i

Features

  • Human-friendly tap+tap vs. hold+tap interpretation for MT and LT
  • Per-key behavior tuning (e.g., hold after N taps in a row)
  • Immediate Tap Dance-style responses (no extra timeout needed)
  • Configurable timeouts per key or globally
  • Feature flags per key or globally
  • Debugging tools
  • Caps Word: integrates with QMK Caps Word
  • Combos: partial support for QMK Combos

Installation

There are two ways to install SM_TD:

Option 1: Manual

  1. In rules.mk, add DEFERRED_EXEC_ENABLE = yes.
  2. In config.h, add #define MAX_DEFERRED_EXECUTORS 10 (or increase if already defined).
  3. Copy sm_td/sm_td.h into your keymaps/<your_keymap>/ folder (next to keymap.c).
  4. Add #include "sm_td.h" in your keymap.c.
  5. Check process_smtd(...) first in process_record_user(...) like this:
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    if (!process_smtd(keycode, record)) {
        return false;
    }

    // your code here

    return true;
}

Option 2: QMK Community Module

  1. In keymap.json, add:

    { "modules": ["stasmarkin/sm_td"] }

That’s it — proceed to Configuration.

Configuration

  1. Create an on_smtd_action() function in your keymap.c that handles extra actions for keycodes. For example, to use KC_A, KC_S, KC_D, and KC_F for Home Row Mods:

    smtd_resolution on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
        switch (keycode) {
            SMTD_MT(KC_A, KC_LEFT_GUI)
            SMTD_MT(KC_S, KC_LEFT_ALT)
            SMTD_MT(KC_D, KC_LEFT_CTRL)
            SMTD_MT(KC_F, KC_LSFT)
        }
    
        return SMTD_RESOLUTION_UNHANDLED;
    }

    See the Customization Guide and practical Examples for more patterns.

  2. (optional) Add global configuration parameters to your config.h file (see timeouts and feature flags).

  3. (optional) Add per-key configuration (see timeouts and feature flags).

Macros for on_smtd_action()

Macro Description
SMTD_MT(KC_A, KC_LEFT_GUI) Basic mod-tap: Tap KC_A → single tap, Hold KC_AKC_LEFT_GUI hold
SMTD_MT(KC_A, KC_LEFT_GUI, 2) Tap count mod-tap: Same as above, but hold after 2 sequential taps results in KC_A hold
↓KC_A, ↑KC_A, ↓KC_A...KC_A tap + KC_LEFT_GUI hold
↓KC_A, ↑KC_A, ↓KC_A, ↑KC_A, ↓KC_A... → 2× KC_A tap + KC_A hold
SMTD_MT(KC_A, KC_LEFT_GUI, 1, false) Caps Word disabled: Basic mod-tap with QMK’s Caps Word feature disabled
SMTD_MTE(KC_A, KC_LEFT_GUI) Eager mod-tap: Holds KC_LEFT_GUI immediately on press
• Quick release → KC_LEFT_GUI released + KC_A tapped
• Continue holding → KC_LEFT_GUI held, no KC_A tap
• Useful for fast mod+mouse clicks
SMTD_MTE(KC_A, KC_LEFT_GUI, 2) Eager with tap count: Eager version of tap count mod-tap
SMTD_MTE(KC_A, KC_LEFT_GUI, 1, false) Eager caps disabled: Eager version with Caps Word disabled
SMTD_LT(KC_A, 2) Layer tap: Momentary layer switching (layer 2), works like SMTD_MT but switches layers instead of modifiers
SMTD_LT(KC_A, 2, 3) Layer tap with count: Hold after 3 sequential taps results in KC_A hold
↓KC_A, ↑KC_A, ↓KC_A...KC_A tap + layer 2 activation
↓KC_A, ↑KC_A, ↓KC_A, ↑KC_A, ↓KC_A, ↑KC_A, ↓KC_A... → 3× KC_A tap + KC_A hold
SMTD_LT(KC_A, 2, 1, false) Layer tap caps disabled: Same as above with Caps Word disabled
SMTD_MT_ON_MKEY(CKC_A, KC_A, KC_LEFT_GUI) Mod-tap with custom keycode: Uses custom keycode CKC_A (do not forget to declare it) in keymap while treating it as KC_A tap and KC_LEFT_GUI hold
• Might be used if you need different behavior of KC_A on different layers
• Useful for migration from older SM_TD versions or when you need custom keycodes
SMTD_LT_ON_MKEY(CKC_A, KC_A, 2) Layer tap with custom keycode: Uses custom keycode CKC_A (do not forget to declare it) in keymap while treating it as KC_A tap and layer 2 activation
• Might be used if you need different behavior of KC_A on different layers
• Useful for migration from older SM_TD versions or when you need custom keycodes

Documentation

There is a /docs folder with extensive documentation.

Also, you may check my layout for a real-world example of using this library.

Community

Start with GitHub issues or pull requests for questions and ideas.

You can also join the SM_TD Discord channel, or reach me on Reddit (u/stasmarkin) or Discord (stasmarkin).

Also, you may email me or tag/text me on Reddit (u/stasmarkin) or Discord (stasmarkin).

Support This Project

If you find this library helpful, consider supporting the project:

GitHub Sponsors Buy Me A Coffee

Crypto support:

  • USDT on TRON: TE4QifvjnPSQoT4oJXYnYAnZxBKAvwUFCN
  • ByBit ID: 230327759

Your support helps me continue developing and maintaining this project. Thank you for using SM_TD!

Roadmap

v0.5.0

  • 3+ finger roll interpretation
  • A collection of useful macros
  • Fix: remove 'SMTD_KEYCODES_BEGIN' undeclared error
  • Bug fixes

v0.5.1

  • QMK community module integration

v0.5.2

  • Fix: smtd_current_keycode is now compatible with AVR (fixes issue #48)

v0.5.3

  • Feature: add SMTD_MBTE5_ON_MKEY macro

v0.5.4 (we are here)

  • Feature: split sm_td into .h and .c file

v0.6.0+ and further v0.x

  • dynamic timeouts
  • better combo support
  • other feature requests (see issues)

v1.0.0

  • stable API
  • memory optimizations (on storing active states)
  • memory optimizations (on state machine stack size)
  • split into header and source files

Special Thanks

Code contributions

Beta testing

(please, let me know, if I have forgotten someone)

Star History

Star History Chart

About

SM Tap Dance user library for QMK

Resources

License

Stars

Watchers

Forks

Contributors 5