UltimateHackingKeyboard / firmware

Ultimate Hacking Keyboard firmware
Other
419 stars 66 forks source link

[Macro Syntax] How to refer to the key that activated the current macro in tapKey, holdKey ... #525

Closed rftw closed 2 years ago

rftw commented 2 years ago

I am trying to implement double tap keys on the number row; for example send 1 on single tap, send ! (shifted keycode) on double tap. I got it working using the following macro:

postponeKeys ifNotPending 1 ifNotPlaytime 300 goTo @0
ifPending 1 ifKeyPendingAt 0 #key goTo @3
holdKey 1
break
consumePending 1
tapKey LS-1
break

In the above macro the keycode 1 is hardcoded in holdKey 1 (line 3) and tapKey LS-1 (line 6). Currently, in commands like tapKey and holdKey, you can only use hardcoded keycodes/keyabbrev. This forces me to create separate macros for each number on the number row which is cluttering my sidebar in the uhk agent. Instead, if we have variables that refer to keycodes just like how #key and %n refer to keyids of activation key and postponed keys, it will allow us to use the same macro on any number of keys.

kareltucek commented 2 years ago

The following should do the trick:

ifGesture #key final write !
holdKey 1

Currently, in commands like tapKey and holdKey, you can only use hardcoded keycodes/keyabbrev. This forces me to create separate macros for each number on the number row which is cluttering my sidebar in the uhk agent.

The following should help, assuming that you are willing to sacrifice one layer...

activateKeyPostponed [atLayer LAYERID] KEYID

So, I guess you are looking for something like (with the shifted symbols mapped on the mod layer):

ifGesture #key final activateKeyPostponed atLayer mod #key
holdKey 1

Instead, if we have variables that refer to keycodes just like how #key and %n refer to keyids of activation key and postponed keys, it will allow us to use the same macro on any number of keys.

Will it? Can you provide an example of the requested syntax?

I mean, even if this gets generalized - (I don't plan to invest time into that in any foreseeable future) - even then, self-referential key action would point to the newly bound macro, rather than to the scancode associated with the physical print label of such key.

(I would very much prefer to avoid solutions that assume information dependent on factory mapping or any fixed mapping.)

rftw commented 2 years ago

Will it? Can you provide an example of the requested syntax?"

$key to refer to keycodes, just like how #key refers to keyId.

So, I guess you are looking for something like (with the shifted symbols mapped on the mod layer):

ifGesture #key final activateKeyPostponed atLayer mod #key
holdKey 1

In the above example, 1 is hardcoded in holdKey 1. Instead if we have a variable like $key the code will be

ifGesture #key final activateKeyPostponed atLayer mod #key
holdKey $key       //<-----------

My example will look like:

postponeKeys ifNotPending 1 ifNotPlaytime 300 goTo @0
ifPending 1 ifKeyPendingAt 0 #key goTo @3
holdKey $key                 //<-----------
break
consumePending 1
tapKey LS-$key            //<-----------
break

Now these macros can be mapped to any key.

I guess I created a duplicate issue. This is very similar to #74 which is still open. You can close this issue here and continue the discussion there

kareltucek commented 2 years ago

$key to refer to keycodes, just like how #key refers to keyId.

You mean scancodes.

But how should UHK know what scancode a $key stands for?

If you bind your brand new macro to the 1 key, a $key will no longer point at a scancode action. Instead, it will be pointing at a macro action.

I believe, you want UHK to know that a $key refers to its printed-label meaning, but that means using a "random" fixed translation map, which will instantly break down and produce wtf behaviour for any non-default or non-enUS mappings/users.

kareltucek commented 2 years ago

Also, just tested following version with two backing layers (didn't realized that two indirections are needed) and it seems to work fine:

ifGesture #key final activateKeyPostponed atLayer mod #key
activateKeyPostponed atLayer mouse #key

Given the new support for 8 non-modifier layers, I guess it should not be a too big problem to dedicate the layers...

Edit: actually, it has some problems, e.g., sequence 1112 produces !12 rather than !@. It is caused by appending the new key at the end of the queue, rather than inserting it at front 😣.

rftw commented 2 years ago

I believe, you want UHK to know that a $key refers to its printed-label

yes, this is what I am asking for. I want a variable that refers to the printed-label of the key that activated the macro. Sorry for the confusion caused with wrong terminology.

but that means using a "random" fixed translation map, which will instantly break down and produce wtf behaviour for any non-default or non-enUS mappings/users.

Now I understand the problem. How about syntax that can resolve layer-keyid to use in tapKey, holdKey commands, something like

tapKey $(mod-24) // 24 is the id of hardware key
tapKey $(mouse-#key) // #key is the id of hardware key that activated macro
tapKey $(fn-%0)  // %0 is the keyid of first key which is postponed but not yet activated

Edit: actually, it has some problems, e.g., sequence 1112 produces !12 rather than !@. It is caused by appending the new key at the end of the queue, rather than inserting it at front

I was about to report it. I looked into using activateKeyPostponed KEYID but since it adds the tap of KEYID at the end of queue, I didn't find it helpful in my macros that use postponeKeys command.

kareltucek commented 2 years ago

Now I understand the problem. How about syntax that can resolve layer-keyid to use in tapKey, holdKey commands, something like

tapKey $(mod-24) // 24 is the id of hardware key
tapKey $(mouse-#key) // #key is the id of hardware key that activated macro
tapKey $(fn-%0)  // %0 is the keyid of first key which is postponed but not yet activated

Doesn't look bad, although I think the syntax should be more explicit (aka less perlish). Something like tapKey $(lookupKeyScancode LAYERID KEYID). Understanding $() as a way to resolve lisp-like expressions in a prefix form (, which would probably be applied to regular variable arithmetics too in the future). (Note that # should in the future be replaced by $, so taking some time to think about possible ambiguity is advisable.)

I don't intend to pursue it at the moment, but I guess I am open to emerging PRs.

Also, activateKeyPostponed should probably get additional optional arguments activateKeyPostponed [ prepend | append ] KEYID, which I will try to do in foreseeable future.

(I strongly dislike the activateKeyPostponed name, so alternative suggestions are welcome.)