13

In Javascript, I want to write a function that returns a list of all keys that are currently pressed (so that I can allow the user to create custom keyboard shortcuts.) Is there any way to obtain a list of all currently pressed keys in Javascript?

Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • 1
    I haven't yet found an answer, but this code sample could (perhaps) be modified in order to do this: http://stackoverflow.com/a/6473318/975097 – Anderson Green Nov 30 '12 at 06:22

2 Answers2

10
  • whenever a key is pressed a keydown event will be sent
  • whenever a key is released a keyup event will be triggered

So you just need to save the keys in an array and check whether your combination is true.

Example

var keys = [];
window.addEventListener("keydown",
    function(e){
        keys[e.keyCode] = true;
        checkCombinations(e);
    },
false);

window.addEventListener('keyup',
    function(e){
        keys[e.keyCode] = false;
    },
false);

function checkCombinations(e){
    if(keys["a".charCodeAt(0)] && e.ctrlKey){
        alert("You're not allowed to mark all content!");
        e.preventDefault();
    }
}

Note that you should use e.key instead of e.keyCode whenever possible (in this case var key = {}, since e.key is a string).

jibiel
  • 8,175
  • 7
  • 51
  • 74
Zeta
  • 103,620
  • 13
  • 194
  • 236
  • This is better than the `keypressed` event. – Sphvn Nov 30 '12 at 06:26
  • What does the `ord` function do in this case? – Anderson Green Nov 30 '12 at 06:38
  • @AndersonGreen: Oops, accidentally used a command from another language. `e.keyCode` will return an `unsigned long`, so you need to get the correct number for a given char. You should use `String.charCodeAt(0)` for this. – Zeta Nov 30 '12 at 06:41
  • @Zeta You should put an escape character in the word "you're", like this, otherwise it won't work: `'You\'re'` – Anderson Green Nov 30 '12 at 17:45
  • 14
    Scenario: you press/hold a key with document in focus, you click the URL box, then you let go of the key. keyup is never fired, yet the key is up, causing the list to be incorrect. – user3015682 May 02 '15 at 07:36
  • @user3015682: So? Same happens in ~70% of all window based PC games. That's malicious user behaviour. – Zeta May 02 '15 at 07:38
  • 3
    What's malicious? Browsers should provide a list of pressed keys. Browsers already provide a list of pressed GamePad buttons. Maybe even the OS should provide applications a list of pressed keys. – user3015682 May 02 '15 at 08:28
  • 2
    @user3015682: *"`` should do ``"* might be a solution, but you'll need to contact the developer of `` in this case ;). – Zeta May 02 '15 at 08:31
  • 2
    @Zeta At least if you contact the OS or browser, you only need to pester 2 or 3 organizations, rather than the literally millions of companies that develop for OS or browser platforms. Also, at least on windows, the OS does in fact provide applications with the keyboard state - so its really only a browser problem. Anytime this happens in a windows-based PC game, its the game's own stupid fault – B T Sep 16 '16 at 02:53
  • 3
    This answer is by no means solid. For example when the focus of the browser is yanked away, it is not uncommon for the OS to do this. Even Chrome will allow one page to yank focus from another page (eg: calendar notification).. This will break keyboard event-based tracking. You will have a keydown which never throws a keyup event. Btw, the question was how to obtain a list of pressed keys. Creating this from bits of info seems quite different than what was asked. – DAG Aug 21 '17 at 20:19
  • `var keys = [];` should be `const keys = {};`. You aren't using `keys` as an `Array` instance w/ virtual indices, you're using it as an `Object` instance w/ computed key names. Perhaps you chose `[]` as your keys are numeric? A cursory look at how `[]` works—both as a type of `{}` & in its own sparse+dense duality—shows `{}` is a better choice for sparse indexes, both for perf. & semantics. `([])[71]='a'` => an array w/ 72 slots, 71 of them empty. `({})[71]='a'` => an object w/ 1 slot, none of them empty. In this context, JS' [] is just an {} with length and sugar to show keys as ints. – james_womack Dec 03 '17 at 08:46
  • @DAG Clearing the keys with `window.onfocus = function() { keys = [] }` has solved many problems for me. It's not a perfect solution but a simple workaround. – Vince Dec 19 '19 at 10:15
9

Improving on the previous answer, I have written a demo that prints the list of pressed keys on keydown and keyup.

Here it is on jsfiddle.

var keys = [];
document.body.innerHTML = "Keys currently pressed: "
window.addEventListener("keydown",
    function(e){
        keys[e.keyCode] = e.keyCode;
        var keysArray = getNumberArray(keys);
        document.body.innerHTML = "Keys currently pressed:" + keysArray;
        if(keysArray.toString() == "17,65"){
            document.body.innerHTML += " Select all!"
        }
    },
false);

window.addEventListener('keyup',
    function(e){
        keys[e.keyCode] = false;
        document.body.innerHTML = "Keys currently pressed: " + getNumberArray(keys);
    },
false);

function getNumberArray(arr){
    var newArr = new Array();
    for(var i = 0; i < arr.length; i++){
        if(typeof arr[i] == "number"){
            newArr[newArr.length] = arr[i];
        }
    }
    return newArr;
}
​
Elijah Mock
  • 587
  • 8
  • 21
Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • 1
    Should note that this suffers from the same limitation: If focus leaves, you never get the keyDown event. Eg(Chrome): Open JSFiddle, press `Ctrl+D`: Triggers bookmark. When you close it, the fiddle will still show both as pressed since it didn't get keyDown event. – Bojan Krkic Jul 04 '20 at 15:32
  • I'm just curious, since `keycode` is deprecated, is there a way to do this with `key` instead and a dictionary? – Codeitfast May 17 '22 at 23:48