How to create a macro to press two modifiers

I am currently trying my hand at homerow mods. Previous attempts never worked for me due to too many misfires, so I am working around this by using multiple keys. Basically the idea is something like this:

S+D = Ctrl
D+F = Shift
S+D+F = Ctrl + Shift

It’s the third part that I’m having trouble with. I tried binding this to S:

ifShortcut d f final {
  holdKey rightCtrl
  holdKey rightShift
}

The hold works as expected if there’s only one “final holdKey” in the command. However, when putting together 2 like this what seems to happen instead is that my key presses are put in a queue and then run without modifiers when I let go. I tried various workarounds, but always fail at the 2 simultaneous modifiers part.

Is it possible to achieve this kind of setup?

Yes. See MODMASK in the grammar.

E.g., holdKey LSC stands for left shift and left control.

Another way would be to use pressKey and delayUntilRelease.

Thanks, MODMASK is exactly what I was looking for.

As a final step, can I change the behavior based on tap vs hold? It’s easy for single keys, but all the methods that I was able to come up with run into the same key queuing issue. For example I’d like to be able to tap JK for escape and hold it for Shift.

Well, you can give a try to ifHold and ifNotHold, or to ifPrimary or ifSecondary, or to use ifInterrupted. Search the firmware/doc-dev/user-guide.md at master · UltimateHackingKeyboard/firmware · GitHub for them.

I am not sure what queuing issue you are talking about. What have you tried?

Here are versions with both ifSecondary and ifHold that I have tried:

ifShortcut timeoutIn $HRM_TIMEOUT j {
  ifHold final holdKey leftShift
  final tapKey escape
}
holdKey k
ifShortcut timeoutIn $HRM_TIMEOUT j {
  ifSecondary advancedStrategy final holdKey leftShift
  final tapKey escape
}
holdKey k

Tapping K as normal input and KJ as escape both work. Only holding KJ as shift has a problem. When I hold KJ and press a the expected behavior is for A to be written because the hold works as shift. What happens instead is that nothing is written. Only when I let go of KJ a lowercase a does get written.

This is what I mean with the queue. As long as KJ is held every other input is queued up and written only after I let go.

That sounds like a bug. Will look into it…

1 Like

There may be some bugs still lurking, @kareltucek. I have been having some weird behaviours with my HRM macros lately, which use a very similar combination of ifShortcut followed by ifSecondary. Unfortunately, I have not been able to create a consistent, small example showcase for the problem. It seems to come and go.

Indeed a bug! Nice catch! Thanks for report!

Please give a try to the firmware from Fix freeze when ifShortcut or ifPrimary was used with braces. · UltimateHackingKeyboard/firmware@7c4e84d · GitHub , should be fixed there.

2 Likes

Tried the firmware and can confirm the bug has been fixed.

For reference, this is what I have built (no idea if and how much I’ll keep, but it does work now):

ifShortcut timeoutIn $HRM_TIMEOUT anyOrder j l final holdKey LSC
ifShortcut timeoutIn $HRM_TIMEOUT anyOrder semicolonAndColon l final holdKey LAC

ifShortcut timeoutIn $HRM_TIMEOUT l final holdKey leftControl
ifShortcut timeoutIn $HRM_TIMEOUT j {
  ifSecondary advancedStrategy final holdKey leftShift
  final tapKey escape
}

holdKey k
3 Likes