Feature: KeyAction::Macro
It would be great (and enable chording (#303), if a keypress (or a chord) would trigger multiple outputs.
KeyAction::Macro([k!(H), k!(E), k!(L), k!(L), k!(O)], Some(2));
would print hello for a single KeyAction, optionally only when layer 2 is active.
There is macro support in RMK, but only ASCII characters are supported. Macros can be configured in vial
Ah, could you please point me to it? Yes, Vial as a few more options - but I strive to have everything configured in the fw. Makes version control and re-flashing easier.
One can configure basic ASCII macros using the rust based config without VIAL?
ah. no, the macros can only be configured in vial now.
Ah, thanks for the clarification. I am looking into implementing macro support without vial in rmk.
#284 is related
I am not sure how we want to implement it - I am writing this up because I won't have time in the next week to work on this. But it would be very cool to have this feature (= defining multiple macros via rust) - there are several issues which could be solved by this :) (The layer/mod/key of KeyAction could be chained as well without risking recursion.)
The way QMK does and compatible with Vial or in a custom way, having a KeyAction::Macro([Action]).
My personal use case is to have many macros, to be used with chords (like mentioned in #303), so that pressing some letters outputs a complete word.
Thus I need many more than 32 macros, more like 200. I don't need keys, as I would bind a KeyAction to a position directly. Or, in my case, bind a combo (aka fork) to a macro.
Vial (and RMK at the moment) supports implementing 8 macros. 32 MacroKeys are registered.
Even in QMK more macros can be implemented.
in RMK [keyboard_macro.rs]{https://github.com/HaoboGu/rmk/blob/main/rmk/src/keyboard_macro.rs} defines a data structure compatible with Vial.
Maybe these are not two separate implementations ... and the execution (= sending the desired keys) might be the same.
After taking a deeper look into the macros, I understood that both can be combined.
The macro processing is already implemented - however, the storage of a macro is in binary form (Keymap.macro_cache: [u8]). It is interpreted in the function process_action_macro in keyboard.rs (actually in get_next_macro_operation).
@HaoboGu could you instead move the "on the fly" deserialization where the other deserialization takes place?
If this is refactored, implementing the rest is not much work :)
The data structure could be:
(from keycap.rs)
pub struct KeyMap<
(...)
> {
/// Layers
pub(crate) layers: &'a mut [[[KeyAction; COL]; ROW]; NUM_LAYER],
(...)
/// Macro cache
pub(crate) macros: [[MacroOperation]; NUM_MACRO],
(...)
}
where MacroOperation is from keyboard_macro.rs.
@HaoboGu's answer, as I accidentally posted my last comment at the wrong place!
It is very hard because you have to know the length of
MacroOperationlist at the compile-time.In current implementation, you can have 1 macro with length 255 or 25 macros with length 10 or 255 macros with length 1.
If we do the deserialization early, the max length of macro actions is
MACRO_SPACE_SIZE/max_size_of(MacroOperation), which might waste lots of RAM space.
Good point. Ok, let's start with a parallel macro structure. Maybe we can later convert this into the Vial macro (as well on the fly) - or we keep them separate.
Currently, if you use vial, you can configure arbitrary macro sequence for example on the "M0" macro key. Then you may include this "M0" key directly in your keymap as output of Combos / Forks. I think the only missing part is to be able to configure them in keymap.toml, that is why I entered https://github.com/HaoboGu/rmk/issues/284 issue.
Yes, but you can’t configure the macro sequences via rust either.
In my ZMK config I mapped the top 100 English words on a combo, e.g. “comboKey + H + E” pressed together outputs “hello”.
It would be too much effort configuring this in vial - and there are only 32 M-Keys.
I am currently working on this, hope to finish today as I am in holidays from tomorrow on.
It looks like I can combine all:
- using [u8; MACRO_SPACE_SIZE] as the only place to store macro sequences
- having a function that takes [[MacroOperation]] and converts it to the binary
- Having a new KeyAction::TriggerMacro, that is an alternative to assigning KeyCode::Mx, so that we can configure more than 32 triggers.
Once that works it should be straightforward to implement a possibility to configure Macros from keyboard.toml as well :)
I think this issue can be closed by #337