Need help on making oneshot/keymapswitch macro

To add some context, i’m a french student in physics/math in university and i need to quickly right mathematics on a computer. i use GNU TexMacs to do that job and a UHK with a bunch of macros. To switch from my normal keyboard to math keyboard wanted to make a oneshot macro that would basically do this :

tapkey Lalt+ls#(to switch my keyboard language bcse macros doesn't work if my keyboard is not in english)

switchkeymap MAT
whenkeypressed wait until macro end
switchkeymap QWR

tapkey lalt+ls

The key problem in this macro is that whenkeyIsPressed is a condition that doesn’t exist in uhk agent (at least i don’t think so with my limited knowledge)
So as i didn’t find a way to make a true oneshot macro that does all of this i’m asking on the forum to see if someone actually knows how to do this.

note : I tried weird things with the advanced functions from the github like postponekey and postponekey conditions but it didn’t work

Is the functionality you’re looking for delayUntilRelease?

No, I think I get it: You want to hit this button, then it runs the first part, waits until another macro has run, then performs the second part.
If that is the case, I would suggest a different approach entirely: Make the other macros reset the settings themselves, either through copy-paste, or by calling a common finalizer macro.

But if you really want this kind of behavior, you could do something like this:

postponeKeys while (true) { // wait until another key is pressed
  ifPending 1 break
  delayUntil 4
}
while (true) {
  // Break on some indicator that the macro has finished running
  // The below may work, but a variable indicator would be better
  ifNotPending 1 break // This probably breaks when the other macro starts, not when it ends
  delayUntil 4
}

What about:

tapkeySeq pLA l s rLA

oneShot holdKeymapLayer MAT base

tapkeySeq pLA l s rLA

If it doesn’t work, please tell us what exactly it is you expect and what exactly it is that you are getting.

Forgot about oneShot. That’s a better solution. Never used it, didn’t know it blocked execution while waiting.

I think i missexplained my issue (my bad btw).
First of all, i can’t use oneshot because it recognize modifier keys such as mod, shift and other as input wich is not good for this purpose because need to use the full keymap (including mod and shift layer). the other reason i don’t use oneshot is because it times out pretty quickly even tho i know i can change this with the oneshotsettimeout or something like that;

2nd, the reason i don’t use delayuntilrelease is because in my experience it doesn’t wait for the macro i inputed to be finished but instead it wait for me to release the button.
the reason why I need to wait the end of the macro is that i got some very simple macros that takes millisecs and other that takes full seconds because of the maxinputspeed of my software (wich if i input too much informations in just starts to input some keypresses twice and forget about other).

here’s an example of one of the very long macros :

presskey lalt
tapkey b
tapkey b
releasekey lalt
writetext "-->"
tapkey leftarrow
tapkey downarrow
writetext "x->"
tapkey leftarrow
tapkey downarrow
writetext ">"

(i haven’t done the math but practically it takes about 1-2 secs to run)

and a very shot macro example could be tapkey lalt+F or writetext \frac.

i run 7ms keystrokedelay to prevent the macro form bothering my software that really doesn’t like it under 5ms (and 7ms for longer macros).

So as you can see, the problem seems to be easy at first but when diving in it gets quiet difficult (at least for me) and as my knowledge about condition and postponekeys is very limited i asked here (after 5 hours reading the github advanced doc and coding different macros that just wouldn’t work properly)

i currently use a macro that uses fixed delays but it make my mathematics writting slower as i need to wait for about 800ms before getting my keyboard back in AZERTY and it also prevents me from going too fast with simple macros as if you press it while the delay is not finished it can litterally lock on MAT keymap.

BTW the tapkey Lalt+ls are out of the command block, instead i’ve put tapkey blocks above and down, outside the command and selected shift and alt.

EDIT :
with the following command (based on what you provided me earlier), i finally got it to work but it still doesn’t wait for the macro i pressed to end to finish the process. the issue with that is that the the macro starts well but finish writting things like i pressed the buttons on a french keyboard replacing → by /q (or something like that) for example.

