4

I've got several editable divs. I want to jump through them by pressing arrow keys (38 and 40).

Firefox 3 on Mac OS and Linux won't repeat the events on holding the key. Obviously only keypress events are supported for repetition. As the keys 38 and 40 are only supported on keydown I'm kind of stuck.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
pex
  • 7,351
  • 4
  • 32
  • 41

2 Answers2

1

Yes, you're kind of stuck. You could emulate the behaviour you want by using timers until you receive the corresponding keyup, but this obviously won't use the user's computer's keyboard repeat settings.

The following code uses the above method. The code you want to handle keydown events (both real and simulated) should go in handleKeyDown:

var keyDownTimers = {};
var keyIsDown = {};
var firstKeyRepeatDelay = 1000;
var keyRepeatInterval = 100;

function handleKeyDown(keyCode) {
    if (keyCode == 38) {
        alert("Up");
    }
}

function simpleKeyDown(evt) {
    evt = evt || window.event;
    var keyCode = evt.keyCode;
    handleKeyDown(keyCode);
}

document.onkeydown = function(evt) {
    var timer, fireKeyDown;
    evt = evt || window.event;
    var keyCode = evt.keyCode;

    if ( keyIsDown[keyCode] ) {
        // Key is already down, so repeating key events are supported by the browser
        timer = keyDownTimers[keyCode];
        if (timer) {
            window.clearTimeout(timer);
        }

        keyIsDown[keyCode] = true;
        handleKeyDown(keyCode);

        // No need for the complicated stuff, so remove it
        document.onkeydown = simpleKeyDown;
        document.onkeyup = null;
    } else {
        // Key is not down, so set up timer
        fireKeyDown = function() {
            // Set up next keydown timer
            keyDownTimers[keyCode] = window.setTimeout(fireKeyDown, keyRepeatInterval);
            handleKeyDown(keyCode);
        };

        keyDownTimers[keyCode] = window.setTimeout(fireKeyDown, firstKeyRepeatDelay);
        keyIsDown[keyCode] = true;
    }
};

document.onkeyup = function(evt) {
    evt = evt || window.event;
    var keyCode = evt.keyCode;
    var timer = keyDownTimers[keyCode];
    if (timer) {
        window.clearTimeout(timer);
    }
    keyIsDown[keyCode] = false;
};
Tim Down
  • 318,141
  • 75
  • 454
  • 536
0

You can use keypress and check the e.keyCode == 38,40 instead of e.which or e.charCode This is consistent across Mac and Win.

$('#test').bind($.browser.mozilla ? 'keypress' : 'keyup', function(e) {
    if ( (e.which || e.keyCode) == 40 ) { /* doSometing() */ }
});

See JavaScript Madness: Keyboard Events (3.2. Values Returned on Character Events) and event.keyCode on MDC.

  • That same page (which is also my stock key event page to which I refer people) also has "2.2. Events Triggered on Auto-Repeat", which suggests that browser support for auto-repeating `keypress` events for special keys such as cursor keys is no better than for `keydown` events. – Tim Down Dec 14 '09 at 22:13
  • 'keydown' for all browsers except firefox (in my case safari) instead of 'keyup' worked fine for me. thanks! – pex Dec 15 '09 at 15:06
  • `$.browser` is now depreciated. – Cullub Feb 05 '16 at 21:32