Skip to content

Commit

Permalink
Keymap introspection for combos. (qmk#19670)
Browse files Browse the repository at this point in the history
  • Loading branch information
tzarc authored May 15, 2023
1 parent 433dc60 commit 5faa23d
Show file tree
Hide file tree
Showing 226 changed files with 533 additions and 729 deletions.
4 changes: 4 additions & 0 deletions builddefs/build_test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ $(TEST)_SRC += \
tests/test_common/main.cpp \
$(QUANTUM_PATH)/logging/print.c

ifneq ($(strip $(INTROSPECTION_KEYMAP_C)),)
$(TEST)_DEFS += -DINTROSPECTION_KEYMAP_C=\"$(strip $(INTROSPECTION_KEYMAP_C))\"
endif

$(TEST_OBJ)/$(TEST)_SRC := $($(TEST)_SRC)
$(TEST_OBJ)/$(TEST)_INC := $($(TEST)_INC) $(VPATH) $(GTEST_INC)
$(TEST_OBJ)/$(TEST)_DEFS := $($(TEST)_DEFS)
Expand Down
4 changes: 2 additions & 2 deletions data/mappings/info_config.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
"DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.double_tap_shift_turns_on", "value_type": "bool"},

// Combos
"COMBO_COUNT": {"info_key": "combo.count", "value_type": "int"},
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},

// Dynamic Keymap
Expand Down Expand Up @@ -182,9 +181,10 @@
"TAPPING_FORCE_HOLD": {"info_key": "tapping.force_hold", "value_type": "bool", "deprecated": true},
"TAPPING_FORCE_HOLD_PER_KEY": {"info_key": "tapping.force_hold_per_key", "value_type": "bool", "deprecated": true},
"UNUSED_PINS": {"info_key": "_invalid.unused_pins", "deprecated": true},
"COMBO_COUNT": {"info_key": "_invalid.combo.count", "invalid": true},

// USB params, need to mark as failure when specified in config.h, rather than deprecated
"DEVICE_VER": {"info_key": "usb.device_version", "value_type": "bcd_version", "deprecated": true, "replace_with": "`usb.device_version` in info.json"}
"DEVICE_VER": {"info_key": "usb.device_version", "value_type": "bcd_version", "deprecated": true, "replace_with": "`usb.device_version` in info.json"},
"MANUFACTURER": {"info_key": "manufacturer", "value_type": "str", "deprecated": true, "replace_with": "`manufacturer` in info.json"},
"PRODUCT": {"info_key": "keyboard_name", "warn_duplicate": false, "value_type": "str", "deprecated": true, "replace_with": "`keyboard_name` in info.json"},
"PRODUCT_ID": {"info_key": "usb.pid", "value_type": "hex", "deprecated": true, "replace_with": "`usb.pid` in info.json"},
Expand Down
2 changes: 0 additions & 2 deletions docs/config_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,6 @@ If you define these options you will enable the associated feature, which may in
* how long before oneshot times out
* `#define ONESHOT_TAP_TOGGLE 2`
* how many taps before oneshot toggle is triggered
* `#define COMBO_COUNT 2`
* Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature. Or leave it undefined and programmatically set the count.
* `#define COMBO_TERM 200`
* how long for the Combo keys to be detected. Defaults to `TAPPING_TERM` if not defined.
* `#define COMBO_MUST_HOLD_MODS`
Expand Down
33 changes: 5 additions & 28 deletions docs/feature_combo.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,12 @@ The Combo feature is a chording type solution for adding custom actions. It lets

To enable this feature, you need to add `COMBO_ENABLE = yes` to your `rules.mk`.

Additionally, in your `config.h`, you'll need to specify the number of combos that you'll be using, by adding `#define COMBO_COUNT 1` (replacing 1 with the number that you're using). It is also possible to not define this and instead set the variable `COMBO_LEN` yourself. There's a trick where we don't need to think about this variable at all. More on this later.


Then, in your `keymap.c` file, you'll need to define a sequence of keys, terminated with `COMBO_END`, and a structure to list the combination of keys, and its resulting action.

```c
const uint16_t PROGMEM test_combo1[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM test_combo2[] = {KC_C, KC_D, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
COMBO(test_combo1, KC_ESC),
COMBO(test_combo2, LCTL(KC_Z)), // keycodes with modifiers are possible too!
};
Expand All @@ -33,25 +30,23 @@ It is possible to overlap combos. Before, with the example below both combos wou
```c
const uint16_t PROGMEM test_combo1[] = {LSFT_T(KC_A), LT(1, KC_B), COMBO_END};
const uint16_t PROGMEM test_combo2[] = {LSFT_T(KC_A), LT(1, KC_B), KC_C, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
COMBO(test_combo1, KC_ESC)
COMBO(test_combo2, KC_TAB)
};
```

## Examples

A long list of combos can be defined in an `enum` list that ends with `COMBO_LENGTH` and you can leave `COMBO_COUNT` undefined:
A long list of combos can be defined in an `enum` list:

```c
enum combos {
AB_ESC,
JK_TAB,
QW_SFT,
SD_LAYER,
COMBO_LENGTH
SD_LAYER
};
uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead!

const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};
Expand All @@ -72,9 +67,7 @@ For a more complicated implementation, you can use the `process_combo_event` fun
enum combo_events {
EM_EMAIL,
BSPC_LSFT_CLEAR,
COMBO_LENGTH
};
uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead!

