1

From another stackoverflow post (How can I add a JavaScript keyboard shortcut to an existing JavaScript Function?) I have this hotkey code:

function doc_keyPress(e) {
    if (e.shiftKey && e.keyCode == 80) {
       //do something
    }
}

document.addEventListener('keyup', doc_keyPress, false);

which works with two keys. But with three keys, shift + l + m for example, it does not work.

the if statement would be:

if (e.shiftKey && e.keyCode == 76 && e.keyCode == 77) {}

again this does not work.

How do I get this working for shift + l + m.

Community
  • 1
  • 1
shell
  • 1,867
  • 4
  • 23
  • 39

3 Answers3

1

Using a closure, I would envisage you can do something like this

var doc_keypress = (function() {
    var prevWasL = false;
    return function(e) {
        if (e.type == 'keypress') {
            if (e.shiftKey && !(e.ctrlKey || e.metaKey)) {
                if (prevWasL) {
                    if (e.charCode == 77) {
                        console.log('doing it');
                        prevWasL = false;
                        return; 
                    }
                }
                if (e.charCode == 76) {
                    prevWasL = true;
                    return;
                }
            }
            prevWasL = false;
        } else { // keyup
            if (e.key == 'Shift') {
                prevWasL = false;
            }
        }
    }
}());

document.addEventListener('keypress', doc_keypress);
document.addEventListener('keyup', doc_keypress);

Add both keypress AND keyup event listeners so that the scenario of

Shift + L, release both, Shift + M, doesn't trigger a false positive

This would require shift then L then M being pressed in that order ... if you want either order of L and M, then the code would be a little different, but you should be able to figure that out

NOTE: I use charCode, because firefox at least, keyCode is always 0 on keyPress event

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
1

tricky, tricky, but I managed to get it working. Just be aware that browsers have their own hot keys (like chromes [ctrl]+[shift]+i) which may override the function.

<!DOCTYPE html>
<html>
<body>
<input id="myInput" onkeydown="keyDownEvent(event)" onkeyup="resetKeys()">
</body>
</html>
<script>
var key1Pressed=false;
var key2Pressed=false;

function resetKeys(){
    key1Pressed=false;
    key2Pressed=false;
}
function keyDownEvent(e){
    e=e||event, chrCode=(typeof e.which=="number")?e.which:e.keyCode;

    if (e.shiftKey && chrCode === 76) key1Pressed=true;
    if (e.shiftKey && chrCode === 77) key2Pressed=true;

    if(key1Pressed && key2Pressed){

        alert('Three Keys Are Pressed');

        key1Pressed=false;
        key2Pressed=false;
    }
}

document.getElementById('myInput').focus();
</script>
Bug
  • 508
  • 1
  • 3
  • 15
0

If you're trying to double press or triple press keys and catch an event after this, I've written a simple helper:

function KeyPress(_opts) {
  this.opts = Object.assign({}, {
    counts: {},
    timeouts: {},
    timeBetweenPresses: 300
  }, _opts || {});
}

KeyPress.prototype.bubbledReset = function bubbledReset(keyCode) {
  var self = this;
  if (this.opts.timeouts[keyCode]) {
    clearTimeout(this.opts.timeouts[keyCode]);
    this.opts.timeouts[keyCode] = 0;
  }
  this.opts.timeouts[keyCode] = setTimeout(function () {
    self.opts.counts[keyCode] = 0;
  }, this.opts.timeBetweenPresses);
};

KeyPress.prototype.onTap = function onTap(cb) {
  var self = this;
  return function handler(event) {
    self.opts.counts[event.keyCode] = self.opts.counts[event.keyCode] || 0;
    self.opts.counts[event.keyCode]++;
    self.bubbledReset(event.keyCode);
    cb(event.keyCode, self.opts.counts[event.keyCode]);
  };
};

Usage Simply use the onTap method to instance:

var keyPress = new KeyPress();

document.addEventListener('keyup', keyPress.onTap(function (keyCode, count) {
  if (keyCode === 68 && count === 3) {
    // 68 was tapped 3 times (D key)
  }
  if (keyCode === 13 && count === 6) {
    // 13 was tapped 6 times (ENTER key)
  }
}));

Hope this helps someone else!

Or if you prefer es6:

class KeyPress {
  constructor(_opts) {
    this.opts = Object.assign({}, {
      counts: {},
      timeouts: {},
      timeBetweenPresses: 300
    }, _opts || {});
  }

  bubbledReset(keyCode) {
    if (this.timeouts[keyCode]) {
      clearTimeout(this.timeouts[keyCode]);
      this.timeouts[keyCode] = 0;
    }
    this.timeouts[keyCode] = setTimeout(() => {
      this.counts[keyCode] = 0;
    }, this.timeBetweenPresses);
  }

  onTap(cb) {
    return event => {
      this.counts[event.keyCode] = this.counts[event.keyCode] || 0;
      this.counts[event.keyCode]++;
      this.bubbledReset(event.keyCode);
      cb(event.keyCode, this.counts[event.keyCode]);
    };
  }

}
Shannon Hochkins
  • 11,763
  • 15
  • 62
  • 95