Browse Source

Custom Tapping Term per key (#5009)

* Add customizable tapping terms

* Add Documentation

* Fix function

* Fixes

* It's not a pointer

* Add debugging output

* Update documentation to be at least vaguely accurate

* Use `get_tapping_term(tapping_key.event)` instead

`e` doesn't include column and row information, properly. It registers as 255, regardless of the actual keypress.

However `tapping_key.event` actually gives the correct column and row information.  It appears be the correct structure to use. 

In fact, it looks like the issue is that `e` is actually the "TICK" structure, as defined in keyboard.h

* Use variable tapping term value rather than define

* Silly drashna - tapping_key.event, not event

* add get_event_keycode() function

* Fix typo

Co-Authored-By: drashna <drashna@live.com>

* Remove post_process_record_quantum since it's the wrong PR

* Update quantum/quantum.c

Co-Authored-By: drashna <drashna@live.com>

* Better handle ifdef statement for permissive hold

Since we can't be sure that tapping term is actually 500

* Update quantum.c comments based on feedback

* Clean up get_tapping_term function

Clean up function so that users don't need to call the event function, and instead only check the keycode

* Add ability to run functionality on and off

* Make ifdef's more compact
pjones-keymap
Drashna Jaelre 3 months ago
parent
commit
5701b75e3c

+ 2
- 0
docs/config_options.md View File

@@ -126,6 +126,8 @@ If you define these options you will enable the associated feature, which may in
126 126
 
127 127
 * `#define TAPPING_TERM 200`
128 128
   * how long before a tap becomes a hold, if set above 500, a key tapped during the tapping term will turn it into a hold too
129
+* `#define TAPPING_TERM_PER_KEY`
130
+  * enables handling for per key `TAPPING_TERM` settings
129 131
 * `#define RETRO_TAPPING`
130 132
   * tap anyway, even after TAPPING_TERM, if there was no other key interruption between press and release
131 133
   * See [Retro Tapping](feature_advanced_keycodes.md#retro-tapping) for details

+ 29
- 0
docs/custom_quantum_functions.md View File

@@ -323,6 +323,7 @@ uint32_t layer_state_set_user(uint32_t state) {
323 323
 * Keyboard/Revision: `uint32_t layer_state_set_kb(uint32_t state)`
324 324
 * Keymap: `uint32_t layer_state_set_user(uint32_t state)`
325 325
 
326
+
326 327
 The `state` is the bitmask of the active layers, as explained in the [Keymap Overview](keymap.md#keymap-layer-status)
327 328
 
328 329
 
@@ -460,3 +461,31 @@ And you're done.  The RGB layer indication will only work if you want it to. And
460 461
 * Keymap: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)` and `void eeconfig_update_user(uint32_t val)`
461 462
 
462 463
 The `val` is the value of the data that you want to write to EEPROM.  And the `eeconfig_read_*` function return a 32 bit (DWORD) value from the EEPROM. 
464
+
465
+# Custom Tapping Term
466
+
467
+By default, the tapping term is defined globally, and is not configurable by key.  For most users, this is perfectly fine.  But in come cases, dual function keys would be greatly improved by different timeouts than `LT` keys, or because some keys may be easier to hold than others.  Instead of using custom key codes for each, this allows for per key configurable `TAPPING_TERM`.
468
+
469
+To enable this functionality, you need to add `#define TAPPING_TERM_PER_KEY` to your `config.h`, first.  
470
+
471
+
472
+## Example `get_tapping_term` Implementation
473
+
474
+To change the `TAPPING TERM` based on the keycode, you'd want to add something like the following to your `keymap.c` file: 
475
+
476
+```c
477
+uint16_t get_tapping_term(uint16_t keycode) {
478
+  switch (keycode) {
479
+    case SFT_T(KC_SPC):
480
+      return TAPPING_TERM + 1250;
481
+    case LT(1, KC_GRV):
482
+      return 130;
483
+    default:
484
+      return TAPPING_TERM;
485
+  }
486
+}
487
+```
488
+
489
+### `get_tapping_term` Function Documentation
490
+
491
+Unlike many of the other functions here, there isn't a need (or even reason) to have a quantum or keyboard level function. Only a user level function is useful here, so no need to mark it as such.

+ 22
- 10
quantum/quantum.c View File

@@ -225,27 +225,39 @@ static uint16_t scs_timer[2] = {0, 0};
225 225
  */
226 226
 static bool grave_esc_was_shifted = false;
227 227
 
228
-bool process_record_quantum(keyrecord_t *record) {
228
+/* Convert record into usable keycode via the contained event. */
229
+uint16_t get_record_keycode(keyrecord_t *record) {
230
+  return get_event_keycode(record->event);
231
+}
229 232
 
230
-  /* This gets the keycode from the key pressed */
231
-  keypos_t key = record->event.key;
232
-  uint16_t keycode;
233
+
234
+/* Convert event into usable keycode. Checks the layer cache to ensure that it
235
+ * retains the correct keycode after a layer change, if the key is still pressed.
236
+ */
237
+uint16_t get_event_keycode(keyevent_t event) {
233 238
 
234 239
   #if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
235 240
     /* TODO: Use store_or_get_action() or a similar function. */
236 241
     if (!disable_action_cache) {
237 242
       uint8_t layer;
238 243
 
239
-      if (record->event.pressed) {
240
-        layer = layer_switch_get_layer(key);
241
-        update_source_layers_cache(key, layer);
244
+      if (event.pressed) {
245
+        layer = layer_switch_get_layer(event.key);
246
+        update_source_layers_cache(event.key, layer);
242 247
       } else {
243
-        layer = read_source_layers_cache(key);
248
+        layer = read_source_layers_cache(event.key);
244 249
       }
245
-      keycode = keymap_key_to_keycode(layer, key);
250
+      return keymap_key_to_keycode(layer, event.key);
246 251
     } else
247 252
   #endif
248
-    keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
253
+    return keymap_key_to_keycode(layer_switch_get_layer(event.key), event.key);
254
+}
255
+
256
+/* Main keycode processing function. Hands off handling to other functions,
257
+ * then processes internal Quantum keycodes, then processes ACTIONs.
258
+ */
259
+bool process_record_quantum(keyrecord_t *record) {
260
+    uint16_t keycode = get_record_keycode(record);
249 261
 
250 262
     // This is how you use actions here
251 263
     // if (keycode == KC_LEAD) {

+ 2
- 0
quantum/quantum.h View File

@@ -224,6 +224,8 @@ void matrix_init_kb(void);
224 224
 void matrix_scan_kb(void);
225 225
 void matrix_init_user(void);
226 226
 void matrix_scan_user(void);
227
+uint16_t get_record_keycode(keyrecord_t *record);
228
+uint16_t get_event_keycode(keyevent_t event);
227 229
 bool process_action_kb(keyrecord_t *record);
228 230
 bool process_record_kb(uint16_t keycode, keyrecord_t *record);
229 231
 bool process_record_user(uint16_t keycode, keyrecord_t *record);

+ 17
- 3
tmk_core/common/action_tapping.c View File

@@ -18,8 +18,17 @@
18 18
 #define IS_TAPPING_PRESSED()    (IS_TAPPING() && tapping_key.event.pressed)
19 19
 #define IS_TAPPING_RELEASED()   (IS_TAPPING() && !tapping_key.event.pressed)
20 20
 #define IS_TAPPING_KEY(k)       (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
21
-#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
22 21
 
22
+__attribute__ ((weak))
23
+uint16_t get_tapping_term(uint16_t keycode) {
24
+  return TAPPING_TERM;
25
+}
26
+
27
+#ifdef TAPPING_TERM_PER_KEY
28
+#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_event_keycode(tapping_key.event)))
29
+#else
30
+#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
31
+#endif
23 32
 
24 33
 static keyrecord_t tapping_key = {};
25 34
 static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
@@ -100,12 +109,17 @@ bool process_tapping(keyrecord_t *keyp)
100 109
                     // enqueue
101 110
                     return false;
102 111
                 }
103
-#if TAPPING_TERM >= 500 || defined PERMISSIVE_HOLD
104 112
                 /* Process a key typed within TAPPING_TERM
105 113
                  * This can register the key before settlement of tapping,
106 114
                  * useful for long TAPPING_TERM but may prevent fast typing.
107 115
                  */
108
-                else if (IS_RELEASED(event) && waiting_buffer_typed(event)) {
116
+#if defined(TAPPING_TERM_PER_KEY) || (!defined(PER_KEY_TAPPING_TERM) && TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD)
117
+#ifdef TAPPING_TERM_PER_KEY
118
+                else if ( ( get_tapping_term(get_event_keycode(tapping_key.event)) >= 500) && IS_RELEASED(event) && waiting_buffer_typed(event))
119
+#else
120
+                else if ( IS_RELEASED(event) && waiting_buffer_typed(event))
121
+#endif
122
+                {
109 123
                     debug("Tapping: End. No tap. Interfered by typing key\n");
110 124
                     process_record(&tapping_key);
111 125
                     tapping_key = (keyrecord_t){};

+ 2
- 0
tmk_core/common/action_tapping.h View File

@@ -35,6 +35,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
35 35
 
36 36
 
37 37
 #ifndef NO_ACTION_TAPPING
38
+uint16_t get_event_keycode(keyevent_t event);
39
+uint16_t get_tapping_term(uint16_t keycode);
38 40
 void action_tapping_process(keyrecord_t record);
39 41
 #endif
40 42
 

Loading…
Cancel
Save