¿Comprobar si una tecla está presionada?

94

¿Hay alguna forma de detectar si una clave está actualmente inactiva en JavaScript?

Sé sobre el evento "keydown", pero eso no es lo que necesito. Algún tiempo DESPUÉS de presionar la tecla, quiero poder detectar si todavía está presionada.

PD: El mayor problema parece ser que después de un período de tiempo la tecla comienza a repetirse, disparando eventos de activación y desactivación de teclas como un demonio. Con suerte, solo hay una función isKeyDown (clave) simple, pero si no, este problema deberá superarse / solucionarse.

Daniel X Moore
fuente
6
Un problema común con las respuestas que veo aquí es que si mantiene presionada una tecla, luego cambia de pestaña o cambia el enfoque, suelta la tecla y luego vuelve a cambiar, el código creerá que la tecla está presionada hasta que la presione de nuevo o la mueva el mouse sobre la página. :-(
Eric Mickelsen

Respuestas:

74

¿Hay alguna forma de detectar si una clave está actualmente inactiva en JavaScript?

No La única posibilidad está vigilando cada uno keyupy el keydowny recordar.

después de un período de tiempo, la tecla comienza a repetirse, disparando eventos de keydown y keyup como un demonio.

No debería. Definitivamente se keypressrepetirá, y en muchos navegadores también se repetirá keydown, pero si se keyuprepite, es un error.

Desafortunadamente, no es un error completamente inaudito: en Linux, Chromium y Firefox (cuando se ejecuta bajo GTK +, que está en distribuciones populares como Ubuntu) ambos generan secuencias repetidas de keyup-keypress-keydown para las teclas retenidas, que son imposibles de distinguir de alguien que aprieta la tecla muy rápido.

bobince
fuente
14
Usted, señor, es un caballero y un erudito. Chromium y Firefox en Ubuntu son mi entorno de desarrollo principal, por lo que eso explica con precisión el problema que he estado viendo. Con suerte, mejorará, de lo contrario, esa solución de pirateo del temporizador podría ser la única solución.
Daniel X Moore
3
Sí, es frustrante que no haya avances en esto. Consulte bugs.launchpad.net/ubuntu/+bug/369880 . Estoy escribiendo un juego de navegador y mi solución por el momento es ceñirme a las teclas modificadoras (shift, ctrl, etc.) que no se repiten en absoluto.
Bobince el
2
No, es posible distinguirlos de las pulsaciones de teclas repetidas genuinas por la falta de keyupeventos correspondientes .
mako
4
¿Sigue siendo así, 8 años después? Es posible que sea necesario actualizar esta respuesta.
Marco Lavagnino
3
ayuda de análisis: (Linux && (Chromium || (Firefox && GTK +)))
bobince
134

Además de usar keyupy los keydownoyentes para rastrear cuándo una tecla baja y vuelve a subir, en realidad hay algunas propiedades que le indican si ciertas teclas están inactivas.

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*/}
}

Esta están disponibles en todos los objetos de eventos generados navegador, tales como los de keydown, keyupy keypress, por lo que no tiene que utilizar mousemove.

Intenté generar mis propios objetos de evento con document.createEvent('KeyboardEvent')y document.createEvent('KeyboardEvent')y buscando e.shiftKeyy tal, pero no tuve suerte.

Estoy usando Chrome 17 en Mac

Devin G Rhode
fuente
Estoy usando esto, tanto en navegadores nuevos como antiguos, incluso en HTA
Jakob Sternberg
1
¿Hay alguna manera de implementar esta respuesta cuando algún número está actualmente bajo? Probé con if (e.keyCode == 49) {console.log ("1 is down");} pero no funciona :(
Roberto Sepúlveda Bravo
Hola @ RobertoSepúlvedaBravo Robert parece responder tu pregunta sobre la siguiente respuesta. ;)
Mark Odey
En realidad, no debería buscar e.shiftKey en el teclado si se refiere a Shift. Utilice e.shiftKey en, por ejemplo, onclick en su lugar.
maciek
46

Mi solución:

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

Ahora puedo verificar si se presiona alguna tecla en cualquier otro lugar del script marcando

pressedKeys["code of the key"]

