kareltucek/firmware

rationale for a `pressKeyPostponed #key` command to write generic macros

orthoceros opened this issue · 2 comments

I have played with $postponeKeys activateKeyPostponed #key this week. If #key is not released yet, I noticed that I need to execute this command twice in order to make the current key play after a subsequent layer change by macro. Even then, it is played as a tap on the target layer (as the docu states), although #key is still physically pressed. This makes OS key repetition impossible, but I need this for my navigation/arrowing layer.
What I would like to have and suggest is a pressKeyPostponed #key command, rather than the currrently implemented tapKeyPostponed #key. Also, the releaseKey event should follow automatically once the associated #key is actually physically released. Is this possible?


A little background: I depleted my 32KB config space, mainly because I copied my virtual mod macros to every char key that I wanted to make a virtual mod. My virtMod logic involves complex timings and rescueing to eradicate typing interference, i.e. these macros are lengthy. To save config space, I rewrote them now using two central generic macros.

  • Each virtMod trigger key now only uses a very short macro that $call(s) virtModTrigger after setting registers defining the intended secondaryLayer.
  • If the decision is typing rather than going to secondaryLayer, the virtModTrigger macro uses $setReg 7 #key; $ifRegEq 7 keyID... switches, i.e. I had to hard-code the keyID->scanCode translations for all trigger keys in this central macro. A first (optional but useful) way to write this much more generically and elegantly would be $postponeKeys holdLayer VAN base; $postponeKeys final pressKeyPostponed #key, where VAN.base is a macro-free vanilla keymap that just defines the scancodes for any #key. So, the idea is to duplicate and prepend the current hardware #key event to the postponer queue again, but route it to the vanilla keymap/layer. Then every key could become a virtMod simply by calling this central macro, without any hard coding of scancodes in this macro.
  • Another use case where pressKeyPostponed #key is not just elegant but even required: One part of my rescueing logic involes pairs of keys that are pressed near-simultaneously. E.g. ; is my virtMod to hold my NAV layer and NAV.l := rightArrow. So ;->l = rightArrow. But I press ;l almost simultaneously in practice and sometimes it physically becomes l;. Therefore, the l key also points to a lookahead macro that corrects the order ifKeyPendingAt 0 19 within 50ms. To make this order correction, I currently use activateKeyPostponed #key, then let the postponed ; = keyID(19) call the virtModTrigger macro, which results in the intended rightArrow after all, despite physically having pressed the keys in the wrong order. But I only get a tap(rightArrow), although keyID(19) is still physically pressed. Here I would like to have a pressKeyPostponed #key command. (Of course, this second generic macro also has to implement scancodes like ifRegEq 7 keyID(l) final holdKey l in case of typing; this hardcoding could again be replaced by the vanilla keymap idea described above.)

Well, so you are basically reporting is:

  • you press a key which activates a macro.
  • this macro adds the same key into the queue (e.g., as if you wanted to program a doubletap).
  • once your macro or postponed mode ends, the events in the postponer queue are replayed even though the activation key has not been released yet.

I noticed that I need to execute this command twice in order to make the current key play

Since you have not released the key yet, the firmware still sees the key as pressed when replaying the "press" event. Therefore the press event is a noop. The only result of the first virtual tap is therefore release of the key. Second such virtual tap takes place as normal.

What I would like to have and suggest is a pressKeyPostponed #key command, rather than the currrently implemented tapKeyPostponed #key. Also, the releaseKey event should follow automatically once the associated #key is actually physically released. Is this possible?

No, since postponer queue is just an event queue. There is no way to queue a macro event in the queue.

Also, the reasons for doing such things via the postponer are far beyond my comprehension. I am very sorry to say so, but I am no longer neither able nor williing to (try to) follow your thought processes. The only thing I can recommend is to dive straight into the C code of the firmware. It should not be hard - the relevant code is just a few thounsands lines (including the extended macro engine).

Actually... it would just suffice to queue a "press" event without a corresponding release event, wouldn't it? Still, I do not think I want to support this sort of usecases, since they are far beyond the intended purposes of the engine. As you have already proven there are some design flaws/limitations of the current action executor and time management mechanisms, which basically means that behaviour of these parts of firmware might be unstable/undefined.