0

Google Chrome is throwing "Uncaught TypeError: Cannot set property 'isDown' of undefined" but it doesn't look like anything is wrong with my code!

Important part of my variable array:

KEY = {
    UP: 38,
    DOWN: 40,
    W: 87,
    S: 83,
    D: 68
}
pingpong = {
    fps: 60,
    pressedKeys: [],
    complete: false,
}

Key listener initialization (this is where the error is thrown):

    for (var keyCode in KEY) {
        if (KEY.hasOwnProperty(keyCode)) {
            pingpong.pressedKeys[KEY[keyCode]] = {
                isDown: false,
                wasDown: false
            };
        }
    }
    $(document).keydown(function(e) {
        pingpong.pressedKeys[e.which].isDown = true;
    });
    $(document).keyup(function(e) {
/* This line is the issue */    pingpong.pressedKeys[e.which].isDown = false;
    });

Any Ideas?

rshea0
  • 11,769
  • 9
  • 27
  • 40
  • What button do you press when the issue occurs? Perhaps this button is not described in KEY object? – dfsq Jan 16 '12 at 08:49

2 Answers2

2

The problem is that you're trying to access an element of the pressedKeys array which does not exist. For example, if we pressed the "a" key:

$(document).keyup(function(e) {
    //Pressed "a" so e.which == 65
    pingpong.pressedKeys[e.which].isDown = false;
});

When you initialize your array you only create elements for the properties of the KEY object:

for (var keyCode in KEY) {
    //Iterating over KEY, which contains 5 properties...
    if (KEY.hasOwnProperty(keyCode)) {
        //Add value to pressedKeys (this happens for each of the 5 properties)
        pingpong.pressedKeys[KEY[keyCode]] = {
            isDown: false,
            wasDown: false
        };
    }
}

So pressedKeys only contains 5 elements, corresponding to the properties of KEY. Note that a TypeError is also thrown in the keydown event handler, as well as keyup.

To fix it, you could check that e.which is in the KEYS object in the event handler functions. If it's not, just ignore it. Something like this perhaps (there may be a better way, this is just what came to mind first):

$(document).keydown(function(e) {
    for(var k in KEY) {
        if(KEY[k] == e.which) {
            break; //Break out of loop and execute last line
        }
        return false; //Key not recognized, last line is not executed
    }
    pingpong.pressedKeys[e.which].isDown = true;
});
James Allardice
  • 164,175
  • 21
  • 332
  • 312
  • So what do you propose as my solution? – rshea0 Jan 16 '12 at 08:55
  • If I understand correctly, its checking if the input is in KEY, if so, carry on normally, if not, don't add it to pressedKeys. – rshea0 Jan 16 '12 at 09:18
  • 1
    That's right. It checks whether `e.which` (which is the pressed key code) is in the `KEY` object. If it is, the `break` statement is reached, so it leaves the `for` loop and runs the last line of the event handler. If `e.which` is not in `KEY`, the event handler returns `false` before the last line is reached. – James Allardice Jan 16 '12 at 09:21
  • Dang, apparently implementing this causes it to ignore EVERY key press (except the up arrow for some reason). Here is a JSFiddle of the code. http://jsfiddle.net/DsNJb/ – rshea0 Jan 16 '12 at 18:12
  • Nevermind, I fixed it. I removed `return false;` and replaced `break;` with `pingpong.pressedKeys[e.which].isDown = true;` – rshea0 Jan 16 '12 at 19:44
1

e.which is IE only. Real browsers use e.keyCode

jQuery Event Keypress: Which key was pressed?

Community
  • 1
  • 1
user123444555621
  • 148,182
  • 27
  • 114
  • 126