Si es cierto, se presiona la tecla.

Robert
fuente
2
Dado que keys ya es una función, un nombre de variable diferente podría ser mejor.
Raven
1
esto no funcionará para detectar si la tecla Alt está presionada o no en todos los casos.
Michael
1
Esto es excelente para detectar arriba / abajo / izquierda / derecha
Jonathan Spiller
11

No creo que haya nada parecido a una función isKeyDown, pero podrías escribir la tuya propia.

Básicamente, cree una matriz cuya longitud sea la cantidad de claves que desea monitorear. Luego, utilizando los eventos keyUp y keyDown de documentos / páginas / controles, actualice la matriz con el estado de esa clave.

Luego escribe una función que verifique si una determinada tecla está presionada y devuelve un 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];
}

Eso debería lograr lo que quieres.

CaídoAvatar
fuente
1
Esto es bueno, y de hecho es parte de la solución, pero no soluciona el error de repetición de teclado que estoy experimentando. Vea la respuesta de bobince.
Daniel X Moore
5
Esta no es una buena solución, ya que estaría escribiendo más y más si. Un "keyList = {};" siendo un objeto acepta "keyList [key] = true;" sin la necesidad de una enumeración o un límite, ya que usa índices / propiedades de cadena y funciona para todas las claves.
SparK
Esto funciona, pero está altamente
diseñado
6

Terminé aquí para verificar si ya había algo integrado en el navegador, pero parece que no lo hay. Esta es mi solución (muy similar a la respuesta de Robert):

"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;
})();

Luego puede verificar si se presiona una tecla con is_key_down('ArrowLeft').

antonagestam
fuente
1

Otras personas han hecho este tipo de preguntas antes (aunque no veo ningún engaño obvio aquí en este momento).

Creo que la respuesta es que el keydownevento (y su gemelo keyup) son toda la información que obtienes. La repetición está conectada con bastante firmeza al sistema operativo, y un programa de aplicación no tiene mucha oportunidad de consultar el BIOS para conocer el estado real de la clave.

Lo que puede hacer, y quizás tenga que hacerlo si necesita que esto funcione, es eliminar el rebote de la clave mediante programación. En esencia, se puede evaluar keydowny keyupusted mismo, pero ignorar un keyupevento si se produce demasiado rápido después de la última keydown... o esencialmente, se debe retrasar su respuesta a keyuptiempo suficiente para asegurarse de que no hay otro keydownsuceso siguiente con algo así como 0,25 segundos de la keyup.

Esto implicaría usar una actividad de temporizador y registrar los tiempos de milisegundos para eventos anteriores. No puedo decir que sea una solución muy atractiva, pero ...

Carl Smotricz
fuente
2
Me preocupaba que pudiera llegar a esto.
Daniel X Moore
1
/*
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 */}
RobKohr
fuente
No estoy seguro si String.fromCharCode (unicode); es una búsqueda rápida o no, por eso tengo el objeto unicode_mapping. Esto podría ser algo para extraer para recortar un poco este código si es ultrarrápido. Dado que esto se llamará repetidamente para key downs, la velocidad es importante, por eso agregué pesimistamente el mapeo.
RobKohr
1

El siguiente código es lo que estoy usando:

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');
}

Cuando el usuario mantiene presionada la tecla Alt durante algún tiempo (aproximadamente 2 segundos), aparece un grupo de etiquetas (class = 'key hidden'). Cuando se suelta la tecla Alt, las etiquetas desaparecen. Se utilizan jQuery y Bootstrap.

Johnny
fuente
y ¿qué sucede si se presiona "Tab" mientras Alt está presionada?
Michael
1

Sé que esta es una pregunta muy antigua, sin embargo, hay una biblioteca de JavaScript muy liviana (~ .5Kb) que efectivamente "parchea" la activación inconsistente de los controladores de eventos del teclado cuando se usa la API DOM.

La biblioteca es Keydrown .

Aquí está el ejemplo de código operativo que ha funcionado bien para mis propósitos con solo cambiar la clave en la que configurar el oyente:

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();
});

