From cfb9364617af9ffe1cc3ddb4d67b848f55201c30 Mon Sep 17 00:00:00 2001 From: oberien Date: Sun, 8 Mar 2020 18:06:53 +0100 Subject: [PATCH 1/4] compose onboard: first version --- common_features.mk | 5 ++ .../process_keycode/process_compose_onboard.c | 63 +++++++++++++++++++ .../process_keycode/process_compose_onboard.h | 53 ++++++++++++++++ quantum/quantum.c | 3 + quantum/quantum.h | 4 ++ quantum/quantum_keycodes.h | 5 ++ 6 files changed, 133 insertions(+) create mode 100644 quantum/process_keycode/process_compose_onboard.c create mode 100644 quantum/process_keycode/process_compose_onboard.h diff --git a/common_features.mk b/common_features.mk index 50b1127dc60d..c4dc537501c9 100644 --- a/common_features.mk +++ b/common_features.mk @@ -509,6 +509,11 @@ ifeq ($(strip $(LEADER_ENABLE)), yes) OPT_DEFS += -DLEADER_ENABLE endif +ifeq ($(strip $(COMPOSE_ONBOARD_ENABLE)), yes) + SRC += $(QUANTUM_DIR)/process_keycode/process_compose_onboard.c + OPT_DEFS += -DCOMPOSE_ONBOARD_ENABLE +endif + ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes) SRC += $(QUANTUM_DIR)/process_keycode/process_auto_shift.c OPT_DEFS += -DAUTO_SHIFT_ENABLE diff --git a/quantum/process_keycode/process_compose_onboard.c b/quantum/process_keycode/process_compose_onboard.c new file mode 100644 index 000000000000..32b9ab060acf --- /dev/null +++ b/quantum/process_keycode/process_compose_onboard.c @@ -0,0 +1,63 @@ +#include "process_compose_onboard.h" + +__attribute__((weak)) bool compose_onboard_mapping(uint16_t* sequence, uint8_t len) { + return false; +} + +static bool composing_onboard = false; +static uint16_t compose_onboard_sequence[COMPOSE_ONBOARD_LEN] = {0, 0, 0, 0, 0}; +static uint8_t compose_onboard_len = 0; + +void compose_onboard_start() { + composing_onboard = true; + compose_onboard_sequence = {0}; + compose_onboard_len = 0; +} +void compose_onboard_stop() { + composing_onboard = false; +} + +bool process_compose_onboard(uint16_t keycode, keyrecord_t* record) { + if (!composing_onboard && keycode == KC_COMPOSE_ONBOARD && record->event.pressed) { + compose_onboard_start(); + return false; + } + if (!composing_onboard || !record->event.pressed) { + return true; + } + // we are composing and a non-layer-modifying key was pressed + if (keycode == COMPOSE_ONBOARD_ABORT) { + composing_onboard = false; + return false; + } + + + // this shouldn't happen, but check it for safety reasons + if (compose_onboard_len >= COMPOSE_ONBOARD_LEN) { + compose_onboard_stop(); + } + + compose_onboard_sequence[compose_onboard_len] = keycode; + compose_onboard_len += 1; + if (!compose_onboard_mapping(compose_onboard_sequence, compose_onboard_len)) { + compose_onboard_stop(); + } + + // Leader key set-up +# ifndef LEADER_KEY_STRICT_KEY_PROCESSING + if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) { + keycode = keycode & 0xFF; + } +# endif // LEADER_KEY_STRICT_KEY_PROCESSING + return false; +} + +size_t compose_onboard_memcmp_index(uint16_t* seq, uint16_t* input, size_t len) { + size_t i = 0; + for (; i < len; i++) { + if (seq[i] != input[i]) { + return i; + } + } + return i; +} diff --git a/quantum/process_keycode/process_compose_onboard.h b/quantum/process_keycode/process_compose_onboard.h new file mode 100644 index 000000000000..0fb297d4d2cc --- /dev/null +++ b/quantum/process_keycode/process_compose_onboard.h @@ -0,0 +1,53 @@ +#ifndef PROCESS_COMPOSE_ONBOARD_H +#define PROCESS_COMPOSE_ONBOARD_H + +#include "quantum.h" + +#ifndef COMPOSE_ONBOARD_ABORT +#define COMPOSE_ONBOARD_ABORT KC_SPC +#endif +#ifndef COMPOSE_ONBOARD_LEN +#define COMPOSE_ONBOARD_LEN 5 +#endif + +/// Compares the first `len` keycode (uint16_t) of the first two arguments +/// and returns the index at which they start to differ or `len` if they are equal. +size_t compose_onboard_memcmp_index(uint16_t* seq, uint16_t* input, size_t len); + +#define ARGLEN(...) (sizeof((uint16_t[]){__VA_ARGS__})/sizeof(uint16_t)) +#define ARRAYLEN(arr) (sizeof(arr)/sizeof(arr[0])) +#define min(a,b) ({ \ + __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; \ +}) + +#define COMPOSE_ONBOARD_DICTIONARY(...) \ + bool compose_onboard_mapping(uint16_t* sequence, uint8_t sequence_len) { \ + bool partial_match = false; \ + __VA_ARGS__ \ + } +#define COMPOSE_ONBOARD_MAPPING(INPUT, ACTION) {\ + uint16_t input[] = INPUT; \ + uint16_t actions[] = ACTION; \ + _Static_assert(ARRAYLEN(input) <= COMPOSE_ONBOARD_LEN, "Number of keys in Compose Onboard input keystroke is too long. Consider increasing COMPOSE_ONBOARD_LEN"); \ + size_t test_len = min(ARRAYLEN(input), sequence_len); \ + size_t match_index = compose_onboard_memcmp_index(sequence, input, test_len); \ + if (match_index != 0) { \ + partial_match = true; \ + } \ + if (sequence_len == ARRAYLEN(input) && match_index == test_len) { \ + for (int i = 0; i < ARRAYLEN(actions); i++) { \ + register_code16(actions[i]); \ + unregister_code16(actions[i]); \ + } \ + return false; \ + } \ + return partial_match; \ +} +#define COMPOSE_ONBOARD_INPUT(...) \ + {__VA_ARGS__} +#define COMPOSE_ONBOARD_ACTION(...) \ + {__VA_ARGS__} + +#endif diff --git a/quantum/quantum.c b/quantum/quantum.c index 2053a1a5f479..c88ee4443ace 100644 --- a/quantum/quantum.c +++ b/quantum/quantum.c @@ -257,6 +257,9 @@ bool process_record_quantum(keyrecord_t *record) { #ifdef LEADER_ENABLE process_leader(keycode, record) && #endif +#ifdef COMPOSE_ONBOARD_ENABLE + process_compose_onboard(keycode, record) && +#endif #ifdef COMBO_ENABLE process_combo(keycode, record) && #endif diff --git a/quantum/quantum.h b/quantum/quantum.h index 45f44f49a1a7..42afbf768392 100644 --- a/quantum/quantum.h +++ b/quantum/quantum.h @@ -96,6 +96,10 @@ extern layer_state_t layer_state; # include "process_leader.h" #endif +#ifdef COMPOSE_ONBOARD_ENABLE +# include "process_compose_onboard.h" +#endif + #ifdef UNICODE_ENABLE # include "process_unicode.h" #endif diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h index 0958c4f4eb00..b5f55c1e8c9d 100644 --- a/quantum/quantum_keycodes.h +++ b/quantum/quantum_keycodes.h @@ -123,6 +123,11 @@ enum quantum_keycodes { KC_LEAD, #endif +#ifdef COMPOSE_ONBOARD_ENABLE + KC_COMPOSE_ONBOARD, + KC_COMPOB = KC_COMPOSE_ONBOARD, +#endif + // Auto Shift setup KC_ASUP, KC_ASDN, From 0e69bb22243f56f41e940b7c0fb99018d25233fd Mon Sep 17 00:00:00 2001 From: oberien Date: Mon, 9 Mar 2020 16:38:42 +0100 Subject: [PATCH 2/4] Compose Onboard: fix bugs and reduce binary size somewhat --- .../process_keycode/process_compose_onboard.c | 49 +++++++++++++------ .../process_keycode/process_compose_onboard.h | 36 ++++++++------ 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/quantum/process_keycode/process_compose_onboard.c b/quantum/process_keycode/process_compose_onboard.c index 32b9ab060acf..047abe8a9636 100644 --- a/quantum/process_keycode/process_compose_onboard.c +++ b/quantum/process_keycode/process_compose_onboard.c @@ -3,52 +3,62 @@ __attribute__((weak)) bool compose_onboard_mapping(uint16_t* sequence, uint8_t len) { return false; } +__attribute__((weak)) void compose_onboard_start(void) {} +__attribute__((weak)) void compose_onboard_end(void) {} static bool composing_onboard = false; static uint16_t compose_onboard_sequence[COMPOSE_ONBOARD_LEN] = {0, 0, 0, 0, 0}; static uint8_t compose_onboard_len = 0; -void compose_onboard_start() { +void qk_compose_onboard_start(void) { composing_onboard = true; - compose_onboard_sequence = {0}; + memset(compose_onboard_sequence, 0, COMPOSE_ONBOARD_LEN * sizeof(uint16_t)); compose_onboard_len = 0; + compose_onboard_start(); } -void compose_onboard_stop() { +void qk_compose_onboard_end(void) { composing_onboard = false; + compose_onboard_end(); } bool process_compose_onboard(uint16_t keycode, keyrecord_t* record) { if (!composing_onboard && keycode == KC_COMPOSE_ONBOARD && record->event.pressed) { - compose_onboard_start(); + qk_compose_onboard_start(); return false; } if (!composing_onboard || !record->event.pressed) { return true; } + // ignore MOD-keys and layer modifiers + if ( + // ignore (L/R)-CTRL, ALT, GUI, Shift + IS_MOD(keycode) + // ignore any layer modifiers + || (QK_LAYER_TAP <= keycode && keycode <= QK_ONE_SHOT_MOD_MAX) + || (QK_LAYER_TAP_TOGGLE <= keycode && keycode <= QK_LAYER_MOD_MAX) + || (QK_MOD_TAP <= keycode && keycode <= QK_MOD_TAP_MAX) + ) { + return true; + } + // we are composing and a non-layer-modifying key was pressed + if (keycode == COMPOSE_ONBOARD_ABORT) { - composing_onboard = false; + qk_compose_onboard_end(); return false; } - // this shouldn't happen, but check it for safety reasons if (compose_onboard_len >= COMPOSE_ONBOARD_LEN) { - compose_onboard_stop(); + qk_compose_onboard_end(); } compose_onboard_sequence[compose_onboard_len] = keycode; compose_onboard_len += 1; if (!compose_onboard_mapping(compose_onboard_sequence, compose_onboard_len)) { - compose_onboard_stop(); + qk_compose_onboard_end(); } - // Leader key set-up -# ifndef LEADER_KEY_STRICT_KEY_PROCESSING - if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) { - keycode = keycode & 0xFF; - } -# endif // LEADER_KEY_STRICT_KEY_PROCESSING return false; } @@ -61,3 +71,14 @@ size_t compose_onboard_memcmp_index(uint16_t* seq, uint16_t* input, size_t len) } return i; } +int compose_onboard_compare_input(uint16_t* input, uint8_t input_len, uint16_t* seq, uint8_t seq_len) { + size_t test_len = min(input_len, seq_len); + size_t match_index = compose_onboard_memcmp_index(seq, input, test_len); + if (seq_len == input_len && match_index == test_len) { + return -1; + } + if (match_index == seq_len) { + return 1; + } + return 0; +} diff --git a/quantum/process_keycode/process_compose_onboard.h b/quantum/process_keycode/process_compose_onboard.h index 0fb297d4d2cc..4e7f7bc5ab1c 100644 --- a/quantum/process_keycode/process_compose_onboard.h +++ b/quantum/process_keycode/process_compose_onboard.h @@ -4,15 +4,24 @@ #include "quantum.h" #ifndef COMPOSE_ONBOARD_ABORT -#define COMPOSE_ONBOARD_ABORT KC_SPC +#define COMPOSE_ONBOARD_ABORT KC_COMPOSE_ONBOARD #endif #ifndef COMPOSE_ONBOARD_LEN #define COMPOSE_ONBOARD_LEN 5 #endif +bool process_compose_onboard(uint16_t keycode, keyrecord_t* record); +bool compose_onboard_mapping(uint16_t* sequence, uint8_t len); +void compose_onboard_start(void); +void compose_onboard_end(void); + /// Compares the first `len` keycode (uint16_t) of the first two arguments /// and returns the index at which they start to differ or `len` if they are equal. size_t compose_onboard_memcmp_index(uint16_t* seq, uint16_t* input, size_t len); +/// Compares the compose mapping input to the sequence so far. +/// Returns -1 on a full match, 0 on no match, and 1 on a partial match. +/// This is done to reduce the binary size compared to inlining it everywhere +int compose_onboard_compare_input(uint16_t* input, uint8_t input_len, uint16_t* seq, uint8_t seq_len); #define ARGLEN(...) (sizeof((uint16_t[]){__VA_ARGS__})/sizeof(uint16_t)) #define ARRAYLEN(arr) (sizeof(arr)/sizeof(arr[0])) @@ -26,28 +35,25 @@ size_t compose_onboard_memcmp_index(uint16_t* seq, uint16_t* input, size_t len); bool compose_onboard_mapping(uint16_t* sequence, uint8_t sequence_len) { \ bool partial_match = false; \ __VA_ARGS__ \ + return partial_match; \ } #define COMPOSE_ONBOARD_MAPPING(INPUT, ACTION) {\ uint16_t input[] = INPUT; \ - uint16_t actions[] = ACTION; \ _Static_assert(ARRAYLEN(input) <= COMPOSE_ONBOARD_LEN, "Number of keys in Compose Onboard input keystroke is too long. Consider increasing COMPOSE_ONBOARD_LEN"); \ - size_t test_len = min(ARRAYLEN(input), sequence_len); \ - size_t match_index = compose_onboard_memcmp_index(sequence, input, test_len); \ - if (match_index != 0) { \ - partial_match = true; \ - } \ - if (sequence_len == ARRAYLEN(input) && match_index == test_len) { \ - for (int i = 0; i < ARRAYLEN(actions); i++) { \ - register_code16(actions[i]); \ - unregister_code16(actions[i]); \ - } \ + uint8_t input_len = ARRAYLEN(input); \ + int res = compose_onboard_compare_input(input, input_len, sequence, sequence_len); \ + if (res == -1) { \ + ACTION \ return false; \ } \ - return partial_match; \ + partial_match |= res; \ } #define COMPOSE_ONBOARD_INPUT(...) \ {__VA_ARGS__} #define COMPOSE_ONBOARD_ACTION(...) \ - {__VA_ARGS__} - + uint16_t actions[] = {__VA_ARGS__}; \ + for (int i = 0; i < ARRAYLEN(actions); i++) { \ + register_code16(actions[i]); \ + unregister_code16(actions[i]); \ + } #endif From 6276b6d6c2a73bc6d73922ddf3a9fb975bbb4da4 Mon Sep 17 00:00:00 2001 From: oberien Date: Mon, 9 Mar 2020 18:15:19 +0100 Subject: [PATCH 3/4] Compose Onboard Documentation --- docs/_summary.md | 1 + docs/config_options.md | 7 ++ docs/de/_summary.md | 1 + docs/es/_summary.md | 1 + docs/feature_compose_onboard.md | 170 ++++++++++++++++++++++++++++++++ docs/fr-fr/_summary.md | 1 + docs/he-il/_summary.md | 1 + docs/ja/_summary.md | 1 + docs/keycodes.md | 8 ++ docs/pt-br/_summary.md | 1 + docs/reference_glossary.md | 5 + docs/ru-ru/_summary.md | 1 + docs/understanding_qmk.md | 1 + docs/zh-cn/_summary.md | 1 + show_options.mk | 1 + 15 files changed, 201 insertions(+) create mode 100644 docs/feature_compose_onboard.md diff --git a/docs/_summary.md b/docs/_summary.md index 842422665e4e..02902f8d7e27 100644 --- a/docs/_summary.md +++ b/docs/_summary.md @@ -61,6 +61,7 @@ * [Dynamic Macros](feature_dynamic_macros.md) * [Grave Escape](feature_grave_esc.md) * [Leader Key](feature_leader_key.md) + * [Compose Onboard](feature_compose_onboard.md) * [Mod-Tap](mod_tap.md) * [Macros](feature_macros.md) * [Mouse Keys](feature_mouse_keys.md) diff --git a/docs/config_options.md b/docs/config_options.md index 16fea83a3312..ecee3329b587 100644 --- a/docs/config_options.md +++ b/docs/config_options.md @@ -162,6 +162,11 @@ If you define these options you will enable the associated feature, which may in * sets the timer for leader key chords to run on each key press rather than overall * `#define LEADER_KEY_STRICT_KEY_PROCESSING` * Disables keycode filtering for Mod-Tap and Layer-Tap keycodes. Eg, if you enable this, you would need to specify `MT(MOD_CTL, KC_A)` if you want to use `KC_A`. +* `#define COMPOSE_ONBOARD_ABORT KC_COMPOSE_ONBOARD` + * which key to use to abort the current composing sequence (defaults to `KC_COMPOSE_ONBOARD`) +* `#define COMPOSE_ONBOARD_LEN 5` + * how many keys should be recorded at maximum in the composing sequence (defaults to `5`) + * should be equal to the largest configured input sequence in the compose dictionary * `#define ONESHOT_TIMEOUT 300` * how long before oneshot times out * `#define ONESHOT_TAP_TOGGLE 2` @@ -361,6 +366,8 @@ Use these to enable or disable building certain features. The more you have enab * Enable keyboard underlight functionality * `LEADER_ENABLE` * Enable leader key chording +* `COMPOSE_ONBOARD_ENABLE` + * Enable composing onboard directly on the keyboard * `MIDI_ENABLE` * MIDI controls * `UNICODE_ENABLE` diff --git a/docs/de/_summary.md b/docs/de/_summary.md index 19c75ecd38f5..f0288d8943e7 100644 --- a/docs/de/_summary.md +++ b/docs/de/_summary.md @@ -73,6 +73,7 @@ * [Key Lock](de/feature_key_lock.md) * [Layouts](de/feature_layouts.md) * [Leader Key](de/feature_leader_key.md) + * [Compose Onboard](de/feature_compose_onboard.md) * [LED Matrix](de/feature_led_matrix.md) * [Macros](de/feature_macros.md) * [Mouse Keys](de/feature_mouse_keys.md) diff --git a/docs/es/_summary.md b/docs/es/_summary.md index b58d825f746e..d5e0ba8e18dc 100644 --- a/docs/es/_summary.md +++ b/docs/es/_summary.md @@ -73,6 +73,7 @@ * [Key Lock](es/feature_key_lock.md) * [Layouts](es/feature_layouts.md) * [Tecla Leader](es/feature_leader_key.md) + * [Compose Onboard](es/feature_compose_onboard.md) * [Matriz LED](es/feature_led_matrix.md) * [Macros](es/feature_macros.md) * [Teclas del ratón](es/feature_mouse_keys.md) diff --git a/docs/feature_compose_onboard.md b/docs/feature_compose_onboard.md new file mode 100644 index 000000000000..8c84b8e2dbd5 --- /dev/null +++ b/docs/feature_compose_onboard.md @@ -0,0 +1,170 @@ +# Compose Onboard + +You may already know the concept of composing from linux, sometimes also called multi key. Composing allows to map a sequence of keystrokes to press different keys, insert a character, or perform any preconfigured action. For example this is often used to write foreign or unicode characters. This features allows you to define such mappings directly on the keyboard. For example, you can create a mapping to write the character `→` by tapping `-` followed by `>` after pressing the compose key. + +This is similar to how the [Leader Key](feature_leader_key.md) works. However, while the Leader Key is time-based, compose doesn't have any time constraints. + +To use this feature, set one of your keys to `KC_COMPOSE_ONBOARD`, which you can then use to start a compose sequence. Also don't forget to enable the compose onboard feature as described in "Adding Compose Onboard Support in the `rules.mk`". + +Imagine the example mapping from above (`-` `>` → `→`). After pressing `KC_COMPOSE_ONBOARD` any key press will be captured (i.e. not written on the computer). We can now type `-` and `>`, which will result in the character `→` being sent to the computer instead. Composing stops by finishing a sequence (e.g. `-` `>`), typing a key for which no further mapping matches (`f`, or `-` `a`), or by pressing the abort key (which defaults to the compose key itself). In those cases no output will be generated. + + +```c +COMPOSE_ONBOARD_DICTIONARY( + // quantum keyboard + COMPOSE_ONBOARD_MAPPING( + COMPOSE_ONBOARD_INPUT(KC_Q, KC_M, KC_K), + COMPOSE_ONBOARD_ACTION( + KC_Q, KC_U, KC_A, KC_N, KC_T, KC_U, KC_M, + KC_SPC, KC_K, KC_E, KC_Y, KC_B, KC_O, KC_A, KC_R, KC_D + ) + ) + // → + COMPOSE_ONBOARD_MAPPING( + COMPOSE_ONBOARD_INPUT(KC_MINS, KC_GT), + { + unicode_input_start(); + register_hex(0x2192); + unicode_input_finish(); + } + ) + // shrug + COMPOSE_ONBOARD_MAPPING( + COMPOSE_ONBOARD_INPUT(KC_S, KC_H, KC_R, KC_U, KC_G), + { + unicode_input_start(); + register_hex(0xaf); + register_hex(0x5c); + register_hex(0x5f); + register_hex(0x28); + register_hex(0x30c4); + register_hex(0x29); + register_hex(0x5f); + register_hex(0x2f); + register_hex(0xaf); + unicode_input_finish(); + } + ) +) +``` + +* `COMPOSE_ONBOARD_DICTIONARY` starts the list of all mappings +* `COMPOSE_ONBOARD_MAPPING` defines a mapping from an input key sequence to an action + * the first argument is the input key sequence + * the second argument is the action +* `COMPOSE_ONBOARD_INPUT` is used to define the key sequence needed to be typed to trigger the action +* `COMPOSE_ONBOARD_ACTION` can be used to define a key sequence to be typed if the input sequence has been typed + +The action can also be a code block containing any C code. This can be used like in the above example to write a unicode character, or to run any arbitrary code similar to a predefined macro. + +## Adding Compose Onboard Support in the `rules.mk` + +To add support for Compose Onboard you simply need to add a single line to your keymap's `rules.mk`: + +```make +COMPOSE_ONBOARD_ENABLE = yes +``` + +## Configuring the Abort Key + +The abort key can be used while in the middle of a sequence to abort composing. It defaults to the compose key itself. If you press the compose key to start a compose sequence, but want to abort halfway through, you can press the compose key (i.e. the configured abort key). (Or you could just continue with a key which doesn't have any mapping.) + +```c +#define COMPOSE_ONBOARD_ABORT KC_COMPOSE_ONBOARD +``` + +## Configuring the Maximum Input Length + +While performing a compose sequence, the pressed keys are recorded. The maximum number of keys recorded should match the longest input of any compose mapping (but can be larger). By default, the number of recorded keys is configured to be `5`. However, if you want to have an input sequence longer than that, you need to adjust that number. + +```c +#define COMPOSE_ONBOARD_LEN 5 +``` + +Notice that compilation will fail with "Number of keys in Compose Onboard input keystroke is too long. Consider increasing COMPOSE_ONBOARD_LEN" if you define an input which is longer than the configured `COMPOSE_ONBOARD_LEN`. + +## Customization - Hooks + +There are some functions which you can define, which will be called during composing. + +* `void compose_onboard_start(void)` is called when the compose key is pressed and can for example be used to light up an LED to indicate that you are within a compose sequence. +* `void compose_onboard_end(void)` is called when composing is done, either by having been aborted or finished successfully. It can for example be used to turn off the composing LED again. + +## Customization - Custom Dictionary + +The macros used above to define the dictionary define a function, which is called for the mapping procedure. For fine-grained control, you can manually define that function instead of using the macros. + +The mapping function has the signature `bool compose_onboard_mapping(uint16_t* sequence, uint8_t len)`. That function is called whenever a new key is pressed, after it has been added to the sequence array. + +* `uint16_t* sequence`: a pointer to an array of recorded keys like `KC_MINS` +* `uint8_t len`: current length of that array + + +To get a feeling for that function, this is an example of the macros and their resulting function definition. + +```c +COMPOSE_ONBOARD_DICTIONARY( + // quantum keyboard + COMPOSE_ONBOARD_MAPPING( + COMPOSE_ONBOARD_INPUT(KC_Q, KC_M, KC_K), + COMPOSE_ONBOARD_ACTION( + KC_Q, KC_U, KC_A, KC_N, KC_T, KC_U, KC_M, + KC_SPC, KC_K, KC_E, KC_Y, KC_B, KC_O, KC_A, KC_R, KC_D + ) + ) + // → + COMPOSE_ONBOARD_MAPPING( + COMPOSE_ONBOARD_INPUT(KC_MINS, KC_GT), + { + unicode_input_start(); + register_hex(0x2192); + unicode_input_finish(); + } + ) +) +``` + +The above macros get converted to the following code. + +```c +bool compose_onboard_mapping(uint16_t* sequence, uint8_t sequence_len) { + bool partial_match = false; + { + uint16_t input[] = {KC_Q, KC_M, KC_K}; + _Static_assert((sizeof(input) / sizeof(input[0])) <= COMPOSE_ONBOARD_LEN, "Number of keys in Compose Onboard input keystroke is too long. Consider increasing COMPOSE_ONBOARD_LEN"); + uint8_t input_len = (sizeof(input) / sizeof(input[0])); + int res = compose_onboard_compare_input(input, input_len, sequence, sequence_len); + if (res == -1) { + uint16_t actions[] = { + KC_Q, KC_U, KC_A, KC_N, KC_T, KC_U, KC_M, + KC_SPC, KC_K, KC_E, KC_Y, KC_B, KC_O, KC_A, KC_R, KC_D + }; + for (int i = 0; i < (sizeof(actions) / sizeof(actions[0])); i++) { + register_code16(actions[i]); + unregister_code16(actions[i]); + } + return false; + } + partial_match |= res; + } + { + uint16_t input[] = {KC_MINS, KC_GT}; + _Static_assert((sizeof(input) / sizeof(input[0])) <= 5, "Number of keys in Compose Onboard input keystroke is too long. Consider increasing COMPOSE_ONBOARD_LEN"); + uint8_t input_len = (sizeof(input) / sizeof(input[0])); + int res = compose_onboard_compare_input(input, input_len, sequence, sequence_len); + if (res == -1) { + { + unicode_input_start(); + register_hex(0x2192); + unicode_input_finish(); + } +return false; + } + partial_match |= res; + } + return partial_match; +} +``` + +That code uses the helper function `int compose_onboard_compare_input(uint16_t* input, uint8_t input_len, uint16_t* seq, uint8_t seq_len)`. That function compares the compose mapping input to the sequence so far. Its return values are counter-intuitive for binary size reasons. It returns -1 on a full match (the input matched completely and the action can be performed), 0 on no match (it's never possible in the current sequence to get this input), and 1 on a partial match (the recorded sequence so far matches the beginning of the mapping input, but the mapping input still has some keys left). + diff --git a/docs/fr-fr/_summary.md b/docs/fr-fr/_summary.md index 25a593b2ec2d..9152e35ae96d 100644 --- a/docs/fr-fr/_summary.md +++ b/docs/fr-fr/_summary.md @@ -77,6 +77,7 @@ * [Touche à verrou / Lock-key](fr-fr/feature_key_lock.md) * [Dispositions / layouts](fr-fr/feature_layouts.md) * [Touche leader](fr-fr/feature_leader_key.md) + * [Compose Onboard](fr-fr/feature_compose_onboard.md) * [Matrice LED](fr-fr/feature_led_matrix.md) * [Macros](fr-fr/feature_macros.md) * [Boutons de souris](fr-fr/feature_mouse_keys.md) diff --git a/docs/he-il/_summary.md b/docs/he-il/_summary.md index bdacd0d1fd29..dbe5189a5f68 100644 --- a/docs/he-il/_summary.md +++ b/docs/he-il/_summary.md @@ -89,6 +89,7 @@ * [Key Lock](he-il/feature_key_lock.md) * [Layouts](he-il/feature_layouts.md) * [Leader Key](he-il/feature_leader_key.md) + * [Compose Onboard](he-il/feature_compose_onboard.md) * [LED Matrix](he-il/feature_led_matrix.md) * [Macros](he-il/feature_macros.md) * [Mouse Keys](he-il/feature_mouse_keys.md) diff --git a/docs/ja/_summary.md b/docs/ja/_summary.md index e6423c6c26f5..489768acbacb 100644 --- a/docs/ja/_summary.md +++ b/docs/ja/_summary.md @@ -60,6 +60,7 @@ * [動的マクロ](ja/feature_dynamic_macros.md) * [グレイブ エスケープ](ja/feature_grave_esc.md) * [リーダーキー](ja/feature_leader_key.md) + * [Compose Onboard](ja/feature_compose_onboard.md) * [モッドタップ](ja/mod_tap.md) * [マクロ](ja/feature_macros.md) * [マウスキー](ja/feature_mouse_keys.md) diff --git a/docs/keycodes.md b/docs/keycodes.md index 18fd81118407..86521ddac96d 100644 --- a/docs/keycodes.md +++ b/docs/keycodes.md @@ -347,6 +347,14 @@ See also: [Leader Key](feature_leader_key.md) |---------|------------------------| |`KC_LEAD`|Begins a leader sequence| +## Compose Onboard :id=compose-onboard + +See also: [Compose Onboard](feature_compose_onboard.md) + +|Key |Aliases |Description | +|--------------------|-----------|-----------------------------------------| +|`KC_COMPOSE_ONBOARD`|`KC_COMPOB`|Begins Composing directly on the keyboard| + ## Mouse Keys :id=mouse-keys See also: [Mouse Keys](feature_mouse_keys.md) diff --git a/docs/pt-br/_summary.md b/docs/pt-br/_summary.md index 78b3b202163c..dbd80ce745be 100644 --- a/docs/pt-br/_summary.md +++ b/docs/pt-br/_summary.md @@ -73,6 +73,7 @@ * [Key Lock](pt-br/feature_key_lock.md) * [Layouts](pt-br/feature_layouts.md) * [Leader Key](pt-br/feature_leader_key.md) + * [Compose Onboard](pt-br/feature_compose_onboard.md) * [LED Matrix](pt-br/feature_led_matrix.md) * [Macros](pt-br/feature_macros.md) * [Mouse Keys](pt-br/feature_mouse_keys.md) diff --git a/docs/reference_glossary.md b/docs/reference_glossary.md index 4cdba024e469..c0ee07b8688e 100644 --- a/docs/reference_glossary.md +++ b/docs/reference_glossary.md @@ -78,6 +78,11 @@ A feature that allows you to tap the leader key followed by a sequence of 1, 2, * [Leader Key Documentation](feature_leader_key.md) +## Compose Onboard +Allows composing directly on the keyboard. After pressing the compose onboard key, the following keystrokes trigger a preconfigured action like pressing other keys, inserting a character, or any other quantum features. + +* [Compose Onboard Documentation](feature_compose_onboard.md) + ## LED Light Emitting Diode, the most common device used for indicators on a keyboard. diff --git a/docs/ru-ru/_summary.md b/docs/ru-ru/_summary.md index f893be3cfd1b..86d446dd4eba 100644 --- a/docs/ru-ru/_summary.md +++ b/docs/ru-ru/_summary.md @@ -74,6 +74,7 @@ * [Key Lock](ru-ru/feature_key_lock.md) * [Layouts](ru-ru/feature_layouts.md) * [Leader Key](ru-ru/feature_leader_key.md) + * [Compose Onboard](ru-ru/feature_compose_onboard.md) * [LED Matrix](ru-ru/feature_led_matrix.md) * [Macros](ru-ru/feature_macros.md) * [Mouse Keys](ru-ru/feature_mouse_keys.md) diff --git a/docs/understanding_qmk.md b/docs/understanding_qmk.md index 93964242582a..02072f19c96b 100644 --- a/docs/understanding_qmk.md +++ b/docs/understanding_qmk.md @@ -154,6 +154,7 @@ The `process_record()` function itself is deceptively simple, but hidden within * [`bool process_unicodemap(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_unicodemap.c#L46) * [`bool process_ucis(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_ucis.c#L95) * [`bool process_leader(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_leader.c#L51) + * [`bool process_compose_onboard(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/a0f2e292946c9a5535c70d9f2dfebb3055f1652a/quantum/process_keycode/process_compose_onboard.c#L24) * [`bool process_combo(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_combo.c#L115) * [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_printer.c#L77) * [`bool process_auto_shift(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_auto_shift.c#L94) diff --git a/docs/zh-cn/_summary.md b/docs/zh-cn/_summary.md index 201b83894d08..36070deca76f 100644 --- a/docs/zh-cn/_summary.md +++ b/docs/zh-cn/_summary.md @@ -78,6 +78,7 @@ * [自锁键](zh-cn/feature_key_lock.md) * [布局](zh-cn/feature_layouts.md) * [前导键](zh-cn/feature_leader_key.md) + * [Compose Onboard](zh-cn/feature_compose_onboard.md) * [LED阵列](zh-cn/feature_led_matrix.md) * [宏指令](zh-cn/feature_macros.md) * [鼠标键](zh-cn/feature_mouse_keys.md) diff --git a/show_options.mk b/show_options.mk index 3f3243fbd0be..914cefad48ab 100644 --- a/show_options.mk +++ b/show_options.mk @@ -45,6 +45,7 @@ OTHER_OPTION_NAMES = \ COMBO_ENABLE \ KEY_LOCK_ENABLE \ LEADER_ENABLE \ + COMPOSE_ONBOARD_ENABLE \ PRINTING_ENABLE \ STENO_ENABLE \ TAP_DANCE_ENABLE \ From 5d75f6d12a9c3364df043fae0fb836b227144e40 Mon Sep 17 00:00:00 2001 From: oberien Date: Mon, 9 Mar 2020 18:27:40 +0100 Subject: [PATCH 4/4] compose onboard: use pragma once instead of ifndef define --- quantum/process_keycode/process_compose_onboard.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/quantum/process_keycode/process_compose_onboard.h b/quantum/process_keycode/process_compose_onboard.h index 4e7f7bc5ab1c..2e37eae44f95 100644 --- a/quantum/process_keycode/process_compose_onboard.h +++ b/quantum/process_keycode/process_compose_onboard.h @@ -1,5 +1,4 @@ -#ifndef PROCESS_COMPOSE_ONBOARD_H -#define PROCESS_COMPOSE_ONBOARD_H +#pragma once #include "quantum.h" @@ -56,4 +55,3 @@ int compose_onboard_compare_input(uint16_t* input, uint8_t input_len, uint16_t* register_code16(actions[i]); \ unregister_code16(actions[i]); \ } -#endif