Skip to content

Commit 2368006

Browse files
authored
v.0.5.0 (#10)
Release of v0.5.0: - 3+ finger roll interpretation - simplified configuration (no more custom keycodes are needed) - no more SMTD_KEYCODES_BEGIN and SMTD_KEYCODES_END are needed - simplified SMTD_MT, SMTD_LT and other macros - bunch of useful macros - some bug fixes
1 parent cb4254c commit 2368006

35 files changed

+4524
-1764
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,7 @@ dkms.conf
5454
.idea
5555

5656
cmake-build-debug
57-
CMakeLists.txt
57+
CMakeLists.txt
58+
59+
build/
60+
.claude/

.run/Python tests.run.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<component name="ProjectRunConfigurationManager">
2+
<configuration default="false" name="Python tests" type="tests" factoryName="Autodetect">
3+
<module name="sm_td" />
4+
<option name="ENV_FILES" value="" />
5+
<option name="INTERPRETER_OPTIONS" value="" />
6+
<option name="PARENT_ENVS" value="true" />
7+
<option name="SDK_HOME" value="" />
8+
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/tests" />
9+
<option name="IS_MODULE_SDK" value="true" />
10+
<option name="ADD_CONTENT_ROOTS" value="true" />
11+
<option name="ADD_SOURCE_ROOTS" value="true" />
12+
<option name="_new_additionalArguments" value="&quot;&quot;" />
13+
<option name="_new_target" value="&quot;$PROJECT_DIR$/tests&quot;" />
14+
<option name="_new_targetType" value="&quot;PATH&quot;" />
15+
<method v="2" />
16+
</configuration>
17+
</component>

LICENSE

Lines changed: 21 additions & 674 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 120 additions & 104 deletions
Large diffs are not rendered by default.

docs/000_overview.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
```
2+
This documentation is written for version 0.4.1.
3+
It is a bit outdated for later versions of SM_TD.
4+
```
15

26
This is the `SM Tap Dance` (`sm_td` or `smtd` for short) user library for QMK.
37
The main goal of this library is to ultimately fix the Home Row Mods (HRM) and Tap Dance problems in QMK.

docs/010_installation_guide.md

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
1. Add `DEFERRED_EXEC_ENABLE = yes` to your `rules.mk` file.
44
2. Add `#define MAX_DEFERRED_EXECUTORS 10` (or add 10 if you already use it) to your `config.h` file.
55
3. Clone the `sm_td.h` repository into your `keymaps/your_keymap` folder (next to your `keymap.c`)
6-
4. Add `#include "sm_td.h"` to your `keymap.c` file. !!! WARNING !!! There is a bug in v0.4.0 and the library would compile with a "'SMTD_KEYCODES_BEGIN' undeclared" error. You need to put this #include "sm_td.h" right after you define your custom keycodes enum (described on p.6).
6+
4. Add `#include "sm_td.h"` to your `keymap.c` file
77
5. Check `!process_smtd` first in your `process_record_user` function like this
88
```c
99
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
@@ -16,37 +16,21 @@
1616
}
1717
```
1818
19-
6. Add `SMTD_KEYCODES_BEGIN` and `SMTD_KEYCODES_END` to you custom keycodes, and put each new custom keycode you want to use with `sm_td` between them.
20-
For example, if you want to use `A`, `S`, `D` and `F` for HRM, you need to create a custom keycode for them like this
19+
6. Create a `smtd_resolution on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count)` function. This is a function to configure behaviour for keys.
20+
For example, if you want to use `KC_A`, `KC_S`, `KC_D` and `KC_F` for HRM, your `on_smtd_action()` function will look like this
2121
```c
22-
enum custom_keycodes {
23-
SMTD_KEYCODES_BEGIN = SAFE_RANGE,
24-
CKC_A, // reads as C(ustom) + KC_A, but you may give any name here
25-
CKC_S,
26-
CKC_D,
27-
CKC_F,
28-
SMTD_KEYCODES_END,
29-
};
30-
```
31-
Please don't forget to put ; at the end of the enum definition. Normally it's not necessary, but if you put #include "sm_td.h" it will break compilation.
32-
Note that `SAFE_RANGE` is a predefined constant in QMK, and is used [to define custom keycodes](https://docs.qmk.fm/custom_quantum_functions).
33-
You need to put it on the beginning of your custom keycodes enum.
34-
Some keyboards may have their own `SAFE_RANGE` constant, so you need to check your firmware for this constant.
35-
36-
7. Place all your custom keycodes on the desired key positions in your `keymaps`.
37-
8. Create a `void on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count)` function that would handle all the actions of the custom keycodes you defined in the previous step.
38-
For example, if you want to use `CKC_A`, `CKC_S`, `CKC_D` and `CKC_F` for HRM, your `on_smtd_action()` function will look like this
39-
```c
40-
void on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
22+
smtd_resolution on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
4123
switch (keycode) {
42-
SMTD_MT(CKC_A, KC_A, KC_LEFT_GUI)
43-
SMTD_MT(CKC_S, KC_S, KC_LEFT_ALT)
44-
SMTD_MT(CKC_D, KC_D, KC_LEFT_CTRL)
45-
SMTD_MT(CKC_F, KC_F, KC_LSFT)
24+
SMTD_MT(KC_A, KC_LEFT_GUI)
25+
SMTD_MT(KC_S, KC_LEFT_ALT)
26+
SMTD_MT(KC_D, KC_LEFT_CTRL)
27+
SMTD_MT(KC_F, KC_LSFT)
4628
}
29+
30+
return SMTD_RESOLUTION_NONE;
4731
}
4832
```
49-
See extensive documentation in the [Customization Guide](https://github.com/stasmarkin/sm_td/blob/main/docs/050_customization.md) with cool [Examples](https://github.com/stasmarkin/sm_td/blob/main/docs/60_customization_examples.md)
33+
See extensive documentation in the [Customization Guide](https://github.com/stasmarkin/sm_td/blob/main/docs/050_customization.md) for all available customisations.
5034

51-
9. (optional) Add global configuration parameters to your `config.h` file (see [timeouts](https://github.com/stasmarkin/sm_td/blob/main/docs/070_customization_timeouts.md) and [feature flags](https://github.com/stasmarkin/sm_td/blob/main/docs/080_customization_features.md)).
52-
10. (optional) Add per-key configuration (see [timeouts](https://github.com/stasmarkin/sm_td/blob/main/docs/070_customization_timeouts.md) and [feature flags](https://github.com/stasmarkin/sm_td/blob/main/docs/080_customization_features.md)).
35+
7. (optional) Add global configuration parameters to your `config.h` file (see [timeouts](https://github.com/stasmarkin/sm_td/blob/main/docs/070_customization_timeouts.md) and [feature flags](https://github.com/stasmarkin/sm_td/blob/main/docs/080_customization_features.md)).
36+
8. (optional) Add per-key configuration (see [timeouts](https://github.com/stasmarkin/sm_td/blob/main/docs/070_customization_timeouts.md) and [feature flags](https://github.com/stasmarkin/sm_td/blob/main/docs/080_customization_features.md)).

docs/015_releases.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
#### `v0.5.0`
2+
- 3+ finger roll interpretation
3+
- simplified configuration (no more custom keycodes are needed)
4+
- no more SMTD_KEYCODES_BEGIN and SMTD_KEYCODES_END are needed
5+
- simplified SMTD_MT, SMTD_LT and other macros
6+
- bunch of useful macros
7+
- some bug fixes
8+
19
#### `v0.4.0`
210
- simplified installation process (no need to init each key with `SMTD()` macro)
311
- added useful `SMTD_MT()`, `SMTD_MTE()`, `SMTD_LT()` macros for easier customization
@@ -9,7 +17,7 @@
917
- optional delay between simultaneous key presses (see SMTD_GLOBAL_SIMULTANEOUS_PRESSES_DELAY_MS in [feature flags](https://github.com/stasmarkin/sm_td/blob/main/docs/080_customization_features.md))
1018

1119
#### `v0.3.0`
12-
- bug fix on pressing same macro key on stage SMTD_STAGE_RELEASE
20+
- bug fix on pressing same macro key on stage SMTD_STAGE_TOUCH_RELEASE
1321
- reduce args number for get_smtd_timeout_default and smtd_feature_enabled_default functions (see Upgrade instructions)
1422
- better stage naming
1523
- comprehensive documentation

docs/020_upgrade_instructions.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## `v0.4.0``v0.5.0`
2+
- replace `sm_td.h` with newer version
3+
- remove SMTD_KEYCODES_BEGIN and SMTD_KEYCODES_END (if you want to)
4+
- change function `void on_smtd_action(...)` to `smtd_resolution on_smtd_action(...)`
5+
- add `return SMTD_RESOLUTION_UNHANDLED;` as the last line of `on_smtd_action(...)` function
6+
- next you have to upgrade SMTD_* macros. There are two ways of doing this:
7+
- **Option 1**: (recommended, but long) for every SMTD_MT (or _LT) macro remove the first argument with custom keycode. So, instead of `SMTD_MT(CKC_A, KC_A, KC_LEFT_GUI, 2)` just leave `SMTD_MT(KC_A, KC_LEFT_GUI, 2)`. You also need to replace every occurrence of CKC_A to KC_A (so, put it in your keycodes matrix, combos and so on). And remove CKC_A from custom_keycodes entirely.
8+
- **Option 2**: (fast, but ugly) replace SMTD_MT with SMTD_MT_ON_MKEY. So, instead of `SMTD_MT(CKC_A, KC_A, KC_LEFT_GUI, 2)` you just write `SMTD_MT_ON_MKEY(CKC_A, KC_A, KC_LEFT_GUI, 2)`. That's it.
9+
110
## `v0.3.1``v0.4.0`
211
- replace `sm_td.h` with newer version
312
- remove `smtd_state smtd_states[]` and `size_t smtd_states_size`

docs/030_known_problems.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
## Three fingers roll
1+
## Partial Combo support
22

3-
If you press 3 keys simultaneously smtd will interpret this as hold + hold + top (read 3.3: Deep Explanation: Three keys and states stack). That's what usually expected in 99% cases, but anyway that breaks fast 3+ fingers rolls while typing. It will be fixed in verison v.1.1.0
3+
`COMBO_ACTION` + `process_combo_event()` is only a supported API for QMK's combo feature.
4+
See [official documentation](https://docs.qmk.fm/features/combo#examples)
45

5-
6-
## Rattle modification key with Mods Recall feature
7-
8-
For example, you hit `↓shift` (that is not a part of smtd), `↓smtd_macro`, `↑shift` and `↑smtd_macro`. Actual tap of smtd_macro wouldn't be sent to OS until you physically release that key. So OS will receive that sequence: `↓shift`, `↑shift` (from physical pressing and releasing shift key), then `↓shift` (from mod recall), `↓↑smtd_macro_tap_action` and `↑shift`. Some programs (like Intellij IDEA) may interpret double shift press as a shortcut for some actions.
9-
10-
To overcome that issue you should put shift modifier as another macro for smtd, so smtd would be able to correctly handle intercepting states for two keys.
6+
Simple `COMBO()` are not supported yet
117

128

139
## Twice quantum key processing before users code

docs/050_customization.md

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,64 @@
1+
```
2+
This documentation is written for version 0.4.1.
3+
It is a bit outdated for later versions of SM_TD.
4+
```
5+
6+
7+
## What is `on_smtd_action()` function?
8+
9+
When you press a key, all state machines in the stack start working.
10+
Other keys you press after the sm_td state machine has run will also be processed by the sm_td state machine.
11+
This state machine might decide to postpone the processing of the key you pressed, so that it will be considered a tap or hold later.
12+
You don't have to worry about this, sm_td will process all keys you press in the correct order and in a very predictable way.
13+
You don't need to understand the internal implementation of the state machine stack, but you do need to know what output you will get from sm_td's state machine.
14+
As soon as you press keys assigned to sm_td, it will call the `on_smtd_action()` function with the following arguments
15+
- uint16_t keycode - keycode of the key you pressed
16+
- smtd_action action - result interpreted action (`SMTD_ACTION_TOUCH`, `SMTD_ACTION_TAP`, `SMTD_ACTION_HOLD`, `SMTD_ACTION_RELEASE`). tap, hold and release are self-explanatory. Touch action fired on key press (without knowing if it is a tap or hold).
17+
- uint8_t tap_count - number of consecutive taps before the current action. (will be reset after hold, pause or any other keypress)
18+
19+
There are only two execution flows for the `on_smtd_action` function:
20+
- `SMTD_ACTION_TOUCH``SMTD_ACTION_TAP`.
21+
- `SMTD_ACTION_TOUCH``SMTD_ACTION_HOLD``SMTD_ACTION_RELEASE`.
22+
23+
Consider the following example to understand the execution flow.
24+
Let's say you want to tap, tap, hold and tap again a custom key `KC`. Here are your finger movements:
25+
26+
- `↓KC` 50ms `↑KC` (first tap finished) 50ms
27+
- `↓KC` 50ms `↑KC` (second tap finished) 50ms
28+
- `↓KC` 200ms (holding long enough for hold action) `↑KC` 50ms
29+
- `↓KC` 50ms `↑KC` (third tap finished)
30+
31+
For this example, you will get the following `on_smtd_action()` calls:
32+
- `on_smtd_action(KC, SMTD_ACTION_TOUCH, 0)` right after pressing `↓KC`
33+
- `on_smtd_action(KC, SMTD_ACTION_TAP, 0)` right after releasing `↑KC` (first tap finished)
34+
- `on_smtd_action(KC, SMTD_ACTION_TOUCH, 1)` right after pressing `↓KC` second time
35+
- `on_smtd_action(KC, SMTD_ACTION_TAP, 1)` right after releasing `↑KC` second time (second tap finished)
36+
- `on_smtd_action(KC, SMTD_ACTION_TOUCH, 2)` right after pressing `↓KC` third time
37+
- `on_smtd_action(KC, SMTD_ACTION_HOLD, 2)` after holding `KC` long enough
38+
- `on_smtd_action(KC, SMTD_ACTION_RELEASE, 2)` right after releasing `↑KC` (hold)
39+
- `on_smtd_action(KC, SMTD_ACTION_TOUCH, 0)` right after pressing `↓KC` fourth time
40+
- `on_smtd_action(KC, SMTD_ACTION_TAP, 0)` right after releasing `↑KC` (third tap finished)
41+
42+
43+
44+
## How to add custom behavior to sm_td keycodes?
45+
146
You need to put all the handlers of your sm_td keycodes into the `on_smtd_action()` function. It's called with the following arguments
247
- `uint16_t keycode` - keycode of the macro key you pressed
3-
- smtd_action action` - result interpreted action (SMTD_ACTION_TOUCH, SMTD_ACTION_TAP, SMTD_ACTION_HOLD, SMTD_ACTION_RELEASE). tap, hold and release are self-explanatory. The touch action is fired on every key press (without knowing if it is a tap or a hold).
4-
- uint8_t tap_count` - Number of consecutive taps before the current action. (will be reset after hold, pause or any other keypress)
48+
- `smtd_action action` - result interpreted action (SMTD_ACTION_TOUCH, SMTD_ACTION_TAP, SMTD_ACTION_HOLD, SMTD_ACTION_RELEASE). tap, hold and release are self-explanatory. The touch action is fired on every key press (without knowing if it is a tap or a hold).
49+
- `uint8_t tap_count` - Number of consecutive taps before the current action. (will be reset after hold, pause or any other keypress)
50+
51+
### `smtd_resolution` return value
52+
53+
The function should return a `smtd_resolution` value to indicate how the action was handled:
54+
- `SMTD_RESOLUTION_UNHANDLED` - The action was not handled by some custom code. `sm_td` will handle it as normal key action
55+
- `SMTD_RESOLUTION_UNCERTAIN` - The action is not yet determined (for example, tapping MT key may result in mod or key, so on tap resolution is uncertain)
56+
- `SMTD_RESOLUTION_DETERMINED` - The action was handled and determined
57+
58+
The rule of thumb is to return `SMTD_RESOLUTION_UNCERTAIN` on `SMTD_ACTION_TOUCH` and `SMTD_RESOLUTION_DETERMINED` on all other actions.
59+
This will be enough for 99.8% of cases. In the other 0.2% contact me, I'm really curious what are you trying to achieve.
60+
61+
### `on_smtd_action()` execution flow
562

663
There are only two execution flows for the `on_smtd_action` function:
764
- `SMTD_ACTION_TOUCH``SMTD_ACTION_TAP`.
@@ -11,8 +68,11 @@ You will never get a tap between hold and release or miss a touch action. So you
1168

1269
One possible structure to describe macro behavior is nested switch-cases. Top level for macro key selection, second for action, third (optional) for tap_count. For example
1370

71+
72+
--- EVERYTHING BELOW IS A BIT OUTDATED ---
73+
1474
```c
15-
void on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
75+
smtd_resolution on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
1676
switch (keycode) {
1777
case CUSTOM_KEYCODE_1: {
1878
switch (action) {
@@ -52,12 +112,13 @@ void on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
52112
}
53113
break;
54114
} // end of switch (action)
55-
break;
115+
return SMTD_RESOLUTION_DETERMINED;
56116
} // end of case CUSTOM_KEYCODE_1
57117

58118
// put all your custom keycodes here
59119

60120
} // end of switch (keycode)
121+
return SMTD_RESOLUTION_UNHANDLED;
61122
} // end of on_smtd_action function
62123
```
63124
@@ -69,8 +130,8 @@ There are special macros to make your code more compact and easier:
69130
They handle custom keycodes in the same way as the standard QMK `MT()` or `LT()` functions.
70131
So instead of writing a multiline handler for each sm_td keycode, you can write something like this
71132
72-
```
73-
void on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) { }
133+
```c
134+
smtd_resolution on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) {
74135
switch (keycode) {
75136
SMTD_MT(CKC_A, KC_A, KC_LEFT_GUI)
76137
SMTD_MT(CKC_S, KC_S, KC_LEFT_ALT)
@@ -80,6 +141,8 @@ void on_smtd_action(uint16_t keycode, smtd_action action, uint8_t tap_count) { }
80141
SMTD_LT(CKC_SPACE, KC_SPACE, LAYER_NUM)
81142
SMTD_LT(CKC_ENTER, KC_ENTER, LAYER_FN)
82143
} // End of switch (keycode)
144+
145+
return SMTD_RESOLUTION_UNHANDLED;
83146
} // End of on_smtd_action function
84147
```
85148

0 commit comments

Comments
 (0)