He incorporado Keydrown en mi JavaScript del lado del cliente para una animación de pausa adecuada en un juego de Red Light Green Light que estoy escribiendo. Puedes ver el juego completo aquí . (Nota: si estás leyendo esto en el futuro, el código del juego debería ser completo y jugable :-D!)

Espero que esto ayude.

buildpax
fuente
1

Recorrí las respuestas anteriores y la propuesta keydown/ keyupenfoque funciona sólo en circunstancias especiales. Si el usuario cambia de pestaña o utiliza un gesto de tecla para abrir una nueva ventana o pestaña del navegador,keydown se registrará una, lo cual está bien, porque en ese momento es imposible saber si la tecla es algo que la aplicación web está monitoreando , o es un navegador estándar o un acceso directo al sistema operativo. Volviendo a la página del navegador, todavía pensará que la clave está retenida, aunque se soltó mientras tanto. O simplemente se mantiene presionada alguna tecla, mientras el usuario cambia a otra pestaña o aplicación con el mouse, y luego se suelta fuera de nuestra página.

Las teclas modificadoras ( Shiftetc.) se pueden monitorear a través de, mousemoveetc., asumiendo que se espera al menos una interacción del mouse al volver a tabular, lo que suele ser el caso.

Durante la mayor parte todas las demás teclas (excepto modificadores, Tab, Delete, pero incluyendo Space, Enter), la vigilancia keypresspodría funcionar para la mayoría de aplicaciones - una clave presionado, se seguirá el fuego. Sin embargo, hay cierta latencia al restablecer la clave, debido a la periodicidad del keypressdisparo. Básicamente, si keypressno sigue disparando, es posible descartar la mayoría de las teclas. Esto, combinado con los modificadores, es bastante hermético, aunque no he explorado qué hacer con Taby Backspace.

Estoy seguro de que hay alguna biblioteca que abstrae esta debilidad de DOM, o tal vez algún cambio estándar de DOM se encargó de ello, ya que es una pregunta bastante antigua.

Robert Monfera
fuente
la pulsación de teclas ahora está en desuso. No parece funcionar en absoluto en Chrome.
eadsjr
0

Mira esta respuesta y usa onkeyupy onkeydown. Aquí hay información más específica sobre esos eventos.

Claudiu
fuente
1
El enlace que cita es para los eventos del mouse, donde la repetición automática no es un problema.
Carl Smotricz
las teclas arriba y abajo no se repetirán. poder presionar la tecla.
Claudiu
bueno, incluso si lo hacen, me estaba imaginando algo como la solución de TJMonk15, simplemente no quería escribirlo
Claudiu
1
La redacción de esas dos preguntas es exactamente la misma. ¿Extraña coincidencia o algo más?
Mitch Lindgren
2
@Mitch: wow ... eso es bastante increíble. No sé por qué alguien haría dos cuentas para hacer la misma pregunta. o más probablemente esta persona simplemente copió la otra pregunta y la adaptó para claves
Claudiu
0

Esto funciona en Firefox y Chrome.

Tenía la necesidad de abrir un archivo html especial localmente (presionando Entercuando el archivo está seleccionado en el explorador de archivos en Windows), ya sea solo para ver el archivo o para editarlo en un editor en línea especial.

Así que quería distinguir entre estas dos opciones manteniendo presionada la Ctrltecla -o no, mientras presiona Enter.

Como todos han entendido por todas las respuestas aquí, esto parece no ser realmente posible, pero aquí hay una forma que imita este comportamiento de una manera que fue aceptable para mí.

La forma en que esto funciona es así:

Si mantiene presionada la Ctrltecla -cuando abre el archivo, nunca se activará un evento de keydown en el código javascript. Pero se activará un evento de activación de teclas (cuando finalmente suelte la Ctrltecla-). El código captura eso.

El código también desactiva los eventos de tecla (tanto de activación como de desactivación) tan pronto como ocurre uno de ellos. Entonces, si presionas elCtrl tecla -después de que el archivo se haya abierto, no sucederá nada.

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;
}
Magnus
fuente
-3
$('#mytextbox').keydown(function (e) {
            if (e.keyCode == 13) {
                if (e.altKey) {
                    alert("alt is pressed");
                }
            }
 });

si presiona alt + enter, verá la alerta.

Mokarom
fuente