-
Notifications
You must be signed in to change notification settings - Fork 358
Using Parameterized Macros in Keymap Editor
If you aren't already familiar with macros in the context of ZMK, they are a behavior type that allows you to define a sequence of bindings to be triggered wherever that macro is bound. Typically this is to a key in one of your keymap's layers, but it can also be a combo, a behavior, or another macro.
Not too long ago support for parameterized macros landed in ZMK, so in addition to enabling a quick way to trigger a number of behaviors you can supply parameters to specific bindings in that sequence for added flexibility and reuse.
In another post I detailed a combination of parameterized macros and hold tap to implement autoshift functionality without repetition in your bindings or resorting to preprocessor macros. Now I want to demonstrate the advanced support in Keymap Editor for resolving parameter types, even in the context of a macro.
In the ZMK macro docs there is an example Layer + Underglow Color macro. It uses the ¯o_press
, ¯o_tap
, ¯o_pause_for_release
, and ¯o_release
binding activation modes to:
- "hold" a
&mo
(momentary layer) binding - "tap" a
&rgb_ug
(colour change) binding - pause as long as the macro is held,
- "release" the initial
&mo
binding - "tap" another
&rgb_ug
(presumably default colour) binding
By turning this into a parameterized macro, the same behavior can be used for any layer without having to create a duplicate.
In Keymap Editor load your keymap and go to the Macros tab. Add a new macro called &rgblayer
.
From here you can start adding control and key bindings to recreate the original macro:
Note: the macro sequence editor is drag-and-drop, so if you forget to add a binding in the correct spot you can always reorder them afterwards.
Now to make this generic, we'll include the appropriate control bindings to map macro parameters into the &mo
and &rgb_ug
bindings. Click the Add Control Binding and then change its behavior to ¯o_param_1to1
.
Note that as soon as this new binding is added to the end of the sequence you'll get a warning that there's no binding following it to receive the parameter. Drag the binding above the first &mo 1
and you'll see the warning disappear as well as the layer value.
The editor knows that ¯o_param_1to1
will cause the next non-control binding to receive the first parameter passed to the macro, in this case that binding is &mo
, so the given value is replaced with ??
(in the generated code this will become MACRO_PLACEHOLDER
).
Now you can add the rest:
-
¯o_param_2to2
before the first&rgb_ug
binding -
¯o_param_1to1
before the second&mo
binding
If you've loaded a keymap using the Clipboard integration, you can click the Keymap button and view macro source generated as something like the following:
rgblayer: rgb_layer {
compatible = "zmk,behavior-macro-two-param";
#binding-cells = <2>;
label = "MOMENTARY_LAYER_WITH_RGB_COLOR";
bindings
= <¯o_param_2to2 &rgb_ug RGB_COLOR_HSB_CMD MACRO_PLACEHOLDER ¯o_param_1to1>
, <¯o_press>
, <&mo MACRO_PLACEHOLDER>
, <¯o_pause_for_release>
, <¯o_release>
, <¯o_param_1to1 &mo MACRO_PLACEHOLDER>
, <¯o_tap>
, <&rgb_ug RGB_COLOR_HSB(0, 0, 0)>
;
};
There are a few things to note:
- The behavior type
zmk,behavior-macro-two-param
is selected for you, because you've indicated the use of two parameters. - The identifier
MACRO_PLACEHOLDER
is injected for you -- it's value doesn't matter, but it helps to make it clear what the purpose is. - Although you may be used to
&rgb_ug RGB_COLOR_HSB(...)
this is a preprocessor function that produces two values:RGB_COLOR_HSB_CMD
andRGB_COLOR_HSB_VAL(...)
. The Keymap Editor recognizes the relationship here, and splits the binding up once it's identified as receiving a macro parameter.
Anywhere you might like to momentarily activate a layer you can change that binding's &mo
behavior to &rgblayer
. In the binding editor you'll see something like the following:
The parameter type resolution support built into Keymap Editor recognizes that:
- the macro accepts two parameters,
- the
&mo
binding has a placeholder for its first parameter, a layer - the
rgb_ug
binding has a placeholder for its second parameter, and because its first parameter is already set asRGB_COLOR_HSB_CMD
the second must therefore beRGB_COLOR_HSB_VAL(...)
which is already set up to use the colour picker helper.