I’m trying to combine the wiggle gesture you helped me set up with an automatic timeout after five seconds of inactivity. I thought I would be able to modify the code snippet from this mouse-jiggler discussion, but I can’t get it to work.
I added the inactivity code at the end of the expression, then replaced Register 1 (which is already in use) with Register 8.
When I save the expression, then the wiggle gesture doesn’t work. I’m guessing that the movement detection is cancelling out the wiggle detection, in which case maybe this doesn’t work at all. If not, what would be a better approach?
I’m also wondering how to enable the back button to also engage scrolling (which would then be disabled by inactivity). I’m not sure if it’s best to add that to the existing expression or make a second expression that also stores Register 5.
/* ALGORITHM STEP 1: Reset countShake (R1) if >150ms has passed since last shake (R3). */
/* If the condition (time - R3 > 150) is true, use 0, otherwise use the old value from R1. */
time 3 recall sub 150 gt 0 1 recall ifte 1 store
/* ALGORITHM STEP 2: Detect a valid wiggle. */
/* Condition is true if: >500ms since last toggle AND mouse moved left/right AND vertical movement is minimal. */
/* Check if time - lastShakeSwitch > 500 */
time 4 recall sub 500 gt
/* Check for rightward shake: mouse.x > 4 AND !lastDir */
0x00010030 input_state 4 gt 2 recall not bitwise_and
/* Check for leftward shake: mouse.x < -4 AND lastDir */
0x00010030 input_state -4 lt 2 recall bitwise_and
/* Combine left and right shake checks */
bitwise_or
/* Check for minimal vertical movement: abs(mouse.y) < 10 */
0x00010031 input_state abs 10 lt
/* Combine horizontal and vertical checks */
swap bitwise_and
/* Combine with the 500ms debounce guard */
swap bitwise_and
/* The boolean result is stored in temp Register 6. */
6 store
/* ALGORITHM STEP 3: If a wiggle was detected (R6=1), update state registers. */
/* Increment countShake (R1) */
6 recall 1 recall 1 add 1 recall ifte 1 store
/* Update lastShake (R3) to current time */
6 recall time 3 recall ifte 3 store
/* Flip lastDir (R2) */
6 recall 2 recall not 2 recall ifte 2 store
/* ALGORITHM STEP 4: If countShake (R1) > 3, toggle scrolling mode and reset state. */
/* First, check the condition and store the result in temp Register 7. */
1 recall 3 gt 7 store
/* Based on R7, toggle set_scrolling (R5). */
7 recall 5 recall not 5 recall ifte 5 store
/* Based on R7, reset countShake (R1) to 0. */
7 recall 0 1 recall ifte 1 store
/* Based on R7, update lastShake (R3). */
7 recall time 3 recall ifte 3 store
/* Based on R7, update lastShakeSwitch (R4) to begin the 250ms debounce. */
7 recall time 4 recall ifte 4 store
/* Cancel if left button is pressed and released */
5 recall
0x00090001 input_state_binary not
0x00090001 prev_input_state_binary mul
not mul
5 store
/* Cancel if back button is pressed and released */
5 recall
0x00090004 input_state_binary not
0x00090004 prev_input_state_binary mul
not mul
5 store
/* Cancel after three seconds of inactivity DOESN'T WORK*/
0x00010030 input_state abs
0x00010031 input_state abs
add /* was there movement? */
3000 /* if so, reset the counter */
8 recall 1 sub /* if not, decrement the counter */
ifte
relu /* don't go below zero */
dup
8 store /* store for next frame */
0 eq 5 store /* this will activate layer 0 */
Ah, I see it now with the ifte. So, the last section is:
/* Cancel after three seconds of inactivity */
0x00010030 input_state abs
0x00010031 input_state abs
add /* was there movement? */
3000 /* if so, reset the counter */
8 recall 1 sub /* if not, decrement the counter */
ifte
relu /* don't go below zero */
dup
8 store /* store for next frame */
0 eq /* if counter is zero */
0 /* deactivate layer */
5 recall /* otherwise keep its current state */
ifte
5 store
If I now want to toggle scrolling with the back button, I believe that I need to modify this section to include a bitwise_and to detect sticky_state.
/* Cancel if back button is pressed and released */
5 recall
0x00090004 input_state_binary not
0x00090004 prev_input_state_binary mul
not mul
5 store
Working from the layer_state example in the documentation, I tried this, and also added a dummy mapping for the back button (as instructed). But it’s just breaking the whole thing, so clearly I’m still missing something.
sticky_state 0x02 bitwise_and not not 0x00090004 input_state_binary mul /* if layer 1 is sticky and back button is pressed */
1 /* activate layer */
0 /* deactivate layer */
ifte
5 store
Again you can’t overwrite register 5 or you lose the activation and timeout logic.
If you want the back button to just activate the layer, you can add something like this:
5 recall
0x00090004 input_state_binary
bitwise_or
5 store
If you want it to activate and deactivate the layer then the logic has to be a little more involved.
5 recall
5 recall /* layer active and... */
0x00090004 input_state_binary
0x00090004 prev_input_state_binary not mul /* button just pressed */
mul
not mul /* deactivate */
5 recall not /* layer not active and... */
0x00090004 input_state_binary
0x00090004 prev_input_state_binary not mul /* button just pressed */
mul
bitwise_or /* activate */
5 store
That’s easier than I thought it would be. Sorry that I need so much hand-holding…I’m a visual learner and an inexperienced programmer. I’m starting to wrap my head around the stack of values in Reverse Polish Notation.
I’ve also realized that this gets even easier if I use tap_state to activate/deactive the layer, because then it’s not necessary to check the previous input state. This enables me to use the hold state as a middle click without needing to add that to the expression.
5 recall
5 recall /* layer active and... */
0x00090004 tap_state /* button is released after tap */
mul
not mul /* deactivate */
5 recall not /* layer not active and... */
0x00090004 tap_state /* button is released after tap */
mul
bitwise_or /* activate */
5 store
Can I suggest adding a “Tutorials” topic to the forum? I’ll post the configuration we’ve put together with comments and JSON, so that other people can use it in its final form.
Now that you’ve got the forum, it would be great to move the examples from the web configuration page here. On a few occasions, I’ve clicked on an example and accidentally overwritten some work in progress. I can’t be the only one who’s done that.
Examples/tutorials would also preserve the expression comments and add content that search engines will pick up, increasing your visibility.
EDIT: I didn’t see your forum post about the expression builder until just now. Doh. It really helps to visualize the logic!