# Throttle the response to keystrokes in an EventHandler expression

What might be the most elegant way to throttle the a,s functions triggered by an EventHandler such that the InputField doesn't get to far behind in the following example? Just to clarify. I am looking to have the queued functions stop executing after either the a or s keys are released.

Here is an illustration of a similar issue to the one I am experiencing while in the Graphics3D element.

i = 0;
a[] := (Pause[RandomInteger[{1, 9}]*.1]; i++;);
s[] := (Pause[RandomInteger[{1, 9}]*.1]; i--;);
EventHandler[InputField[Dynamic@i, Number], {"KeyDown" :> (
If[CurrentValue["EventKey"] == "a",
a[], s[]
]
)}
]


EDIT: If you hold down the a key I would like the unrun functions to either not run or somehow throttle the number of times the function is executed such that you can successfully hold down the a key for 2 seconds and then immediately(or as quickly as possible) hold down s key to subtract without a delay in the response. Ideally I would like to use the EventHandler KeyReleased option but I am currently unable to get such key to work.

• Just to clarify, does "too far behind" mean your example should not increment/decrement when I press a key multiple times during the pause or are you hoping for some type of buffered response? – bobthechemist Sep 21 '14 at 14:46
• @bobthechemist If you hold down the a key I would like the unrun functions to either not run or somehow throttle the number of times the function is executed such that you can successfully hold down the a key for 2 seconds and then immediately(or as quickly as possible) hold down s key to subtract without a delay in the response. – William Sep 21 '14 at 16:58
• @bobthechemist I believe KeyReleased would make this process a lot easier although I have been unable to get such EventHandler to work currently – William Sep 21 '14 at 17:08
• This I believe is a duplicate of this if not similar mathematica.stackexchange.com/questions/5246/… – William Apr 14 '16 at 20:41

You can always make a back-end for it and check the response time on that. Here's a little example of a back-end I've been working with:

$eventHandlerData = <| "ResponseDelay" -> Quantity[1, "Seconds"], "_ResponseDelay" :> With[{n = Now}, AbsoluteTime[n +$eventHandlerData["ResponseDelay"]] -
AbsoluteTime[n]
],
"CallDelay" :>
($eventHandlerData[ "_EventAbsoluteTime"] -$eventHandlerData[
"LastCallAbsoluteTime"]),
"LastCallEventTime" -> 0,
"LastCallAbsoluteTime" -> 0,
"x" -> Function[Print["!"]],
"DefaultEvent" -> (Print[$eventHandlerData["EventKey"]] &) |>; callEventHandler[] := Catch[$eventHandlerData =
Join[
$eventHandlerData, Association@CurrentValue["EventData"], <| "EventKey" -> CurrentValue["EventKey"], "EventAbsoluteTime" -> CurrentValue["EventAbsoluteTime"], "_EventAbsoluteTime" -> AbsoluteTime[] |>]; If[$eventHandlerData["_ResponseDelay"] > $eventHandlerData[ "CallDelay"], Throw[$Failed]
];
$eventHandlerData["LastCallAbsoluteTime"] =$eventHandlerData["_EventAbsoluteTime"];
$eventHandlerData["LastCallTime"] =$eventHandlerData["EventAbsoluteTime"];
Lookup[$eventHandlerData,$eventHandlerData@"EventKey",
\$eventHandlerData@"DefaultEvent"
][]
];
EventHandler[expr,
{
"KeyDown" :> callEventHandler[],
PassEventsDown -> False
}
]


Note that I had to fall back to AbsoluteTime as I'm not entirely sure what the timings in CurrentValue["EventAbsoluteTime"] are.

You can then extend it to work in an indexable manner with DynamicModule that way you don't have to worry about cleaning up the backend when you're done with it.

This doesn't work completely for reasons I don't know why, but the following seems to help some by using an InputField to monitor the keyboard input.

str = "";
i = 0;
a[] := (Pause[RandomInteger[{1, 9}]*.1]; i++;);
s[] := (Pause[RandomInteger[{1, 9}]*.1]; i--;);
Dynamic[Refresh[
t = 0;
Map[
(If[# == "a", a[], s[]]) &,
Select[StringSplit[str, ""], t++ < 3 &]
];
str = "";
, UpdateInterval -> 1], TrackedSymbols -> {}]
InputField[Dynamic@str, String, ContinuousAction -> True]
InputField[Dynamic@i, Number]