Expressions - ability to call one expression from another
To keep them more DRY, modular, readable.
Let's look at the extended expression from https://github.com/jfedor2/hid-remapper/issues/131#issuecomment-2186958622 It contains quite mouthful piece repeated twice, that does something meaningful and can be extracted as a function in other programming languages. Would be great to be able to do a similar thing.
New expressions may look like this:
Expression 1:
/* 1 on A press, otherwise 0 */
0x00070004 input_state_binary
0x00070004 prev_input_state_binary not
bitwise_and
Expression 2:
1 recall
/* A pressed and layer not active... */
1 expression
1 recall not
bitwise_and
/* -> activate it */
bitwise_or
/* A pressed and layer active... */
1 expression
1 recall
bitwise_and
/* -> deactivate it */
not bitwise_and
/* B pressed... */
0x00070005 input_state_binary
/* -> deactivate layer */
not bitwise_and
1 store
Parameters can be passed through registry:
Expression 1:
/* 1 on input press, otherwise 0 */
3 recall input_state_binary
3 recall prev_input_state_binary not
bitwise_and
Expression 2:
1 recall
/* A pressed and layer not active... */
0x00070004 3 store 1 expression
1 recall not
bitwise_and
/* -> activate it */
bitwise_or
/* A pressed and layer active... */
0x00070004 3 store 1 expression
1 recall
bitwise_and
/* -> deactivate it */
not bitwise_and
/* B pressed... */
0x00070005 input_state_binary
/* -> deactivate layer */
not bitwise_and
1 store
I'm still figuring how expressions work.
Seems like at least trivial cases are already possible like this:
Expression 1:
/* 1 on A press, otherwise 0 */
0x00070004 input_state_binary
0x00070004 prev_input_state_binary not
bitwise_and
3 store
Expression 2:
1 recall
/* A pressed and layer not active... */
3 recall
1 recall not
bitwise_and
/* -> activate it */
bitwise_or
/* A pressed and layer active... */
3 recall
1 recall
bitwise_and
/* -> deactivate it */
not bitwise_and
/* B pressed... */
0x00070005 input_state_binary
/* -> deactivate layer */
not bitwise_and
1 store
Documentation on expressions lifecycle in context of a mapping and interaction between expressions might be handy to have.
hey, i just finished making a tool to simulate hid remapper expression, personally i think this tool might be useful for debugging, creating any complex expression you want, and or might be helpful for figuring out the language too
HID remapper expression evaluator
hope this helps
Hey @onixldlc that's nice and handy. I also thought about making something around the expression language. But specifically for my issues, I think it is not helpful.
I think I have a grasp of the stack language itself. What I have trouble with and what lacks documentation is the lifecycle of the remapper itself, where in the loop multiple mappings, expressions, etc are evaluated...
@onixldlc Oh, that is exciting!
@KillyMXI I hope to improve the documentation in the future, it roughly works like this every frame.
First, tap/hold/sticky mappings are processed. Then layer-activating mappings are processed. Then expressions are evaluated one after another. Every expression is executed once, in order, regardless of whether its output is used in a mapping. Then regular mappings are processed. The order in which they're defined doesn't matter.
This means that for example if you're using expressions to set layer state, you're getting a 1 frame delay, because the results of the expression will be used on the next frame. The delay itself shouldn't realistically be an issue as it's 1 millisecond, just something to keep in mind as it can affect the logic.
@onixldlc , excellent, but...
I was about to post a question about the clamp expression and wanted to make sure I understood its x,y,z inputs.
Your hid remapper expression evaluator answered it for me. It was as I expected with the lifo nature of the stack; First item pushed is x, next is y, last is z.
I entered the following expression as a test:
124 4 add 8 sub 127 -127 clamp
and got the result of 127 as expected.
Then I added 1 store:
124 4 add 8 sub 127 -127 clamp 1 store
I thought it would push 1, then pop 1 and pop 127 and store 127 in register 1, but it gave me an error:
Error
The expression reduce to an empty result.
I can't see the contents of R1 in my browser (Safari), so I selected, copied and pasted and R1 does contain 127, but I'm not clear on the error.
Am I missing something?
It is okay for an expression to finish with an empty stack if you're not using the expression itself in your mappings, but registers that it set.
Oh woops, my bad, i should really make the website scale based on the user screen, i'll probably fix that later.
And for the error, yeah most of the example expression that i used always rely on the output of the expression itself, like the socd and the proportional mouse movement via arrow, and so using register as a method to control your input never really crosses my mind.
But i guess for the sake of clarity i might change that empty expression error into a warning or info instead, so that it won't confuse anyone else
Thanks for the clarifications.