Vérifier si une touche est enfoncée?

91

Existe-t-il un moyen de détecter si une clé est actuellement en panne dans JavaScript?

Je connais l'événement "keydown", mais ce n'est pas ce dont j'ai besoin. Quelques temps APRÈS avoir appuyé sur la touche, je veux être en mesure de détecter si elle est toujours enfoncée.

PS Le plus gros problème semble être qu'après un certain temps, la clé commence à se répéter, déclenchant des événements keydown et keyup comme un démon. J'espère qu'il n'y a qu'une simple fonction isKeyDown (key), mais sinon, ce problème devra être surmonté / contourné.

Daniel X Moore
la source
6
Un problème courant avec les réponses que je vois ici est que si vous maintenez une touche enfoncée, puis changez d'onglet ou changez de focus, laissez la touche monter, puis revenez en arrière, le code croira que la touche est enfoncée jusqu'à ce que vous la pressiez à nouveau ou la déplaciez la souris sur la page. :-(
Eric Mickelsen

Réponses:

71

Existe-t-il un moyen de détecter si une clé est actuellement en panne dans JavaScript?

Nan. La seule possibilité surveille chaque keyupet keydownet se souvenir.

après un certain temps, la clé commence à se répéter, déclenchant des événements keydown et keyup comme un démon.

Ça ne devrait pas. Vous serez certainement keypressrépété, et dans de nombreux navigateurs, vous serez également répété keydown, mais s'il se keyuprépète, c'est un bogue.

Malheureusement, ce n'est pas un bogue complètement inconnu: sous Linux, Chromium et Firefox (lorsqu'il est exécuté sous GTK +, ce qui est dans les distributions populaires telles que Ubuntu), les deux génèrent des séquences de touches répétées pour les touches maintenues, qui sont impossibles à distinguer de quelqu'un qui martèle la clé très rapidement.

bobince
la source
14
Vous, Monsieur, êtes un gentleman et un savant. Chromium et Firefox sur Ubuntu sont mon environnement de développement principal, ce qui explique précisément le problème que j'ai rencontré. Espérons que cela ira mieux, sinon cette solution de piratage de la minuterie pourrait être la seule solution de contournement.
Daniel X Moore
3
Ouais, c'est frustrant qu'il n'y ait pas de progrès à ce sujet. Voir bugs.launchpad.net/ubuntu/+bug/369880 . J'écris un jeu par navigateur et ma solution de contournement pour le moment est de m'en tenir aux touches de modification (shift, ctrl, etc.) qui ne se répètent pas du tout.
bobince
2
Non, il est possible de les distinguer des véritables pressions répétées sur les touches par leur absence d' keyupévénements correspondants .
mako
4
est-ce toujours le cas, 8 ans plus tard? Cette réponse devra peut-être être mise à jour.
Marco Lavagnino
3
aide à l'analyse: (Linux && (Chromium || (Firefox && GTK +)))
bobince
134

En plus d'utiliser keyupet des keydownécouteurs pour suivre quand une touche descend et recule, il existe en fait certaines propriétés qui vous indiquent si certaines touches sont enfoncées.

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

Ce sont disponibles sur tous les objets d'événements générés par navigateur, tels que ceux de keydown, keyupet keypress, donc vous ne devez pas utiliser mousemove.

J'ai essayé de générer mes propres objets événementiels avec document.createEvent('KeyboardEvent')et document.createEvent('KeyboardEvent')et de chercher e.shiftKeyet autres, mais je n'ai pas eu de chance.

J'utilise Chrome 17 sur Mac

Devin G Rhode
la source
J'utilise ceci, dans les navigateurs nouveaux et anciens, même HTA
Jakob Sternberg
1
Existe-t-il un moyen de mettre en œuvre cette réponse lorsqu'un certain nombre est actuellement en panne? J'ai essayé avec if (e.keyCode == 49) {console.log ("1 is down");} mais ne fonctionne pas :(
Roberto Sepúlveda Bravo
Hey @ RobertoSepúlvedaBravo Robert semble répondre à votre question sur la réponse suivante. ;)
Mark Odey
En fait, vous ne devriez pas chercher e.shiftKey au keyup si vous voulez dire en haut de Shift. Utilisez plutôt e.shiftKey sur par exemple onclick.
maciek
45

Ma solution:

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

Je peux maintenant vérifier si une touche est enfoncée ailleurs dans le script en vérifiant

