MACRO: HotKey Multi-Press Template (Double-Press, Triple-Press, Etc.)

As @DanThomas said, it is the "Switch/Case" Action.
I just renamed the title of the Action after I inserted it in my Macro.

Here is what it looks like when you first insert the Action:

You can find it in the Actions > Control Flow category:

perfect, it keep getting deeper and deeper and deeper, I’m completely smiling. - cheers.

1 Like

Very good solution for app activation hotkeys if you have analogous apps, like Safari and Chrome!

1 Like

I’m a begginer user of this app and I don’t get it. I tried to use this macro but can’t figure out what exactly needs to be done to be able to perform different actions triggered by only one key, depends on how many time it has been pressed. Anyone could provide more complex guide?

As a beginner, you may be better off starting more slowly and then working up. The best way to start using Keyboard Maestro is to start simple:

  • Read the Quick Start (Help menu)
  • Do the Tutorial (Help menu)
  • And then grow your macros organically, starting simple.
  • Then ask for help with any macros you get stuck on.

This macro basically keeps track of the time it was last executed, and keeps a count of the number of times that the macro is triggered repeatedly in a short period of time. To use it, you you add your actions to the end, (replacing the Prompt for User Input action) and use the hkmpKeypressCount variable to determine what behaviour to perform. But it is a fairly complex macro, so you are going to need to know a fair bit about Keyboard Maestro in order to understand it (you may well be able to make use of it without understanding the details before then).

But if you have a specific behaviour you want to create, the best thing to do is to post a new topic and specify exactly what you want to do and then people can help you solve it - there may well be simpler solutions.

Hi Dan,

This comes late after your post (almost two years).
I was looking for how to distinguish single and double taps (or presses), and am grateful for your macro.
When I tried to document it for my own purposes, I found a number of simplifications, and I may be wrong or have overlooked something. But here is my version:

HotKey MultiPress Template.kmmacros (11.1 KB)

Comments in general on this way of solving the multi-press problem:

a) It relies on the delay to be longer than any sequence of decision statements to be executed.

b) When trying to understand what is going on, the complexity is caused by having five separate processes collapsed into one piece of code:
1-setting the delay and limit constants
2-restarting a pause at each press
3-counting the number of presses
4-doing the desired actions when a pause times out
5-cleaning up

c) Normally these processes communicate with each other and run independently, as they would in e.g. Modula.

d) In a summarising language (not Modula):

========================================================

1  put 0.2 into delay
2  put 5 into limit
3
4  lock Running
5  if already locked then --"timeout exceeded"
6     if active <= limit then
7            increment active
8     exit
9			
10 put 1 into active
11 put 0 into count
12	
13 while active > count
14      put active into count
15      pause delay
16	
17	
18 case count
19      1: …
20      2: …
21      …
22	
23 delete variables

========================================================

Since there are no constant declarations, lines 1 and 2 must be executed at each press.

We start a new pause each time there is a press within the current pause. To detect that we are in a pause, we lock a semaphore "Running" (line 4): at each press we try to lock it again and count an additional press if it fails and terminate the current instance (lines 5-8)

There seems to be no need for the second semaphore nor for some other assignments.

The case statement ("switch" in C-like languages) finally does the desired action depending on the count of presses (lines 18-20).

It seems to work for me: I'm using Keyboard Maestro to type French on a US extended keyboard where I use the Fn keys for accents. F1 to F5 type â,ê,î,ô,û but I also need ù sometimes, so I configured it so that pressing F5 twice gives me ù.

Hopefully you find something dreadfully wrong with this version.
Or not. :grin:

Best, Robert.

Umph… There is a problem with this macro, both in the original version and mine.
If another key is pressed before the delay is over then that key is "executed".
Example: I have multi-press on F5: a single press types û and a double press types ù.
Now if I type "C'est là où il y a la statue" but I go at my normal typing speed then it comes out as:
"C'est là o ùil y a la statue"
and that is because I managed to type the space before the delay was over, so the space goes into the text right after the "o". Then the delay is over and the "ù" is inserted by the macro, then I hit the "i".
If I make the delay sufficiently long then I can type many letters before the "ù" appears and if I make it too short then I can't type the "ù" because I can't hit the keys fast enough.
So? The moment I type anything else than F5 the F5 macro should somehow find that out, tell the system to hold on (accumulating keystrokes in a buffer) do whatever it needs to do with the current count it has, then let the system put in the other keystrokes.
I don't know how to do that, or even if it is possible.

