Check if a key is down?
Asked Answered
B

16

128

Is there a way to detect if a key is currently down in JavaScript?

I know about the "keydown" event, but that's not what I need. Some time AFTER the key is pressed, I want to be able to detect if it is still pressed down.

P. S. The biggest issue seems to be that after some period of time the key begins to repeat, firing off keydown and keyup events like a fiend. Hopefully there is just a simple isKeyDown(key) function, but if not then this issue will need to be overcome / worked around.

Berkley answered 1/12, 2009 at 20:17 Comment(2)
A common problem with the answers I see here is that if you hold a key down, then change tabs or change focus, let the key up, and then switch back, the code will believe the key is down until you press it again or move the mouse over the page. :-(Baggs
Does this answer your question? JavaScript: Check if mouse button down?Macneil
E
98

Is there a way to detect if a key is currently down in JavaScript?

Nope. The only possibility is monitoring each keyup and keydown and remembering.

after some period of time the key begins to repeat, firing off keydown and keyup events like a fiend.

It shouldn't. You'll definitely get keypress repeating, and in many browsers you'll also get repeated keydown, but if keyup repeats, it's a bug.

Unfortunately it is not a completely unheard-of bug: on Linux, Chromium, and Firefox (when it is being run under GTK+, which it is in popular distros such as Ubuntu) both generate repeating keyup-keypress-keydown sequences for held keys, which are impossible to distinguish from someone hammering the key really fast.

Enterotomy answered 1/12, 2009 at 20:47 Comment(15)
You sir are a gentleman and a scholar. Chromium and Firefox on Ubuntu are my primary development environment, so that accurately explains the issue I've been seeing. Hopefully it will get better, otherwise that timer hack solution might be the only workaround.Berkley
Yeah, it is frustrating that there is no progress on this. See bugs.launchpad.net/ubuntu/+bug/369880 . I'm writing a browser game and my workaround for the moment is to stick to the modifier keys (shift, ctrl, etc.) which do not repeat at all.Enterotomy
No, it is possible to distinguish them from genuine repeated keypresses by their lack of corresponding keyup events.Andonis
@Andonis Isn't it what bobince he explained ?: That keyup events were emitted as well ?Thanasi
is this still the case, 8 years later? This answer might need being updated.Constituent
The GTK+ bug is fixed now, but the rest remains.Enterotomy
Linux is not a browser. Huh?Astonish
parsing help: (Linux && (Chromium || (Firefox && GTK+)))Enterotomy
MouseEvent has the shiftKey property, if that's what someone is looking for. So it is in fact possible to check for modifier keys in other ways than keydown.Whereunto
@AdamJagosz - OP is aware that events can pass keyboard information. The question is about detecting key information outside of an event.Semiotic
@Semiotic I was simply stating that "The only possibility is monitoring each keyup and keydown and remembering." is not true.Whereunto
You can check my script here in: github.com/brunoinds/isKeyPressed You only need to call a function KeyPressing.isKeyPressed(theKeyCode) and it will return true or false when and how you want!Ora
In my experience (on chrome), this method doesn't work, because there is sometimes no keyup event when a key is released (e.g. if the user presses the key, moves the focus out of the element or window, and then releases the key) in which case this method will erroneously report the key is being held down forever. @BrunoFreire 's isKeyPressed code suffers from this problem. So, is there no way to do this?Embezzle
@DonHatch That's true Don! Actually, after a while, I realized the browser KeyUp Event behaviour is not the only problem. The nature of JS EventLoop is a problem too. When the key up is fired, they go to the EventLoop queue. But this do not means the EventLoop will dispatch the events in same order they was created. Some times the KeyUp is dispatched before the KeyDown, even if the KeyDown was created before the KeyUp. It's a really sucks, even more if you are working with a high key pressing rates.Ora
@BrunoFreire wow, that's terrible. I was going to suggest listening for the "blur" event (on window, not document, apparently), and, when received, record that all keys have been released. That seems to work reliably to deal with the missing keyup events, in my experience. But I have no idea how to deal with the keyup coming before the corresponding keydown, that just seems like it would be impossible to handle correctly.Embezzle
F
175

In addition to using keyup and keydown listeners to track when is key goes down and back up, there are actually some properties that tell you if certain keys are down.

window.onmousemove = function (e) {
  if (!e) e = window.event;
  if (e.shiftKey) {/*shift is down*/}
  if (e.altKey) {/*alt is down*/}
  if (e.ctrlKey) {/*ctrl is down*/}
  if (e.metaKey) {/*cmd is down*/}
}

This are available on all browser generated event objects, such as those from keydown, keyup, and keypress, so you don't have to use mousemove.

I tried generating my own event objects with document.createEvent('KeyboardEvent') and document.createEvent('KeyboardEvent') and looking for e.shiftKey and such, but I had no luck.

I'm using Chrome 17 on Mac

Fireweed answered 16/1, 2012 at 3:36 Comment(6)
I'm using this, in both new and old browsers, even HTA'sResident
Is there a way to implement this answer when some number is currently down? I've tryed with if (e.keyCode==49) {console.log("1 is down");} but doesn't works :(Backtrack
Hey @RobertoSepúlvedaBravo Robert seems to answer you question on the next answer. ;)Cassella
Actually you shouldn't be looking for e.shiftKey on keyup if you mean up of Shift. Use e.shiftKey on e.g. onclick instead.Luanaluanda
Dope answer, exactly what i came here to find. Thanks!Tucson
"This are available on all browser generated event objects". Well, not all browser events. It looks like only events of type KeyboardEvent and MouseEvent, and those descended from them (like TouchEvent), have the keydown-related properties like altKey. I'd hoped FocusEvent might have it, but nope.Bemuse
E
98

Is there a way to detect if a key is currently down in JavaScript?

Nope. The only possibility is monitoring each keyup and keydown and remembering.

after some period of time the key begins to repeat, firing off keydown and keyup events like a fiend.

It shouldn't. You'll definitely get keypress repeating, and in many browsers you'll also get repeated keydown, but if keyup repeats, it's a bug.

Unfortunately it is not a completely unheard-of bug: on Linux, Chromium, and Firefox (when it is being run under GTK+, which it is in popular distros such as Ubuntu) both generate repeating keyup-keypress-keydown sequences for held keys, which are impossible to distinguish from someone hammering the key really fast.

Enterotomy answered 1/12, 2009 at 20:47 Comment(15)
You sir are a gentleman and a scholar. Chromium and Firefox on Ubuntu are my primary development environment, so that accurately explains the issue I've been seeing. Hopefully it will get better, otherwise that timer hack solution might be the only workaround.Berkley
Yeah, it is frustrating that there is no progress on this. See bugs.launchpad.net/ubuntu/+bug/369880 . I'm writing a browser game and my workaround for the moment is to stick to the modifier keys (shift, ctrl, etc.) which do not repeat at all.Enterotomy
No, it is possible to distinguish them from genuine repeated keypresses by their lack of corresponding keyup events.Andonis
@Andonis Isn't it what bobince he explained ?: That keyup events were emitted as well ?Thanasi
is this still the case, 8 years later? This answer might need being updated.Constituent
The GTK+ bug is fixed now, but the rest remains.Enterotomy
Linux is not a browser. Huh?Astonish
parsing help: (Linux && (Chromium || (Firefox && GTK+)))Enterotomy
MouseEvent has the shiftKey property, if that's what someone is looking for. So it is in fact possible to check for modifier keys in other ways than keydown.Whereunto
@AdamJagosz - OP is aware that events can pass keyboard information. The question is about detecting key information outside of an event.Semiotic
@Semiotic I was simply stating that "The only possibility is monitoring each keyup and keydown and remembering." is not true.Whereunto
You can check my script here in: github.com/brunoinds/isKeyPressed You only need to call a function KeyPressing.isKeyPressed(theKeyCode) and it will return true or false when and how you want!Ora
In my experience (on chrome), this method doesn't work, because there is sometimes no keyup event when a key is released (e.g. if the user presses the key, moves the focus out of the element or window, and then releases the key) in which case this method will erroneously report the key is being held down forever. @BrunoFreire 's isKeyPressed code suffers from this problem. So, is there no way to do this?Embezzle
@DonHatch That's true Don! Actually, after a while, I realized the browser KeyUp Event behaviour is not the only problem. The nature of JS EventLoop is a problem too. When the key up is fired, they go to the EventLoop queue. But this do not means the EventLoop will dispatch the events in same order they was created. Some times the KeyUp is dispatched before the KeyDown, even if the KeyDown was created before the KeyUp. It's a really sucks, even more if you are working with a high key pressing rates.Ora
@BrunoFreire wow, that's terrible. I was going to suggest listening for the "blur" event (on window, not document, apparently), and, when received, record that all keys have been released. That seems to work reliably to deal with the missing keyup events, in my experience. But I have no idea how to deal with the keyup coming before the corresponding keydown, that just seems like it would be impossible to handle correctly.Embezzle
H
69

My solution:

var pressedKeys = {};
window.onkeyup = function(e) { pressedKeys[e.keyCode] = false; }
window.onkeydown = function(e) { pressedKeys[e.keyCode] = true; }

I can now check if any key is pressed anywhere else in the script by checking

pressedKeys["code of the key"]

If it's true, the key is pressed.

Hermeneutics answered 26/1, 2016 at 17:53 Comment(5)
Since keys is already a function, a different variable name might be better.Cappello
this won't work for detecting if the Alt key is down or not in all cases.Virginity
This is great for detecting up / down / left / rightTrapeziform
be careful with things like "cmd-tab" on mac or "ctrl-tab" on windows. It will fire the key down, then switch windows, and when they come back it will never fire the keyup (because the browser wasn't focused to receive that keyevent)Offcolor
what if the key was pressed before this listener was added?Seethrough
I
12

I don't believe there is anything like an isKeyDown function, but you could write your own.

Basically, create an array whose length is the number of keys you want to monitor. Then using the documents/pages/controls keyUp and keyDown events, update the array with that key's state.

Then write a function that checks if a certain key is down and returns a bool.

var keyEnum = { W_Key:0, A_Key:1, S_Key:2, D_Key:3 };
var keyArray = new Array(4);

function onKeyDown()
{
    // Detect which key was pressed
    if( key == 'w' )
        keyArray[keyEnum.W_Key] = true;
    // Repeat for each key you care about...
}

function onKeyUp()
{
    // Detect which key was released
    if( key == 'w' )
        keyArray[keyEnum.W_Key] = false;
    // Repeat for each key you care about...
}

function isKeyDown(key)
{
    return keyArray[key];
}

That should accomplish what you want.

Inhalator answered 1/12, 2009 at 20:27 Comment(2)
This is good, and indeed part of the solution, but it doesn't address the keyup repeating bug I am experiencing. See bobince's answer.Berkley
This is not a good solution as you would be writing more and more ifs. A "keyList = {};" being an object accepts "keyList[key] = true;" without the need of an enum or limit as it uses string indexes/properties and works for all keys.Pharyngeal
I
9

Ended up here to check if there was something builtin to the browser already, but it seems there isn't. This is my solution (very similar to Robert's answer):

"use strict";

const is_key_down = (() => {
    const state = {};

    window.addEventListener('keyup', (e) => state[e.key] = false);
    window.addEventListener('keydown', (e) => state[e.key] = true);

    return (key) => state.hasOwnProperty(key) && state[key] || false;
})();

You can then check if a key is pressed with is_key_down('ArrowLeft').

Intolerance answered 12/2, 2018 at 16:18 Comment(0)
I
2
/*
Tracks what keys are currently down on the keyboard
*/

function keyboard_module(onUpdate){
    var kb = {};
    var unicode_mapping = {};
    document.onkeydown = function(e){
        var unicode=e.charCode? e.charCode : e.keyCode
        var key = getKey(unicode);
        kb[key] = true;
        if(onUpdate){
            onUpdate(kb);
        }
    }

    document.onkeyup = function(e){
        var unicode=e.charCode? e.charCode : e.keyCode
        var key = getKey(unicode);
        delete kb[key];
        if(onUpdate){
            onUpdate(kb);
        }
    }

    function getKey(unicode){
        if(unicode_mapping[unicode]){
            var key = unicode_mapping[unicode];
        }else{
            var key= unicode_mapping[unicode] = String.fromCharCode(unicode);
        }
        return key;
    }
    return kb;
}

function testing(kb){
    console.log('These are the down keys', kb);
}


var keyboard = keyboard_module(testing);

....
//somewhere else in the code
if(keyboard['K']){/*do something special */}
Istic answered 11/3, 2014 at 0:41 Comment(1)
Not sure if String.fromCharCode(unicode); is a fast lookup or not, so that is why I have unicode_mapping object. This might be something to pull out to trim down this code a bit if it is ultrafast. Since this will be called repeatedly for key downs, speed is important, hence why I pessimistically added the mapping.Istic
S
2

I scanned the above answers and the proposed keydown/keyup approach works only under special circumstances. If the user alt-tabs away, or uses a key gesture to open a new browser window or tab, then a keydown will be registered, which is fine, because at that point it's impossible to tell if the key is something the web app is monitoring, or is a standard browser or OS shortcut. Coming back to the browser page, it'll still think the key is held, though it was released in the meantime. Or some key is simply kept held, while the user is switching to another tab or application with the mouse, then released outside our page.

Modifier keys (Shift etc.) can be monitored via mousemove etc. assuming that there is at least one mouse interaction expected when tabbing back, which is frequently the case.

For most all other keys (except modifiers, Tab, Delete, but including Space, Enter), monitoring keypress would work for most applications - a key held down will continue to fire. There's some latency in resetting the key though, due to the periodicity of keypress firing. Basically, if keypress doesn't keep firing, then it's possible to rule out most of the keys. This, combined with the modifiers is pretty airtight, though I haven't explored what to do with Tab and Backspace.

I'm sure there's some library out there that abstracts over this DOM weakness, or maybe some DOM standard change took care of it, since it's a rather old question.

Slushy answered 1/9, 2018 at 11:10 Comment(1)
keypress is now deprecated. It doesn't appear to work at all on Chrome.Lebanon
A
1

Other people have asked this kind of question before (though I don't see any obvious dupes here right now).

I think the answer is that the keydown event (and its twin keyup) are all the info you get. Repeating is wired pretty firmly into the operating system, and an application program doesn't get much of an opportunity to query the BIOS for the actual state of the key.

What you can do, and perhaps have to if you need to get this working, is to programmatically de-bounce the key. Essentially, you can evaluate keydown and keyup yourself but ignore a keyupevent if it takes place too quickly after the last keydown... or essentially, you should delay your response to keyup long enough to be sure there's not another keydown event following with something like 0.25 seconds of the keyup.

This would involve using a timer activity, and recording the millisecond times for previous events. I can't say it's a very appealing solution, but...

Absentminded answered 1/12, 2009 at 20:24 Comment(1)
I was worried that it might come to this.Berkley
M
1

The following code is what I'm using:

var altKeyDownCount = 0;
window.onkeydown = function (e) {
    if (!e) e = window.event;
    if (e.altKey) {
        altKeyDownCount++;
        if (30 < altKeyDownCount) {
            $('.key').removeClass('hidden');
            altKeyDownCount = 0;
        }
        return false;
    }
}

window.onkeyup = function (e) {
    if (!e) e = window.event;
    altKeyDownCount = 0;
    $('.key').addClass('hidden');
}

When the user keeps holding down the Alt key for some time (about 2 seconds), a group of labels (class='key hidden') appears. When the Alt key is released, the labels disappear. jQuery and Bootstrap are both used.

Moguel answered 25/8, 2015 at 5:31 Comment(1)
and what happens if "Tab" is pressed while Alt is down?Virginity
C
1

I know this is very old question, however there is a very lightweight (~.5Kb) JavaScript library that effectively "patches" the inconsistent firing of keyboard event handlers when using the DOM API.

The library is Keydrown.

Here's the operative code sample that has worked well for my purposes by just changing the key on which to set the listener:

kd.P.down(function () {
  console.log('The "P" key is being held down!');
});

kd.P.up(function () {
  console.clear();
});

// This update loop is the heartbeat of Keydrown
kd.run(function () {
  kd.tick();
});

I've incorporated Keydrown into my client-side JavaScript for a proper pause animation in a Red Light Green Light game I'm writing. You can view the entire game here. (Note: If you're reading this in the future, the game should be code complete and playable :-D!)

I hope this helps.

Cumulation answered 8/1, 2018 at 2:11 Comment(0)
G
1

This works in Firefox and Chrome.

I had a need to open a special html file locally (by pressing Enter when the file is selected in the file explorer in Windows), either just for viewing the file or for editing it in a special online editor.

So I wanted to distinguish between these two options by holding down the Ctrl-key or not, while pressing Enter.

As you all have understood from all the answers here, this seems to be not really possible, but here is a way that mimics this behaviour in a way that was acceptable for me.

The way this works is like this:

If you hold down the Ctrl-key when opening the file then a keydown event will never fire in the javascript code. But a keyup event will fire (when you finally release the Ctrl-key). The code captures that.

The code also turns off keyevents (both keyup and keydown) as soon as one of them occurs. So if you press the Ctrl-key after the file has opened, nothing will happen.

window.onkeyup = up;
window.onkeydown = down;
function up(e) {
  if (e.key === 'F5') return; // if you want this to work also on reload with F5.

  window.onkeyup = null;
  window.onkeyup = null;
  if (e.key === 'Control') {
    alert('Control key was released. You must have held it down while opening the file, so we will now load the file into the editor.');
  }         
}
function down() {
  window.onkeyup = null;
  window.onkeyup = null;
}
Ginter answered 19/8, 2020 at 10:32 Comment(0)
S
1

For special keys like CONTROL and SHIFT, you can use getModifierState(). This doesn't rely on OnKeyDown and OnKeyUp that only work if your current page is in focus when the key was initially pressed.

  function myFunction(event) {
    let x = event.getModifierState("Shift");
    document.getElementById("demo").innerHTML = "Pressing the shift key: " + x;
  }
  <!DOCTYPE html>
  <html>
  <body>

  <h1>Is the Shift Key Pressed?</h1>

  <p>Write some text in the input field, then press down the Shift key and write some more text in the input field:</p>

  <input type="text" size="40" onkeydown="myFunction(event)">

  <p id="demo"></p>

  </body>
  </html>
Skatole answered 8/1 at 19:44 Comment(0)
O
0

I know it's to late, but I have a lightweight (398 bytes) script that returns if a key is being pressed: https://github.com/brunoinds/isKeyPressed

if (KeyPressing.isKeyPressed(13)){ //Pass the keyCode integer as parameter
     console.log('The Enter key is being pressed!')
  }else{
     console.log('The Enter key is NOT being pressed!')
  }

You can even set a interval to check if the key is being pressed:

setInterval(() => {
    if (KeyPressing.isKeyPressed(13)){
        console.log('The Enter key is being pressed!')
    }else{
        console.log('The Enter key is NOT being pressed!')
    }
  }, 1000) //Update data every 1000ms (1 second)
Ora answered 8/2, 2021 at 1:33 Comment(2)
This relies on keeping track of keydown/keyup. As discussed in other answers, this isn't entirely reliable because the user might release the key while the window or tab is out of focus (think Alt+Tab or Ctrl+PgUp/PgDown). You can mitigate this by resetting the state on blur, but it will never be perfectOnder
Also be aware of some browser wonkiness in how these events are handled due to the nature of the event loop. The event handler for keydown might be called before the one for keyupOnder
W
0

I had good luck detecting if a key was held down by inspecting the keyboard event's repeat property.

If you run the code snippet and hold down a key while filling in the text input, you should see it reflected in the output.

Presumable you could use these event handlers to save off the repeating key somewhere that other code could check at its own leisure.

const input = document.getElementById('input'),
  output = document.getElementById('output');

input.addEventListener('keydown', event => {
  if (event.repeat) {
    output.value = event.key;
  }
});

input.addEventListener('keyup', event => {
  output.value = '';
});
<p>
  <label for="input">Text input:</label>
  <input id="input" />
</p>
<p>
  Repeating key = "<output id="output" for="input"></output>"
</p>
Wynd answered 11/4, 2022 at 18:6 Comment(0)
C
0

KeyboardEvent object describes a single interaction between the user and a key (or combination of a key with modifier keys) on the keyboard

KeyboardEvent.shiftKey: is a boolean value that indicates if the shift key was pressed (true) or not (false)

KeyboardEvent.ctrlKey: is a boolean value that indicates if the control key was pressed (true) or not (false)

KeyboardEvent.altKey: is a boolean value that indicates if the alt key (Option or ⌥ on macOS) was pressed (true) or not (false)

Example:

<html>
<head>
<title>shiftKey example</title>

<script type="text/javascript">

function showChar(e){
  alert(
    "Key Pressed: " + String.fromCharCode(e.charCode) + "\n"
    + "charCode: " + e.charCode + "\n"
    + "SHIFT key pressed: " + e.shiftKey + "\n"
    + "ALT key pressed: " + e.altKey + "\n"
    + "CTRL key pressed: " + e.ctrlKey + "\n"
  );
}

</script>
</head>

<body onkeypress="showChar(event);">
<p>Press any character key, with or without holding down
 the SHIFT key.<br />
You can also use the SHIFT key together with the ALT key.</p>
</body>
</html>
Cockburn answered 15/6, 2022 at 11:34 Comment(0)
S
0

One easy way is to monitor and save the key states by listening to keypresses.

Many other answers don't handle those situations where a keyboard shortcut opens a browser popup or the website loses focus in some other way. In that case, the webapp thinks the key is pressed when it actually was already released.

To make sure, the states are updated correctly, you can listen for more events and update the states accordingly. This way, you can easily put event types in that make sense for your specific use case.

let shiftPressed = false;
let altPressed = false;
let ctrlPressed = false;

["keyup", "keydown", "mousedown", "mouseup", "touchstart", "touchend", "touchcancel", "mouseleave"].forEach((sType)=>{
    window.addEventListener(sType, function(e){
        shiftPressed = e.shiftKey;
        altPressed = e.altKey;
        ctrlPressed = e.ctrlKey;
    }, true);
});

Beware: The true parameter is important, because you want this event to be handled before it reaches other events further down the DOM tree.

Spaak answered 25/11, 2023 at 11:23 Comment(1)
These specific event types will not work for all keys (like letters), but I'm assuming most of the time we need this for shift, ctrl and alt keys. In other scenarios simply choose different event types.Spaak

© 2022 - 2024 — McMap. All rights reserved.