switchKeymap MAT
postponeKeys while (true) { // wait until another key is pressed
  ifPending 1 break
  delayUntil 1
}
while (true) {
  // Break on some indicator that the macro has finished running
  // The below may work, but a variable indicator would be better
  ifNotPending 1 break // This probably breaks when the other macro starts, not when it ends
  delayUntil 4
  
}
delayUntilRelease
switchKeymap QWR

To solve this issue my guess would’ve been to add a fixed delay and postpone any input that is done during this delay to then return it once the delay is finished (but i have no proof of concept that it would work or even be possible).

One other issue i’ve spotted while playing around with the macro is that it does not exclude the shift and mod so i need to hold it if i need to use mod and shift.

I’m sorry if this post is very long i’d understand if you gave up because my needs are pretty specific and i really thank you if you’ve made it this far.

I would suggest using variables for signalling.

Like

setVar oneshotActive true
while $oneshotActive delayUntil 10

And in the other
macros

setVar oneshotActive true

It may also be interesting to use postponeKeys in the other macro to postpone the switcher key’s release, but I guess oneShot implementation doesn’t account for that.

Some hacking with ifGesture may make that work though :thinking:.

setVar oneshotActive false

in other macros, I presume. Otherwise, I agree with this solution.

It might also be easier to just have one macro for enabling the state you want and another for disabling it, then binding it to the same key on both QWR and MAT keymaps? Then you can hit that key, do whatever macros you need, hit it again and continue.

I would also once again mention the option of having a macro unMat or something containing the

switchkeymap QWR

tapkey lalt+ls

and then call unMat at the end of the other macros, although I do dislike solutions which require boilerplate code in macros.

I might also suggest a more radical solution which I went for when faced with a similar problem:
I switched entirely from using my native Danish keymap to US International (With AltGr deadkeys) . It’s just US International with a whole lot of international characters on various Alt+Gr keys. It has the Danish ones, so I presume it will also work for French. Then I had one keyboard layout which fit all my needs.

At the end of the macro, I would exec unMat.

In the interest of less busy waiting, maybe the language should have a

waitUntil ( $oneshotActive == false )

which can be implemented in firmware for whatever loop delay or event trigger works best for the particular firmware/hardware/processor/…

(…and corresponding waitUntilMax TIMEOUT CONDITION, too.)

1 Like

I tried doing some black magic with the ifGesture condition (with a technique i’ve found on this post from the uhk forum : Usecase: One Shot macro (tutorial)). it didn’t really work tho bcse of the same delay issue you gave me a solution for.

I’ve tried with the following macro :

switchKeymap MAT

setVar oneshotActive true
while $oneshotActive delayUntil 5
delayUntilRelease

switchKeymap QWR

and added setVar oneshotActive false in the end of every macro from MAT keymap and it works just as intended (+ i get to choose wich macro ends the oneshot and which doesn’t) in addition to that i made a killswitch that sets the variable back to false and switch keymap to QWR (my base keymap)

I think that i’ll keep it like that bcse it works just as intended, thank to everyone that participated and helped me here.

i’d also like to share a macro that i found myself using pretty often wich improves the mod key behaviour so if u single tap it very fast (like if u missclick it because you’re too used to normal keyboard) it tapkey space but doesn’t have that slight delay you have in a simple macro like :

ifPrimary final tapKey space
ifHold holdLayer mod

Instead it does this (idk it just feels more natural to me) :

holdLayer mod
while (true) {
    ifPlaytime 200 {
        printStatus
        break
        }
    else ifNotAnyMod {
        tapKey space
        break
        }
    noOp
}

You should not need this; it’s already looping in the while until your next macro is done.

A delay of 5 is quite short and will stress the firmware. I’d recommend to keep it at 10 like @kareltucek recommended.

i use delayUntilRelease because i wan’t to be able to hold the macro as long as i want (like if i need to use more than 1 macro from the MAT Keymap) but i use the oneshot as wel. Overall it’s just comfort and if that makes me faster at typing math (for exams for example) that’s all that matters.

Ah, yes, that makes sense! Thanks for the clarification.