Is there a way to detect how long a key press is being held?

Is there a way to detect how long a key press is being held? So I can do things based on how long I hold the key.

Probably -- with varying degrees of difficulty, accuracy, and impact on your system's performance depending on how you do it.

What are you trying to do? If you wanted to X if the key is released after 2 seconds but Y after 5 you could save the key-down time to a variable then compare the release time. If you wanted to do X for the first 2 seconds from when the key is pressed and Y after that and until the key is released you could use a time-comparing loop.

This all may be unnecessary anyway -- if you explain your goal, someone may come up with a better way of achieving it.

I would like to record the total time a key has been held down into a global variable. So the variable starts at 0. if I hold it for 300 milliseconds and then release, it should be set to 300. If I hold it for another 200 ms, then it should be set to 500. The time it registers must be consistent and deterministic.

I managed to get something which kind of works.

It will count how long the left arrow key is held and display correctly. However, I'm going to use this macro for a game, and now left-arrow does nothing in the game. So it seems like Keyboard Maestro overrides the default action of left-arrow with this macro. Is there any way to avoid this?

Or another way to solve it?

Among these macros is one that does one thing for a short press and another for a long press. Is that what you want or do you actually need to log the length of the press?

Not quite -- it counts how many times the "While" loop has executed, so will only be correct time-wise if your loop takes 1 millisecond.

Have a read of the Hot Key Trigger page on the Wiki. Note that KM usually swallows the keystroke so it isn't available to the active app.

Importantly for you -- the behaviour when simulating a keypress with KM that is also a hotkey trigger is undefined. So adding a "Keystroke ←" action might send that keystroke to your app, might trigger another instance of your macro, or might do either of those at random.

Could you use, say, ⌥← as your trigger, and your macro then sends ← until you release?

Alternatively you might be able to run an "endless" background macro that reacts to pressed key changes. AFAIK there's no way to detect what key has changed so you'd have to write your own checks -- not so bad if it is just the arrow keys, horrible if you want to use every key available!

Here's a demo. Run the macro in KM, press-hold your arrow keys for varying amounts of time, try some other keys, use the ⌘ key to end the macro (or use KM's menu bar icon's "Cancel All Macros" item):

Log Keypress Times.kmmacros (10.6 KB)

Image

But I'm really hoping one of the gurus will step in with a better way of doing this.

To explain in more detail: In the game you move with the arrow keys. I am basically trying to keep track of the position of the player, while playing the game. And then later, I can make other macros which does things based on the player position. I do realize now that Keyboard Maestro is probably not the best suited for this task.

I tested your Macro Nige_S. It works to some extent. However it seems to not have the accuracy needed. If I press shortly it shows 102 milliseconds. Holding slightly longer, it will give around 200. But it never gives any number in between. Also for very short key-presses, it does nothing.

I think I will try doing this in Python or similar instead as I have some programming experience. It seems a bit more flexible for complex tasks like this.

It's not so much the complexity -- KM is just not made to do this sort of thing. What you're after is, effectively, a key-logger.

While looking for something else I saw this about USB Device Key triggers:

Unlike hot key triggers, the pressed key is not removed or affected in any way.

So:

Arrow Test.kmmacros (6.7 KB)

Image

You might need to set the trigger keys for your own keyboard and, obviously, you could split this into multiple macros with single triggers.

I'm not sure it'll do what you want, though. Events take time to be passed and registered, macros take time to instantiate and run, etc. So it may not be accurate enough for you to reliably track movement within the game -- unless you've a decent +/- because you're looking for "zones" rather than points?

Perhaps there's another way -- many games have mini-maps you could scrape, displayed world coordinates you could OCR, etc.