Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine the &mo and &ht #1643

Closed
kaievns opened this issue Jan 31, 2023 · 6 comments
Closed

Combine the &mo and &ht #1643

kaievns opened this issue Jan 31, 2023 · 6 comments

Comments

@kaievns
Copy link

kaievns commented Jan 31, 2023

ohi folks, can I ask for an advise, please?

here is the problem. I'm using a custom keyboard layout, but it's a tricky one, because it switches to QWERTY when one of the mods are pressed. basically the point is that all the normal crtl+c, ctrl+v, ctrl+s combinations still work the way they work in QWERTY, but otherwise it's a different layout altogether.

now, I'm trying to replicate this behaviour in ZMK and apply that to home row mods. I two layers defined the custom layout and qwerty, and now I want something like mod-tap that drops into another layer when mod is pressed.

I found that I can combine a mod and a layer switch with a macro like so, I have wrapped it into a macro generator. Where I'm struggling is combining that with the hold tap behaviour, or more simply how to pass a macro into a hold-tap as an argument.

Here is what I'm trying so far, but it doesn't really compile

#define COLMAK 0
#define QWERTY 1
....

#define QWERTY_MOD_MACRO(name, mod)            \
name: name##_macro {                           \
	label = #name;                             \
	compatible = "zmk,behavior-macro";         \
	#binding-cells = <0>;                      \
	wait-ms = <0>;                             \
    bindings                                   \
        = <&macro_press &mo QWERTY &kp mod>    \
        , <&macro_pause_for_release>           \
        , <&macro_release &mo QWERTY &kp mod>; \
};

/ {
    macros {
        QWERTY_MOD_MACRO(qalt, LALT)
        QWERTY_MOD_MACRO(qgui, LGUI)
        QWERTY_MOD_MACRO(qctl, LCTRL)
    };
};

#define HOME_ROW_MOD_TAP(name, macro)      \
name: name##_mod_tap {                     \
    label = #name;                         \
    compatible = "zmk,behavior-hold-tap";  \
    #binding-cells = <2>;                  \
    flavor = "balanced";                   \
    tapping-term-ms = <200>;               \
    quick-tap-ms = <150>;                  \
    global-quick-tap;                      \
    bindings = <macro>, <&kp>;             \
};

/ {
    behaviors {
        HOME_ROW_MOD_TAP(ht_alt, &qalt)
        HOME_ROW_MOD_TAP(ht_gui, &qgui)
        HOME_ROW_MOD_TAP(ht_ctl, &qctl)
        qht: quick_hold_tap {
            label = "quick_hold_tap";
            compatible = "zmk,behavior-hold-tap";
            #binding-cells = <2>;
            flavor = "balanced";
            tapping-term-ms = <170>;
            quick-tap-ms = <130>;
            global-quick-tap;
            bindings = <&kp>, <&kp>;
        };
    };
};

#define HRML(k1,k2,k3,k4) &ht_gui k1  &ht_alt k2  &qht LSHFT k3  &ht_ctl k4
#define HRMR(k1,k2,k3,k4) &ht_ctl k1  &qht RSHFT k2  &ht_alt k3  &ht_gui k4

can you school me in the zmk ways a bit and let me know what am I doing wrong here?

Thanks!

@caksoylar
Copy link
Contributor

You always need to pass two paramaters to a hold-tap behavior, even if one of the sub-behaviors do not expect one. In your case the hold binding (macro) doesn't expect one, so you can pass a dummy parameter like 0 that it will ignore:

#define HRML(k1,k2,k3,k4) &ht_gui 0 k1  &ht_alt 0 k2  &qht LSHFT 0 k3  &ht_ctl 0 k4

That being said, a mod-morph can make your life easier where you simply morph the custom layout key to C, V, S etc. when ctrl is held down.

@kaievns
Copy link
Author

kaievns commented Jan 31, 2023

thanks, Cem, passing a dummy 0 worked like a charm!

btw, I'm still feeling about how the bindings and the #binding-cells thing work. I see there is some sort of a repeating pattern going on between the behaviours, but I'm still pretty vague on how it actually works.

Is there any piece of documentation around specifically for those properties?

@kaievns kaievns closed this as completed Jan 31, 2023
@caksoylar
Copy link
Contributor

btw, I'm still feeling about how the bindings and the #binding-cells thing work. I see there is some sort of a repeating pattern going on between the behaviours, but I'm still pretty vague on how it actually works.

Is there any piece of documentation around specifically for those properties?

I am not a devicetree expert myself, but keymap bindings property is a phandle array and there are some Zephyr docs explaining #X-cells and how it related to X properties: https://docs.zephyrproject.org/latest/build/dts/phandles.html#dt-phandle-arrays

In the context of ZMK, different behavior types (as specified by compatible property) have fixed #binding-cells values that cannot be changed when you create instances of them; however they still need to be specified in the node definition to those fixed values, like described in the behavior config sections.

How the behaviors handle the passed parameters I think is dependent on its implementation. Some behaviors take zero parameters like macros and mod-morphs, which are not parametrizable (so you need to create a new instance for each macro). One binding behaviors like &kp and &mo are trivially parametrized. The only behavior that has two binding cells is the hold-tap, which requires nuance on how it handles them.

@kaievns
Copy link
Author

kaievns commented Jan 31, 2023

ah, that makes perfect sense, I didn't know that it's the zephyr's thing. I'll poke at that. thanks for the info!

@kaievns
Copy link
Author

kaievns commented Jan 31, 2023

btw, @caksoylar, did you solve that pesky alt-tab problem somehow by any chance?

@caksoylar
Copy link
Contributor

If you mean #997, then I use a custom branch with #1366 merged in and it is working well for my purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants