javascripteventskeypresskeydownonkeyup

keydown (repetition) breaks when keyup event (for ANOTHER key) is fired


This is a bit of a weird one so I figure I'm either missing something obvious or this is a flaw with how these events are implemented in browsers.

Let me first summarize an example scenario this issue comes up with before providing an isolated case-example;

The arrow keys are used to move the player (as a handleKeyDown function is fired anytime a key is hit anywhere on the page). Likewise, anytime a key is released another function is fired (handleKeyUp).

As you (the player) hold the left key down, the handleKeyDown function is repeatedly triggered (which admittedly I think defies what you'd expect and what the name implies, but nonetheless, this is normal behavior across all browsers as I'm sure you know).

So here's what happens: the player holds a direction to walk in that direction; they then press a number key (for hot-keyed item) AS they continue to walk while holding the direction down. What happens here is that as you release the number key for the hot-keyed item, the repetition for player movement just stops!

I've written a very small isolated example of this behavior:

<html>
<head>
    <script type='text/javascript' src='jquery-1.5.1.min.js'></script>
    <script type='text/javascript'>
        var log = {};
        var keyState = {};
        var keyCount = {'down': 0, 'up': 0};
        window.addEventListener('keydown', handleKeyDown, false);
        window.addEventListener('keyup', handleKeyUp, false);
        function handleKeyDown (e)
            {
            keyState[e.keyCode] = true;
            keyCount.down++;
            log.prepend(" ["+e.keyCode+"] ");
            return false;
            }
        function handleKeyUp (e)
            {
            keyState[e.keyCode] = false;
            keyCount.down++;
            return true;
            }
        $(function(){log = $('#log');});
    </script>
</head>
<body>
    <div id='debug'></div>
    <div id='log'></div>
</body>

You can also try it here:

http://sikosoft.net/keys.html

Press any keys on the page and you will see the keyCode appear on the page. As you hold down the key, the keycode repeats over and over.

The behavior gets quirky when press down a different key while the initial key is still being held. Upon release of that recent key, the repetition stops from the first key. Interestingly, if you try the example and hold down one key, and then hold a second key, but instead of releasing the second, release the first: the second key DOES continue to repeat.

So what seems to go on is that when the keyup event is fired, it seems to terminate repetition in keydown events that were fired on an earlier key.

I've tried all sorts of things ranging from using returning false in both event-handling functions, returning true, trying keypress instead of keydown, saving key-states and continuing movement if the button's keystate is still true, but what it all comes down to is that when keyup is fired any actively propagating keydown events are killed. I've read through JavaScript Madness: Keyboard Events and I am not seeing anything about this specific sort of behavior.

Is this a design flaw with the implementation of key-events, or am I missing something? I observe this same behavior in Chrome, IE & Firefox.

Any advice or input?


Solution

  • That is the way the OS/environment works, and as a result that is the way the browser works.

    The keydown repetition shouldn't continue firing after the keyup from another key in the browser, since it doesn't behave that way anywhere else. Open Notepad, or vim, or pico, or whatever text editor you use, and perform the same sequence of events. You'll see that after the keyup, the first key you pressed does not keep printing new letters. That's just the way these things were designed in the OS, and as a result that's the way they're propogated through to the editors and browsers etc.