Search code examples
javascriptkeyboard-events

Lightweight JavaScript keyboard configuration map


I'm trying to provide a way for a user to map custom keys for a JavaScript game I'm working on. I think I'm just missing something simple here as I can't see how to make this work without looping over each key value (something I want to avoid as I don't want to introduce any unnecessary loops while still providing flexibility).

Basically, there is a global array keys which tracks the keys that have been pressed to easily allow multiple keypresses to be handled simultaneously.

// keyboard lookup
// map movement keys to WASD, VI keys, and arrow keys
let keyboardConfig = {
  'left': [37, 72, 65],
  'right': [39, 76, 68],
  'up': [38, 75, 87],
  'down': [40, 74, 83],
  'upleft': [89],
  'upright': [85],
  'downleft': [66],
  'downright': [78]
}

And the keyboard handler:

// handle keyboard
let keys;
function handleKeys(e) {
  keys = (keys || []);
  keys[e.keyCode] = true;

  let dirX = 0;
  let dirY = 0;
  let updateViz = false;

  // TBD: replace keys[37] (etc.) with a more intelligent approach
  if (keys[37]) { // left
    dirX = -1;
    updateViz = true;
  }
  if (keys[38]) { // up
    dirY = -1;
    updateViz = true;
  }
  if (keys[39]) { // right
    dirX = 1;
    updateViz = true;
  }
  if (keys[40]) { // down
    dirY = 1;
    updateViz = true;
  }

  if (updateViz) {
    player.move(dirX, dirY);
    camera.update();
  }
}

Basically, I want to avoid having to do something like a forEach over every keyCode defined in keyboardConfig.left, for instance. On the other hand, I need to avoid doing something like if keys[keyboardConfig.left[0]] || keys[keyboardConfig.left[1]] || keys[keyboardConfig.left[2]] as that clearly is not very extensible.


Solution

  • This is the general idea, if there are conditions you need to check against, you're almost always going to want maps to define what it is to do, then implement those maps as instructions - this is a start:

    document.onkeyup = handleKeys;
    let elExample = document.getElementById("example");
    // keyboard lookup
    // map movement keys to WASD, VI keys, and arrow keys
    let keyboardConfig = {
      'left': [37, 72, 65],
      'right': [39, 76, 68],
      'up': [38, 75, 87],
      'down': [40, 74, 83],
      'upleft': [89],
      'upright': [85],
      'downleft': [66],
      'downright': [78]
    }
    let movement = {
      'left': -1,
      'right': 1,
      'up': -1,
      'down': 1
    }
    let keyConfig = {};
    for(let item in keyboardConfig){
        for(let i in keyboardConfig[item]){
            keyConfig[keyboardConfig[item][i]] = item;
        }
    }
    
    // handle keyboard
    let keys;
    function handleKeys(e) {
    console.log(e.keyCode)
      keys = (keys || []);
      keys[e.keyCode] = true;
      
      if (keyConfig[e.keyCode]) {
          console.log(keyConfig[e.keyCode], movement[keyConfig[e.keyCode]]);
          elExample.innerHTML = keyConfig[e.keyCode] + " " + movement[keyConfig[e.keyCode]];
          
          //player.move(movement[keyConfig[e.keyCode]] || 0, movement[keyConfig[e.keyCode]] || 0);
          //camera.update();
      }else{
        elExample.innerHTML = "Not a tracked key";
      }
    
    }
    <h4 id="example">type some stuff</h4>