MACRO: HotKey Multi-Press Template (double-press, triple-press, etc.)

#MACRO: HotKey Multi-Press (Multi-Tap) Template

HotKey Multi-Press Template.v1.0.kmmacros (18.3 KB)

Based on an example by @peternlewis.

Use this macro template to create a macro whose hotkey can be single-tapped, double-tapped, triple-tapped, etc.

Just copy the template, change the hotkey, and add your macro actions to the end (replace the "Prompt" action). The variable "hkmpKeypressCount" contains the number of taps.

You can specify how many multi-taps to allow, and how long to wait between taps before assuming you've got them all.

After the taps have been detected, any additional taps are ignored while the macro is running.

10 Likes

Awesome macro, Macro Master Dan! :thumbsup:

It seems to work perfectly, but I can’t figure out the logic.
But that’s OK, you don’t need to explain. I’m happy to treat this as a black box. :wink:

One thought does occur: This is a great candidate for a custom plug-in, because of its size and complexity. It would be great to have a plug-in that simply returns the number of key presses.

Thanks!

This is a great candidate for a custom plug-in

Plugins can’t do what this macro does. Sorry. As for the size, just collapse all the actions. :wink:

It seems to work perfectly, but I can’t figure out the logic.

LOL. I just now tried to explain it, and I couldn’t do it very well. I’ll think about doing a video, because some of the techniques I use could be useful to other people. We’ll see.

Fortunately, it’s easy to use and reuse. Add it to KMFAM. :smile:

OK, then here is how I have configured your macro to go into my KMFAM:
Your entire macro is in the Group "GET Number of HotKey Presses".
The Actions in magenta need to be changed for each use of your macro.

1 Like

That works. Or, you could make a macro that asks for the number of keypresses, builds those actions, and pastes it in.

If you post the actions, I can create a macro to do that. It would be good practice for me, because I want to do something like this in a tutorial.

I’m not sure I understand what you are suggesting, but it sounds too complicated.
With my setup, all I have to do is insert the Actions for each number of key presses.
Very simple.

Fair enough. Truth is, even after I create the tutorial, you may still feel it’s too complicated - and you might be right! I mean, just because you can do something doesn’t mean you should do it, right? :smile:

what is that last magenta ‘block’ action called? What type of action is it.
the ‘execute actions’ chuck
It’s not an if/then statement,
what is it?
thanx

It’s a “Switch” action.

nice, thank you-

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:

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