]> git.donarmstrong.com Git - qmk_firmware.git/commitdiff
Custom Tapping Term per key (#5009)
authorDrashna Jaelre <drashna@live.com>
Fri, 5 Apr 2019 19:47:25 +0000 (12:47 -0700)
committerJack Humbert <jack.humb@gmail.com>
Fri, 5 Apr 2019 19:47:25 +0000 (15:47 -0400)
* 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

docs/config_options.md
docs/custom_quantum_functions.md
quantum/quantum.c
quantum/quantum.h
tmk_core/common/action_tapping.c
tmk_core/common/action_tapping.h

index ad42e978020193f3cfa324bb1b111f18318f10c3..c5131a84145db89c9d177aa41ce97a0f2c565da2 100644 (file)
@@ -126,6 +126,8 @@ If you define these options you will enable the associated feature, which may in
 
 * `#define TAPPING_TERM 200`
   * 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
+* `#define TAPPING_TERM_PER_KEY`
+  * enables handling for per key `TAPPING_TERM` settings
 * `#define RETRO_TAPPING`
   * tap anyway, even after TAPPING_TERM, if there was no other key interruption between press and release
   * See [Retro Tapping](feature_advanced_keycodes.md#retro-tapping) for details
index 418faf349464633914f1b2788e9b9055d6b91c2d..6287b9530909e596d44095d6f0162d3774c15f7f 100644 (file)
@@ -323,6 +323,7 @@ uint32_t layer_state_set_user(uint32_t state) {
 * Keyboard/Revision: `uint32_t layer_state_set_kb(uint32_t state)`
 * Keymap: `uint32_t layer_state_set_user(uint32_t state)`
 
+
 The `state` is the bitmask of the active layers, as explained in the [Keymap Overview](keymap.md#keymap-layer-status)
 
 
@@ -460,3 +461,31 @@ And you're done.  The RGB layer indication will only work if you want it to. And
 * Keymap: `void eeconfig_init_user(void)`, `uint32_t eeconfig_read_user(void)` and `void eeconfig_update_user(uint32_t val)`
 
 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. 
+
+# Custom Tapping Term
+
+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`.
+
+To enable this functionality, you need to add `#define TAPPING_TERM_PER_KEY` to your `config.h`, first.  
+
+
+## Example `get_tapping_term` Implementation
+
+To change the `TAPPING TERM` based on the keycode, you'd want to add something like the following to your `keymap.c` file: 
+
+```c
+uint16_t get_tapping_term(uint16_t keycode) {
+  switch (keycode) {
+    case SFT_T(KC_SPC):
+      return TAPPING_TERM + 1250;
+    case LT(1, KC_GRV):
+      return 130;
+    default:
+      return TAPPING_TERM;
+  }
+}
+```
+
+### `get_tapping_term` Function Documentation
+
+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.
index 8c928441c5ae1ed6bcd5d3be4b2d46f2904f0406..48c338fc85c02bae4c2fb92fad2ba7c431504f89 100644 (file)
@@ -225,27 +225,39 @@ static uint16_t scs_timer[2] = {0, 0};
  */
 static bool grave_esc_was_shifted = false;
 
-bool process_record_quantum(keyrecord_t *record) {
+/* Convert record into usable keycode via the contained event. */
+uint16_t get_record_keycode(keyrecord_t *record) {
+  return get_event_keycode(record->event);
+}
 
-  /* This gets the keycode from the key pressed */
-  keypos_t key = record->event.key;
-  uint16_t keycode;
+
+/* Convert event into usable keycode. Checks the layer cache to ensure that it
+ * retains the correct keycode after a layer change, if the key is still pressed.
+ */
+uint16_t get_event_keycode(keyevent_t event) {
 
   #if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
     /* TODO: Use store_or_get_action() or a similar function. */
     if (!disable_action_cache) {
       uint8_t layer;
 
-      if (record->event.pressed) {
-        layer = layer_switch_get_layer(key);
-        update_source_layers_cache(key, layer);
+      if (event.pressed) {
+        layer = layer_switch_get_layer(event.key);
+        update_source_layers_cache(event.key, layer);
       } else {
-        layer = read_source_layers_cache(key);
+        layer = read_source_layers_cache(event.key);
       }
-      keycode = keymap_key_to_keycode(layer, key);
+      return keymap_key_to_keycode(layer, event.key);
     } else
   #endif
-    keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
+    return keymap_key_to_keycode(layer_switch_get_layer(event.key), event.key);
+}
+
+/* Main keycode processing function. Hands off handling to other functions,
+ * then processes internal Quantum keycodes, then processes ACTIONs.
+ */
+bool process_record_quantum(keyrecord_t *record) {
+    uint16_t keycode = get_record_keycode(record);
 
     // This is how you use actions here
     // if (keycode == KC_LEAD) {
index c12ac9ab8aff007c89080c120e73aa5c992ac49c..d0b2bedb1b1c732f3cb9231194452a913e9e955d 100644 (file)
@@ -224,6 +224,8 @@ void matrix_init_kb(void);
 void matrix_scan_kb(void);
 void matrix_init_user(void);
 void matrix_scan_user(void);
+uint16_t get_record_keycode(keyrecord_t *record);
+uint16_t get_event_keycode(keyevent_t event);
 bool process_action_kb(keyrecord_t *record);
 bool process_record_kb(uint16_t keycode, keyrecord_t *record);
 bool process_record_user(uint16_t keycode, keyrecord_t *record);
index 8adf013e16cad6a9b4dfccbe46fbabba890ea296..3b67ed152f798f47778824d674d4328385183976 100644 (file)
 #define IS_TAPPING_PRESSED()    (IS_TAPPING() && tapping_key.event.pressed)
 #define IS_TAPPING_RELEASED()   (IS_TAPPING() && !tapping_key.event.pressed)
 #define IS_TAPPING_KEY(k)       (IS_TAPPING() && KEYEQ(tapping_key.event.key, (k)))
-#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
 
+__attribute__ ((weak))
+uint16_t get_tapping_term(uint16_t keycode) {
+  return TAPPING_TERM;
+}
+
+#ifdef TAPPING_TERM_PER_KEY
+#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < get_tapping_term(get_event_keycode(tapping_key.event)))
+#else
+#define WITHIN_TAPPING_TERM(e)  (TIMER_DIFF_16(e.time, tapping_key.event.time) < TAPPING_TERM)
+#endif
 
 static keyrecord_t tapping_key = {};
 static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};
@@ -100,12 +109,17 @@ bool process_tapping(keyrecord_t *keyp)
                     // enqueue
                     return false;
                 }
-#if TAPPING_TERM >= 500 || defined PERMISSIVE_HOLD
                 /* Process a key typed within TAPPING_TERM
                  * This can register the key before settlement of tapping,
                  * useful for long TAPPING_TERM but may prevent fast typing.
                  */
-                else if (IS_RELEASED(event) && waiting_buffer_typed(event)) {
+#if defined(TAPPING_TERM_PER_KEY) || (!defined(PER_KEY_TAPPING_TERM) && TAPPING_TERM >= 500) || defined(PERMISSIVE_HOLD)
+#ifdef TAPPING_TERM_PER_KEY
+                else if ( ( get_tapping_term(get_event_keycode(tapping_key.event)) >= 500) && IS_RELEASED(event) && waiting_buffer_typed(event))
+#else
+                else if ( IS_RELEASED(event) && waiting_buffer_typed(event))
+#endif
+                {
                     debug("Tapping: End. No tap. Interfered by typing key\n");
                     process_record(&tapping_key);
                     tapping_key = (keyrecord_t){};
index 2f143ae8b82d8e22720ba766e313023f831d4b21..1db43a442e33cd98a2e266419866563cf0875701 100644 (file)
@@ -35,6 +35,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 
 #ifndef NO_ACTION_TAPPING
+uint16_t get_event_keycode(keyevent_t event);
+uint16_t get_tapping_term(uint16_t keycode);
 void action_tapping_process(keyrecord_t record);
 #endif