const uint16_t PROGMEM email_combo[] = {KC_E, KC_M, COMBO_END};
const uint16_t PROGMEM clear_line_combo[] = {KC_BSPC, KC_LSFT, COMBO_END};
Expand Down Expand Up @@ -259,18 +252,6 @@ bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode
}
```
### Variable Length Combos
If you leave `COMBO_COUNT` undefined in `config.h`, it allows you to programmatically declare the size of the Combo data structure and avoid updating `COMBO_COUNT`. Instead a variable called `COMBO_LEN` has to be set. It can be set with something similar to the following in `keymap.c`: `uint16_t COMBO_LEN = ARRAY_SIZE(key_combos);` or by adding `COMBO_LENGTH` as the *last* entry in the combo enum and then `uint16_t COMBO_LEN = COMBO_LENGTH;` as such:
```c
enum myCombos {
...,
COMBO_LENGTH
};
uint16_t COMBO_LEN = COMBO_LENGTH;
```
Regardless of the method used to declare `COMBO_LEN`, this also requires to convert the `combo_t key_combos[COMBO_COUNT] = {...};` line to `combo_t key_combos[] = {...};`.


### Combo timer
Normally, the timer is started on the first key press and then reset on every subsequent key press within the `COMBO_TERM`.
Expand Down Expand Up @@ -300,10 +281,8 @@ Here's an example where a combo resolves to two modifiers, and on key releases t
```c
enum combos {
AB_MODS,
COMBO_LENGTH
AB_MODS
};
uint16_t COMBO_LEN = COMBO_LENGTH;
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
Expand Down Expand Up @@ -415,6 +394,4 @@ SUBS(TH_THE, "the", KC_T, KC_H) // SUBS uses SEND_STRING to output the give
...
```
Now, you can update only one place to add or alter combos. You don't even need to remember to update the `COMBO_COUNT` or the `COMBO_LEN` variables at all. Everything is taken care of. Magic!

For small to huge ready made dictionaries of combos, you can check out http://combos.gboards.ca/.
2 changes: 0 additions & 2 deletions docs/ja/config_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* ワンショットがタイムアウトするまでの時間
* `#define ONESHOT_TAP_TOGGLE 2`
* ワンショットトグルが引き起こされるまでのタップ数
* `#define COMBO_COUNT 2`
* [コンボ](ja/feature_combo.md)機能で使っているコンボの数にこれを設定します。
* `#define COMBO_TERM 200`
* コンボキーが検出されるまでの時間。定義されていない場合は、デフォルトは `TAPPING_TERM` です。
* `#define TAP_CODE_DELAY 100`
Expand Down
6 changes: 3 additions & 3 deletions docs/ja/feature_combo.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

```c
const uint16_t PROGMEM test_combo[] = {KC_A, KC_B, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {COMBO(test_combo, KC_ESC)};
combo_t key_combos[] = {COMBO(test_combo, KC_ESC)};
```
これは、A と B のキーを押した場合に、"Escape" を送信します。
Expand All @@ -38,7 +38,7 @@ enum combos {
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[AB_ESC] = COMBO(ab_combo, KC_ESC),
[JK_TAB] = COMBO(jk_combo, KC_TAB)
};
Expand All @@ -55,7 +55,7 @@ enum combo_events {
const uint16_t PROGMEM copy_combo[] = {KC_Z, KC_C, COMBO_END};
const uint16_t PROGMEM paste_combo[] = {KC_X, KC_V, COMBO_END};

combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[ZC_COPY] = COMBO_ACTION(copy_combo),
[XV_PASTE] = COMBO_ACTION(paste_combo),
};
Expand Down
1 change: 0 additions & 1 deletion keyboards/0xcb/splaytoraid/keymaps/pi/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@