pressedKeys["code of the key"]

Si c'est vrai, la touche est enfoncée.

Robert
la source
2
Comme les touches sont déjà une fonction, un nom de variable différent pourrait être préférable.
Raven
1
cela ne fonctionnera pas pour détecter si la touche Alt est enfoncée ou pas dans tous les cas.
Michael
1
C'est génial pour détecter haut / bas / gauche / droite
Jonathan Spiller
11

Je ne pense pas qu'il existe une fonction isKeyDown, mais vous pouvez écrire la vôtre.

Fondamentalement, créez un tableau dont la longueur correspond au nombre de clés que vous souhaitez surveiller. Ensuite, en utilisant les événements keyUp et keyDown documents / pages / controls, mettez à jour le tableau avec l'état de cette clé.

Ensuite, écrivez une fonction qui vérifie si une certaine touche est enfoncée et renvoie un booléen.

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];
}

Cela devrait accomplir ce que vous voulez.

DéchuAvatar
la source
1
C'est bien, et fait partie de la solution, mais cela ne résout pas le bogue répétitif de keyup que je rencontre. Voir la réponse de bobince.
Daniel X Moore
4
Ce n'est pas une bonne solution car vous écririez de plus en plus de ifs. Un "keyList = {};" étant un objet accepte "keyList [key] = true;" sans avoir besoin d'une énumération ou d'une limite car il utilise des index / propriétés de chaîne et fonctionne pour toutes les clés.
SparK
5

Terminé ici pour vérifier s'il y avait déjà quelque chose de intégré au navigateur, mais il semble que ce ne soit pas le cas. Voici ma solution (très similaire à la réponse 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;
})();

Vous pouvez alors vérifier si une touche est enfoncée avec is_key_down('ArrowLeft').

Antonagestam
la source
1

D'autres personnes ont déjà posé ce genre de question (bien que je ne vois aucune dupe évidente ici pour le moment).

Je pense que la réponse est que l' keydownévénement (et son jumeau keyup) sont toutes les informations que vous obtenez. La répétition est assez fermement connectée au système d'exploitation et un programme d'application n'a pas beaucoup l'occasion d'interroger le BIOS pour connaître l'état réel de la clé.

Ce que vous pouvez faire, et peut-être devoir le faire si vous avez besoin de faire fonctionner cela, est de dé-rebondir la clé par programme. Essentiellement, vous pouvez évaluer keydownet keyupvous - même mais ignorer un keyupévénement s'il se produit trop rapidement après le dernier keydown... ou essentiellement, vous devriez retarder votre réponse keyupsuffisamment longtemps pour être sûr qu'il n'y a pas un autre keydownévénement suivant avec quelque chose comme 0,25 seconde de keyup.

Cela impliquerait d'utiliser une activité de minuterie et d'enregistrer les millisecondes des événements précédents. Je ne peux pas dire que c'est une solution très attrayante, mais ...

Carl Smotricz
la source
2
J'avais peur que cela puisse en arriver là.
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
la source
Je ne sais pas si String.fromCharCode (unicode); est une recherche rapide ou non, c'est pourquoi j'ai un objet unicode_mapping. Cela pourrait être quelque chose à retirer pour réduire un peu ce code s'il est ultra-rapide. Comme cela sera appelé à plusieurs reprises pour les touches, la vitesse est importante, d'où la raison pour laquelle j'ai ajouté le mappage de manière pessimiste.
RobKohr
1

Le code suivant est ce que j'utilise:

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

Lorsque l'utilisateur maintient la touche Alt enfoncée pendant un certain temps (environ 2 secondes), un groupe d'étiquettes (class = 'key hidden') apparaît. Lorsque la touche Alt est relâchée, les étiquettes disparaissent. jQuery et Bootstrap sont tous deux utilisés.

Johnny
la source
et que se passe-t-il si "Tab" est appuyé alors que Alt est en bas?
Michael
1

Je sais que c'est une question très ancienne, mais il existe une bibliothèque JavaScript très légère (~ 0,5 Ko) qui "corrige" efficacement le déclenchement incohérent des gestionnaires d'événements de clavier lors de l'utilisation de l'API DOM.

La bibliothèque est Keydrown .

Voici l'exemple de code opérationnel qui a bien fonctionné pour mes besoins en modifiant simplement la clé sur laquelle définir l'écouteur:

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