Use the "Semaphore Lock" action.

image

Put this at the start of the macro. It locks a "Semaphore" with the name you enter. Don't worry about what a Semaphore is. And KM automatically unlocks the Semaphore when the macro is done, so don't worry about that.

Then put this same action at the start of any other macro you want to fail if the multi-press action is running. So when this other macro tries to lock the Semaphore with the same name, the lock will fail, and the macro will quit.

You probably want to adjust the settings so you don't get notified when this happens. Click the Gear icon.

Hope this helps.

Hi Dan,

Thanks! (someone is replying!).
I happen to know what a semaphore is (I wrote real-time operating systems way back when, and also happen to have met Edsger Dijkstra who was the first to use them in computing, inspired by the railways' block systems)

However, while that semaphore will block other macros, it does not block any simple keys. It would be a bit tedious to assign a macro to each key, just for that purpose.
I admit readily that I have not fully explored Keyboard Maestro's possibilities, so I may have overlooked something.

Now, I wrote this tiny demo program:

=================================================

global gWaitDoublePress, gBuffer

on openstack
   put false into gWaitDoublePress
   put empty into gBuffer
   put empty into field "Text"
end openstack


on RawKeyDown fKey
   if fKey<128 then
      if gWaitDoublePress then
         put numtochar(fKey) after gBuffer
      else
         put numtochar(fKey) after field "Text"
      end if
      exit RawKeyDown
   end if
   if fKey=65474 then -- F5
      F5doublepress
   end if
end RawKeyDown



on F5doublepress
   if gWaitDoublePress then
      -- this is the second one
      put "ù" after field "Text"
      put gBuffer after field "Text"
      put false into gWaitDoublePress
      put empty into gBuffer
   else
      put true into gWaitDoublePress
      send TypeUcirc to me in 12 ticks
   end if
end F5doublepress


on TypeUcirc
   -- the timer has expired, were we actually waiting?
   if gWaitDoublePress then -- yes, type û (u-circ)
      put "û" after field "Text"
      put gBuffer after field "Text"
      put false into gWaitDoublePress
      put empty into gBuffer
   end if
end TypeUcirc 

=================================================

And I've attached the LiveCode app as well:

doublepresskeys.livecode.zip (1.2 KB)
(to run it, you need to download a free version of LiveCode which you can find here:
https://downloads.livecode.com/livecode/
use the community edition, it is free; then you will have activate the project browser and inspect the stack's script, and explore a bit; good luck…)

I'm not happy with that program at all, but it does show some things: it catches all keypresses, transmits the ASCII ones but nothing else except the F5 key. For that it launches a process which waits for 12 ticks (1 tick = 1/60 second) but while doing so other messages pass, i.e. it does not block further typing.
(note that if you set the delay to 2 seconds instead of 12 ticks, you will actually see the typing buffer in action)

It is this blocking delay that I don't know how to circumvent.
In the meantime I'll just have to remember that for "ù" I have to slow down my typing a little. :grinning:

1 Like

Ah, that explains everything! I'm a developer also, so I understand your dilemma. You need to step back and think of Keyboard Maestro in a different light. Don't try to make it do things it's not designed to do. In other words, quit thinking like a developer (for now, anyway - there's plenty of development fun you can have once you get your thinking straight).

KM is designed to respond to a single trigger, such as one key being pressed. (Ignore Typed String Triggers for this discussion). When it sees the trigger, it runs a macro.

Assume that for all intents and purposes, it eats the keystroke. Never try to pass that keystroke on to the application from within your macro. You might get away from it, but it will always end up causing problems.

Trying to catch other keystrokes during a macro is asking for trouble, and totally counter to how KM expects to work. Trust me on this - been there, done that. There are rare times when you can get away with it, but they're exceptions, and really will only lead to trouble in the end.

So when you use the multi-press concept, use it on a true hotkey. A key that is designed to run an action, and nothing else. The fact you can hold it down a little longer and take a different action is irrelevant - It's still a hotkey, and don't ever expect it to act as a normal key.

I don't know if any of this makes sense or not, but the main point is that you need to step back and rethink how you use KM. Even though it has tons of features, it's NOT the operating system, and you can't "program" it like it is.

But once you "get it", hold on, man! The fact you can call AppleScript, or better yet, JSX, opens a whole new world.

Dan

Ah well, there we go…
Yes, I thought it would be impossible with KM.

I do have lots of hotkeys and they work well, and have been doing so for years.

But then because of a complex building renovation project around here I needed to type a lot more French than usual. But my keyboard is not Swiss-French, it is UK/US because I need the [ ] { } and so on for programming. No accents.

Apple's original shortcuts for accents are easy to remember but they do need two keystrokes and a modifier key: option-e followed by e to get é for example. Well, try to reply to your notary's messages with lots of é, è, à, ù etc. and not lose your patience.

So I thought: why not use the F-keys for those characters. And it works like a dream, except that the "où" still annoyed me because it occurs so often. That's when I thought to "overlay" some of the accented characters on each other, using a double-press to get the simular but less used forms, e.g. ù on top of û.

Then I looked for a solution and found your template. It took some time to "thaw" it out so I could understand it (I'm not the type to use a piece of code without knowing what goes on…), but it worked well.
Until the time, soon after, that I began to type faster.

Having those keys makes typing French so much easier that it's hard to imagine not having them. I'll just be a little careful with the ù.

Robert.

Have a look at LiveCode anyway, you may be interested. Applescript and LiveCode have a common ancester in Hypercard, in fact, if you happen to remember Hypercard, LiveCode is Hypercard as it should have been: easy, fast, connected to the internet etc. and it produces real apps for nearly all platforms (including html5!)

Glad that helped! I don't really have time to look at anything right now, I'm busy working on my YouTube channel. The only reason I answered your question is because I got an email when you talked about one of my macros.

Not that I minded answering your question - I didn't mind at all. :slightly_smiling_face:

Damn, this is so freaking awesome

1 Like

Hey, this is really great. How can I modify it so that it only reacts to a specific number of taps in quick succession?

I would like to replicate the behaviour of some IDEs where, for instance, double-tapping shift brings up a search bar. Unless I'm missing something, this macro will execute all the way through, no matter how many presses are made? (below the maximum limit, that is.)

Should I just add a 'if hkmpActiveKeypressCount == the_number_I_want, then do my_action' action?

Thanks for your template, it saved me a lot of fumbling around already :slight_smile:

A post was split to a new topic: How Do I Use xKeys with KM?

Was searching for something like this and found this macro. (I'm surprised I did not see this before. I sought I skimmed through the entire section of "Macro Library" before. I guess I probably did not notice it because I did not have the need by then.)

Thanks a lot for all of your excellent macros, @DanThomas.

2 Likes

This seems to be just what I'm looking for. I'm trying to allow single/double taps on my Stream Deck, but rather than using the device key trigger or a hotkey, I'm trying to use @corcules' KMLink plugin to pass TriggerValues onto KM. For context, the buttons on my Stream Deck contain the KMLink plugin, each passing on a TriggerValue (via KMLink's Parameter) that corresponds to the Keystroke I'd like to be simulated. So if the TriggerValue is f1, then one tap will simulate the hotkey F1 and two taps will simulate alt+F1.

@DanThomas, perhaps your macro only works with hotkeys or perhaps I've made an error, but I've set it up according to @JMichaelTX's example and hkmpKeypressCount always comes back as 1.

SD single:double tap.kmmacros (71.5 KB)

As far as I can tell, my original macro should handle this just fine. Assuming the original macro is basically unchanged, all I can think of is to check these actions in the macro:

image

Hi Dan. Thanks for the reply. I checked by changing the trigger to a hotkey and it worked nicely, so the issue seems to be using KMLink as the trigger.

1 Like

For anyone interested, I figured out a workaround for Stream Deck double presses.

Set up as many buttons as you like as hotkey actions in Stream Deck.
Add all these hotkeys as triggers for the macro.
Press each button once with a Display text in a window action and copy/paste the hotkey as text into the relevant Switch group entries. Example:

Works like a charm! Thanks @DanThomas!

7 Likes