The objective is manually set a held key's "repeat rate".
For example, when in a text box and pressing and holding the X key, I understand that there is browser-specific ways of repeating the pressed character. In some, it pauses, then continuously triggers the pressed key. In others, it doesn't repeat at all. I want to mitigate this by forcing the pressed key to repeat at a specific interval, regardless of browser.
Through research, I've come up with a timer-based attempt, but in Safari, it does not repeat the character. I've got a menu system where holding down arrow scrolls through the list, but the translation animation and repeat rate don't like each other.
var repeating = false;
var repeatRateTimer = null;
$( document ).bind( 'keyup', function( input ) {
if( repeatRateTimer != null )
{
clearTimeout( repeatRateTimer );
repeatRateTimer = null;
}
repeating = false;
} );
$( document ).bind( 'keydown', function( input ) {
input.preventDefault( );
if( repeating == true )
{
if( repeatRateTimer != null )
{
clearTimeout( repeatRateTimer );
repeatRateTimer = null;
}
else
{
repeatRateTimer = setTimeout( function( ){ repeating = false; }, 1000 );
}
return;
}
repeating = true;
// ...keyboard logic
} );
I may have botched this whole thing up...I tried to recreate a simplified version of this SO post. However, I feel there has to be a better way of doing this. Any thoughts?
Update:
We can assume that the end-user hasn't set their OS keyboard repeat rate greater than the rate I want to use (1000ms). If it is, then it should fall back to their repeat rate, since it won't keep triggering the key press event. If it isn't (more likely since most people don't modify that), then we would be overriding that behavior to make it delay our specified period.
Well, I figured out why my example wasn't looping. In the keydown loop, it was clearing the timeout before it expired:
The timeout should be cleared only after it expires, so the
if
condition needed to be moved into the timeout function:I'll leave this bounty open in case someone can improve upon this, or provide a better alternative.
Look at the following JavaScript file. If you scroll down to line 530 you will find the following class:
What the author has done is that he has created a special
Keyboard
class for delegating the key events:keyup
,keydown
andkeypress
. The class has only one constructor which accepts a single argument - the interval of thekeypress
event (which is what you want). You can add event listeners using theaddEventListener
method of the instance of theKeyboard
class:Note that the above class depends on the following framework: Lambda JS. You can see a working demo of the above script here. Hope this helps.
Update 1:
Your code does not work in Opera. In addition the second event fires after a extra 500 ms delay in Firefox and consecutive events do not maintain the same interval. Plus it can't handle multiple key events at the same time. Let's rectify this problem:
First we need to create a simple script for Delta Timing so that the key events fire after constant interval. We use the following snippet for creating a
DeltaTimer
:Next we write the logic to fire custom
keypressed
events. We need custom events since we must be able to handle multiple keys at the same time:The
interval
is set at1000
ms but you may change that. Finally to register an event we do:This is simple and efficient JavaScript. No jQuery required. You can see the live demo here, and see the difference between your script and mine. Cheers.
Update 2:
Looking at the other question on StackOverflow, this is how you would implement it using the above pattern:
Using the above code will remove the short delay you're experiencing and also allow multiple events to be fired for different keys at the same time.
How about you make custom key events. you can listen to the original ones (keyup/keydown) and if they pass the time condition, you trigger your custom event.
This way has the benefit that you do not rely on timers and it gives you more power, because you use custom events (btw, you can skip the cancel event part if you wish).
Here's a demo to see what I'm talking about : http://jsfiddle.net/gion_13/gxEMz/
And the basic code looks something like this :