#ifdef COMBO_ENABLE
#define COMBO_COUNT 9
#define COMBO_TERM 20
#define COMBO_ONLY_FROM_LAYER 0
#endif
Expand Down
6 changes: 1 addition & 5 deletions keyboards/0xcb/splaytoraid/keymaps/pi/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const uint16_t PROGMEM ent_combo[] = {HM_K, HM_L, COMBO_END};
const uint16_t PROGMEM tab_combo[] = {HM_F, HM_D, COMBO_END};
const uint16_t PROGMEM esc_combo[] = {HM_D, HM_S, COMBO_END};

combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
COMBO(ae_combo, RALT(KC_Q)),
COMBO(ss_combo, RALT(KC_S)),
COMBO(ue_combo, RALT(KC_Y)),
Expand Down Expand Up @@ -298,7 +298,3 @@ const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_NUMBERS] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[_FUNCTION] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) }
};




4 changes: 1 addition & 3 deletions keyboards/3w6/keymaps/helltm/combos.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@
#define CB(name, action, ...) C_##name,
enum user_combos {
#include "combos.def"
COMBO_LENGTH
};
#undef CB
uint16_t COMBO_LEN = COMBO_LENGTH;

#define CB(name, action, ...) const uint16_t PROGMEM name##_combo[] = {__VA_ARGS__, COMBO_END};
#include "combos.def"
#undef CB

combo_t key_combos[COMBO_LENGTH] = {
combo_t key_combos[] = {
#define CB(name, action, ...) COMBO(name##_combo, action),
#include "combos.def"
#undef CB
Expand Down
2 changes: 0 additions & 2 deletions keyboards/40percentclub/gherkin/keymaps/stevexyz/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
// how long before oneshot times out
#define ONESHOT_TAP_TOGGLE 2
// how many taps before oneshot toggle is triggered
#define COMBO_COUNT 2
// Set this to the number of combos that you're using in the Combo feature.
#define COMBO_TERM 200
// how long for the Combo keys to be detected. Defaults to TAPPING_TERM if not defined.
#define TAP_CODE_DELAY 100
Expand Down
2 changes: 0 additions & 2 deletions keyboards/40percentclub/nori/keymaps/wings_36key/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,5 @@
#define RETRO_TAPPING_PER_KEY
#define TAPPING_TERM_PER_KEY

#define COMBO_COUNT 2 // number of combos used
#define COMBO_TERM 40 // time out for combos in ms
#define TAPPING_TERM 200 // time out for tap-hold in ms

4 changes: 2 additions & 2 deletions keyboards/40percentclub/nori/keymaps/wings_36key/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
)
};

combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
COMBO(df_tab, KC_TAB),
COMBO(jk_alt, KC_LALT),
};

layer_state_t layer_state_set_user(layer_state_t state) {
return update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST);
}
}

uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
Expand Down
1 change: 0 additions & 1 deletion keyboards/ashpil/modelm_usbc/keymaps/ashpil/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,4 @@


/* Add combos */
#define COMBO_COUNT 1
#define COMBO_TERM 200
4 changes: 2 additions & 2 deletions keyboards/ashpil/modelm_usbc/keymaps/ashpil/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ enum combo_events {

const uint16_t PROGMEM reset_combo[] = {KC_LCTL, KC_PAUS, COMBO_END};

combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[CTRL_PAUS_RESET] = COMBO_ACTION(reset_combo),
};

Expand All @@ -44,4 +44,4 @@ void process_combo_event(uint16_t combo_index, bool pressed) {
}
break;
}
}
}
2 changes: 0 additions & 2 deletions keyboards/b_sides/rev41lp/keymaps/namnlos/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#define BACKLIGHT_LIMIT_VAL 255
#define BACKLIGHT_DEFAULT_LEVEL 3

#define COMBO_COUNT 3

#define UNICODE_SELECTED_MODES UNICODE_MODE_WINCOMPOSE, UNICODE_MODE_WINDOWS, UNICODE_MODE_MACOS, UNICODE_MODE_LINUX

#define QUICK_TAP_TERM 0
Expand Down
2 changes: 1 addition & 1 deletion keyboards/b_sides/rev41lp/keymaps/namnlos/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const uint16_t PROGMEM copy_combo[] = {KC_Z, KC_C, COMBO_END};
const uint16_t PROGMEM paste_combo[] = {KC_X, KC_V, COMBO_END};
const uint16_t PROGMEM cut_combo[] = {KC_Z, KC_X, COMBO_END};

combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[ZC_COPY] = COMBO_ACTION(copy_combo),
[XV_PASTE] = COMBO_ACTION(paste_combo),
[ZX_CUT] = COMBO_ACTION(cut_combo),
Expand Down
1 change: 0 additions & 1 deletion keyboards/bluebell/swoop/keymaps/kyek/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@
*/
#pragma once
#define ONESHOT_TIMEOUT 1000
#define COMBO_COUNT 2
34 changes: 17 additions & 17 deletions keyboards/bluebell/swoop/keymaps/kyek/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ enum combos {
};
const uint16_t PROGMEM accent_combo[] = {KC_SPC, MO(_SYM1), COMBO_END};
const uint16_t PROGMEM settings_combo[] = {MO(_EXT), SFT_T(KC_SPC), COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[ACC] = COMBO(accent_combo, MO(_ACC)),
[SET] = COMBO(settings_combo, MO(_SET)),
};
Expand Down Expand Up @@ -78,37 +78,37 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_EXT] = LAYOUT_split_3x5_3(
KC_ESC, _______, _______, _______, _______, KC_PAGE_UP, KC_HOME, KC_UP, KC_END, KC_CAPS,
OS_ALT, OS_GUI, OS_SFT, OS_CTL, OS_RALT, KC_PAGE_DOWN, KC_LEFT, KC_DOWN, KC_RIGHT, KC_DELETE,
UNDO, CUT, COPY, KC_TAB, PASTE, DEL_WORD, KC_BSPC, _______, _______, _______,
UNDO, CUT, COPY, KC_TAB, PASTE, DEL_WORD, KC_BSPC, _______, _______, _______,
_______, _______, _______, KC_ENT, FNC, _______
),
[_FNC] = LAYOUT_split_3x5_3(
KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10,
OS_ALT, OS_GUI, OS_SFT, OS_CTL, OS_RALT, KC_F11, KC_F12, KC_PSCR, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10,
OS_ALT, OS_GUI, OS_SFT, OS_CTL, OS_RALT, KC_F11, KC_F12, KC_PSCR, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______
),
[_SYM2] = LAYOUT_split_3x5_3(
IT_CIRC, IT_UNDS, IT_PND, IT_EURO, IT_HASH, _______, _______, _______, _______, _______,
BACKTICK, TILDE, IT_BSLS, IT_PIPE, IT_AMPR, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
IT_CIRC, IT_UNDS, IT_PND, IT_EURO, IT_HASH, _______, _______, _______, _______, _______,
BACKTICK, TILDE, IT_BSLS, IT_PIPE, IT_AMPR, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______
),
[_ACC] = LAYOUT_split_3x5_3(
_______, _______, _______, CEGR, _______, _______, _______, _______, _______, _______,
IT_AGRV, IT_IGRV, IT_OGRV, IT_EGRV, IT_EACU, _______, _______, _______, _______, _______,
_______, _______, _______, IT_UGRV, _______, _______, _______, _______, _______, _______,
_______, _______, _______, CEGR, _______, _______, _______, _______, _______, _______,
IT_AGRV, IT_IGRV, IT_OGRV, IT_EGRV, IT_EACU, _______, _______, _______, _______, _______,
_______, _______, _______, IT_UGRV, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______
),
[_SET] = LAYOUT_split_3x5_3(
_______, _______, _______, RGB_RMOD, RGB_MOD, RGB_VAI, RGB_VAD, _______, _______, _______,
_______, _______, _______, RGB_M_B, RGB_M_P, RGB_HUI, RGB_HUD, _______, _______, _______,
QK_BOOT, _______, _______, RGB_M_R, RGB_TOG, RGB_SAI, RGB_SAD, _______, _______, QK_BOOT,
_______, _______, _______, RGB_RMOD, RGB_MOD, RGB_VAI, RGB_VAD, _______, _______, _______,
_______, _______, _______, RGB_M_B, RGB_M_P, RGB_HUI, RGB_HUD, _______, _______, _______,
QK_BOOT, _______, _______, RGB_M_R, RGB_TOG, RGB_SAI, RGB_SAD, _______, _______, QK_BOOT,
_______, _______, _______, _______, _______, _______
),
// [_TEMP] = LAYOUT_split_3x5_3(
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
// _______, _______, _______, _______, _______, _______
// ),
};
1 change: 0 additions & 1 deletion keyboards/centromere/keymaps/mini_bom/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#pragma once

#ifdef COMBO_ENABLE
# define COMBO_COUNT 10
# define COMBO_TERM 50
#endif

Expand Down
Loading

0 comments on commit 5faa23d

Please sign in to comment.