views:

299

answers:

2

Hi!

When you hold down a key, the JQuery events start to pop out like crazy for this single key press:

...
keydown
keypress
keyup
keydown
keypress
keyup
...

Is there any (even non-browser-portable) way to capture only one event for each key pressed (example: press A and hold it down, and this should yield only one function call)?

Cheers!

+5  A: 

I have found that keyup works the best...

$(document).keyup(function(e) {
  alert(e.keyCode);
});
Josh Stodola
But that produces multiple events per single key press.
Mike Hordecki
@Mike: binding to an event does not produce more events.
Crescent Fresh
You mean $(document).bind('keydown', callback)? It does.
Mike Hordecki
No it does not. This event will fire every time you lift a finger off a key.
Josh Stodola
And karim79, what are you doing? jQuery takes care of the keyCode browser problem. Edit with care, please.
Josh Stodola
Probably an inconsistent behavior across different browsers. In mine(Fx 3.5.2 Gecko/20090804) binding an event to a function that calls console.log gives me the auto-repeating(tested with both keydown and keyup).
Mike Hordecki
Well OK... I've been using keyup for 10 years and I promise you it does not fire more than once per key stroke. I don't care what console.log tells you!
Josh Stodola
Not sure how you are "binding" but you need to do it like how I've done it in the answer.
Josh Stodola
Actually, I've tried that before asking the question. Which browser/OS are you using?
Mike Hordecki
+1  A: 

Since you're giving jQuery a callback, you're surrendering to it's wits. However, you could introduce some more latency for excessive notifications by installing some sort of lazy event queue that you process every tenth of a second.

queue = new Array();
setTimeInterval( 100, function() { queue.process(); } );

queue.process = function( ) { 
    key = queue[0];
    process( key );

    // consume equivalent keypresses by shifting array
    var originallength = queue.length;

    // find shift size
    var firstdiff = 1;
    for(; firstdiff < queue.length && queue[ firstdiff ] == key; 
          firstdiff=firstdiff+1 ) 
    {}
    var newlength = originallength - firstdiff;

    // shift everything and delete trailing tail
    var i = firstdiff;        
    for( var j = 0; j != newlength; j=j+1 ) { queue[ j ] = queue[ j+firstdiff ]; }
    for( var k = newlength; k != originallength; k=k+1 ) { queue[k]=null; }
}

$(document).keyup( function(e) { queue[ queue.length ] = e; } );

Or prevent appending to the queue alltogether using a minimal time diff between keypress events, as in this answer.

xtofl