J'ai incorporé Keydrown dans mon JavaScript côté client pour une animation de pause appropriée dans un jeu Red Light Green Light que j'écris. Vous pouvez voir l'intégralité du jeu ici . (Remarque: si vous lisez ceci à l'avenir, le jeu devrait être complet et jouable :-D!)

J'espère que ça aide.

buildpax
la source
1

J'ai scanné les réponses ci-dessus et l' approche proposée keydown/ keyupne fonctionne que dans des circonstances spéciales. Si l'utilisateur s'éloigne ou utilise un geste de touche pour ouvrir une nouvelle fenêtre ou un nouvel onglet de navigateur, alors un keydownsera enregistré, ce qui est bien, car à ce stade, il est impossible de dire si la clé est quelque chose que l'application Web surveille , ou est un navigateur standard ou un raccourci du système d'exploitation. En revenant à la page du navigateur, il pensera toujours que la clé est maintenue, bien qu'elle ait été publiée entre-temps. Ou une touche est simplement maintenue enfoncée, pendant que l'utilisateur passe à un autre onglet ou application avec la souris, puis relâchée en dehors de notre page.

Les touches de modification ( Shiftetc.) peuvent être surveillées via mousemoveetc. en supposant qu'au moins une interaction de la souris est attendue lors de la tabulation, ce qui est souvent le cas.

Pour la plupart toutes les autres touches ( à l' exception des modificateurs, Tab, Deletemais y compris Space, Enter), le suivi keypresstravaillerait pour la plupart des applications - une clé maintenue enfoncée continuera à feu. Il y a cependant une certaine latence dans la réinitialisation de la clé, en raison de la périodicité du keypressdéclenchement. Fondamentalement, si le keypresstir ne continue pas, il est possible d'exclure la plupart des clés. Ceci, combiné avec les modificateurs, est assez hermétique, même si je n'ai pas exploré quoi faire avec Tabet Backspace.

Je suis sûr qu'il existe une bibliothèque qui résume cette faiblesse du DOM, ou peut-être qu'une modification de la norme DOM l'a corrigée, car c'est une question plutôt ancienne.

Robert Monfera
la source
keypress est désormais obsolète. Cela ne semble pas du tout fonctionner sur Chrome.
eadsjr le
0

Regardez cette réponse et utilisez onkeyupet onkeydown. Voici des informations plus spécifiques sur ces événements.

Claudiu
la source
1
Le lien que vous citez concerne les événements de souris, où la répétition automatique ne pose pas de problème.
Carl Smotricz
les touches haut et bas ne se répéteront pas. appuyer sur une touche pourrait.
Claudiu
eh bien même s'ils le font, j'imaginais quelque chose comme la solution de TJMonk15, je ne voulais tout simplement pas l'écrire
Claudiu
1
Le libellé de ces deux questions est exactement le même. Bizarre coïncidence, ou quelque chose de plus?
Mitch Lindgren
2
@Mitch: wow ... c'est assez incroyable. Je ne sais pas pourquoi quelqu'un ferait deux comptes pour poser la même question. ou plus probablement, cette personne vient de copier l'autre question et de l'adapter pour les clés
Claudiu
0

Cela fonctionne dans Firefox et Chrome.

J'avais besoin d'ouvrir un fichier html spécial localement (en appuyant sur Enterlorsque le fichier est sélectionné dans l'explorateur de fichiers de Windows), soit juste pour afficher le fichier, soit pour le modifier dans un éditeur en ligne spécial.

J'ai donc voulu faire la distinction entre ces deux options en maintenant la Ctrltouche enfoncée ou non, tout en appuyant sur Enter.

Comme vous l'avez tous compris de toutes les réponses ici, cela ne semble pas vraiment possible, mais voici une manière qui imite ce comportement d'une manière qui était acceptable pour moi.

La façon dont cela fonctionne est comme ceci:

Si vous maintenez la Ctrltouche enfoncée lors de l'ouverture du fichier, un événement keydown ne se déclenchera jamais dans le code javascript. Mais un événement keyup se déclenchera (lorsque vous relâcherez enfin la Ctrltouche -key). Le code capture cela.

Le code désactive également les événements clés (à la fois keyup et keydown) dès que l'un d'eux se produit. Donc, si vous appuyez sur la Ctrltouche après l'ouverture du fichier, rien ne se passera.

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

si vous appuyez sur alt + entrée, vous verrez l'alerte.

Mokarom
la source