Controlla se una chiave è abbassata?


91

C'è un modo per rilevare se una chiave è attualmente inattivo in JavaScript?

So dell'evento "keydown", ma non è quello che mi serve. Qualche tempo DOPO che il tasto è stato premuto, voglio essere in grado di rilevare se è ancora premuto.

PS Il problema più grande sembra essere che dopo un certo periodo di tempo la chiave inizia a ripetersi, attivando eventi di keydown e keyup come un demone. Si spera che ci sia solo una semplice funzione isKeyDown (chiave), ma in caso contrario sarà necessario superare / aggirare il problema.


6
Un problema comune con le risposte che vedo qui è che se si tiene premuto un tasto, quindi si cambia scheda o si sposta lo stato attivo, si solleva il tasto e si torna indietro, il codice crederà che il tasto sia premuto finché non lo si preme di nuovo o si sposta il mouse sulla pagina. :-(
Eric Mickelsen

Risposte:


71

C'è un modo per rilevare se una chiave è attualmente inattivo in JavaScript?

No. L'unica possibilità sta monitorando ogni keyupe keydowne ricordando.

dopo un certo periodo di tempo la chiave inizia a ripetersi, attivando eventi di keydown e keyup come un demone.

Non dovrebbe. Sarai sicuramente keypressripetuto e in molti browser sarai anche ripetuto keydown, ma se si keyupripete, è un bug.

Sfortunatamente non è un bug del tutto inaudito: su Linux, Chromium e Firefox (quando viene eseguito con GTK +, che è in distribuzioni popolari come Ubuntu) entrambi generano sequenze ripetute di keyup-keypress-keydown per i tasti tenuti, che sono impossibili da distinguere da qualcuno che martella la chiave molto velocemente.


14
Lei è un gentiluomo e uno studioso. Chromium e Firefox su Ubuntu sono il mio ambiente di sviluppo principale, quindi questo spiega accuratamente il problema che ho riscontrato. Si spera che migliorerà, altrimenti quella soluzione di hacking del timer potrebbe essere l'unica soluzione alternativa.
Daniel X Moore

3
Sì, è frustrante che non ci siano progressi su questo. Vedi bugs.launchpad.net/ubuntu/+bug/369880 . Sto scrivendo un browser game e la mia soluzione alternativa per il momento è di attenermi ai tasti di modifica (shift, ctrl, ecc.) Che non si ripetono affatto.
bobince

2
No, è possibile distinguerli da autentiche pressioni di tasti ripetute per la loro mancanza di keyupeventi corrispondenti .
mako

4
è ancora così, 8 anni dopo? Potrebbe essere necessario aggiornare questa risposta.
Marco Lavagnino

3
aiuto per l'analisi: (Linux && (Chromium || (Firefox && GTK +)))
bobince

134

Oltre a utilizzare keyupe keydownlistener per tenere traccia di quando la chiave scende e torna su, in realtà ci sono alcune proprietà che ti dicono se alcuni tasti sono giù.

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

Questo sono disponibili su tutti gli oggetti evento del browser generato, come quelli da keydown, keyupe keypress, in modo da non dover usare MouseMove.

Ho provato a generare i miei oggetti evento con document.createEvent('KeyboardEvent')e document.createEvent('KeyboardEvent')e cercando e.shiftKeye simili, ma non ho avuto fortuna.

Utilizzo Chrome 17 su Mac


Lo sto usando, sia nei nuovi che nei vecchi browser, anche in HTA
Jakob Sternberg

1
C'è un modo per implementare questa risposta quando un numero è attualmente in esaurimento? Ho provato con if (e.keyCode == 49) {console.log ("1 is down");} ma non funziona :(
Roberto Sepúlveda Bravo

Hey @ RobertoSepúlvedaBravo Robert sembra rispondere alla tua domanda nella prossima risposta. ;)
Mark Odey

In realtà non dovresti cercare e.shiftKey su keyup se intendi up di Shift. Utilizzare invece e.shiftKey, ad esempio, onclick.
maciek

45

La mia soluzione:

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

Ora posso verificare se viene premuto un tasto in qualsiasi altro punto dello script controllando

pressedKeys["code of the key"]

Se è vero, viene premuto il tasto.


2
Poiché le chiavi sono già una funzione, un nome di variabile diverso potrebbe essere migliore.
Raven

1
questo non funzionerà per rilevare se il tasto Alt è premuto o meno in tutti i casi.
Michael

1
Questo è ottimo per rilevare su / giù / sinistra / destra
Jonathan Spiller

11

Non credo che esista qualcosa come una funzione isKeyDown, ma potresti scriverne una tua.

Fondamentalmente, crea un array la cui lunghezza è il numero di chiavi che desideri monitorare. Quindi, utilizzando gli eventi documenti / pagine / controlli keyUp e keyDown, aggiorna l'array con lo stato di quella chiave.

Quindi scrivi una funzione che controlla se un determinato tasto è inattivo e restituisce 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];
}

Questo dovrebbe ottenere ciò che desideri.


1
Questo è buono, e in effetti fa parte della soluzione, ma non risolve il bug che si ripete nel keyup che sto riscontrando. Vedi la risposta di Bobince.
Daniel X Moore

4
Questa non è una buona soluzione perché scriveresti sempre di più se. Un "keyList = {};" essendo un oggetto accetta "keyList [key] = true;" senza la necessità di un'enumerazione o di un limite poiché utilizza indici / proprietà di stringa e funziona per tutte le chiavi.
SparK

5

Sono finito qui per verificare se c'era già qualcosa integrato nel browser, ma sembra che non ci sia. Questa è la mia soluzione (molto simile alla risposta di 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;
})();

È quindi possibile verificare se un tasto viene premuto con is_key_down('ArrowLeft').


1

Altre persone hanno già posto questo tipo di domande (anche se non vedo nessun ovvio stupido qui in questo momento).

Penso che la risposta sia che l' keydownevento (e il suo gemello keyup) sono tutte le informazioni che ottieni. La ripetizione è collegata abbastanza saldamente al sistema operativo e un programma applicativo non ha molte opportunità per interrogare il BIOS per lo stato effettivo della chiave.

Quello che puoi fare, e forse devi farlo se hai bisogno di farlo funzionare, è annullare il rimbalzo della chiave a livello di programmazione. In sostanza, puoi valutare keydowne keyupte stesso ma ignorare un keyupevento se si verifica troppo rapidamente dopo l'ultimo keydown... o essenzialmente, dovresti ritardare la tua risposta keyupabbastanza a lungo da essere sicuro che non ci sia un altro keydownevento successivo con qualcosa come 0,25 secondi di keyup.

Ciò comporterebbe l'utilizzo di un'attività del timer e la registrazione dei tempi in millisecondi per gli eventi precedenti. Non posso dire che sia una soluzione molto interessante, ma ...


2
Ero preoccupato che si potesse arrivare a questo.
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 */}

Non sono sicuro se String.fromCharCode (unicode); è una ricerca veloce o meno, quindi è per questo che ho l'oggetto unicode_mapping. Questo potrebbe essere qualcosa da tirare fuori per ridurre un po 'questo codice se è ultraveloce. Poiché questo verrà chiamato ripetutamente per i key down, la velocità è importante, quindi ho aggiunto pessimisticamente la mappatura.
RobKohr

1

Il codice seguente è quello che sto 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');
}

Quando l'utente continua a tenere premuto il tasto Alt per un po 'di tempo (circa 2 secondi), viene visualizzato un gruppo di etichette (class =' ​​key hidden '). Quando il tasto Alt viene rilasciato, le etichette scompaiono. jQuery e Bootstrap vengono entrambi utilizzati.


e cosa succede se si preme "Tab" mentre Alt è premuto?
Michael,

1

So che questa è una domanda molto vecchia, tuttavia esiste una libreria JavaScript molto leggera (~ .5Kb) che "corregge" efficacemente l'attivazione incoerente dei gestori di eventi della tastiera quando si utilizza l'API DOM.

La libreria è Keydrown .

Ecco l'esempio di codice operativo che ha funzionato bene per i miei scopi semplicemente cambiando la chiave su cui impostare l'ascoltatore:

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

Ho incorporato Keydrown nel mio JavaScript lato client per una corretta animazione di pausa in un gioco Red Light Green Light che sto scrivendo. Puoi vedere l'intero gioco qui . (Nota: se stai leggendo questo in futuro, il gioco dovrebbe essere completo di codice e giocabile :-D!)

Spero che aiuti.


1

Ho analizzato le risposte di cui sopra e l' approccio keydown/ proposto keyupfunziona solo in circostanze speciali. Se l'utente utilizza un tasto alt-tab per aprire una nuova finestra o scheda del browser, keydownverrà registrato un, il che va bene, perché a quel punto è impossibile dire se la chiave è qualcosa che l'app web sta monitorando o è un browser standard o un collegamento del sistema operativo. Tornando alla pagina del browser, penserà ancora che la chiave sia trattenuta, anche se nel frattempo è stata rilasciata. Oppure qualche tasto viene semplicemente tenuto premuto, mentre l'utente passa a un'altra scheda o applicazione con il mouse, quindi rilasciato al di fuori della nostra pagina.

I tasti modificatori ( Shiftecc.) Possono essere monitorati tramite mousemoveecc. Supponendo che ci sia almeno un'interazione con il mouse prevista quando si torna indietro, il che è spesso il caso.

Per la maggior parte tutti gli altri tasti (ad eccezione di modificatori, Tab, Delete, ma compresa Space, Enter), il monitoraggio keypressavrebbe funzionato per la maggior parte delle applicazioni - un tasto premuto continuerà a fuoco. Tuttavia, c'è una certa latenza nel ripristino della chiave, a causa della periodicità di keypressattivazione. Fondamentalmente, se keypressnon si continua a sparare, è possibile escludere la maggior parte delle chiavi. Questo, combinato con i modificatori, è abbastanza ermetico, anche se non ho esplorato cosa fare con Tabe Backspace.

Sono sicuro che ci sono alcune librerie là fuori che astraggono su questa debolezza del DOM, o forse qualche modifica allo standard DOM se ne è occupata, poiché è una domanda piuttosto vecchia.


keypress è ora deprecato. Non sembra funzionare affatto su Chrome.
eadsjr

0

Guarda questa risposta e usa onkeyupe onkeydown. Ecco informazioni più specifiche su questi eventi.


1
Il link che citi è per gli eventi del mouse, dove la ripetizione automatica non è un problema.
Carl Smotricz

key-up e key-down non si ripeteranno. premere il tasto potrebbe.
Claudiu

beh, anche se lo fanno, stavo immaginando qualcosa come la soluzione di TJMonk15, ma non volevo scriverlo
Claudiu

1
La formulazione di queste due domande è esattamente la stessa. Strana coincidenza o qualcosa di più?
Mitch Lindgren

2
@ Mitch: wow ... è davvero incredibile. non so perché qualcuno farebbe due conti per fare la stessa domanda. o più probabilmente questa persona ha semplicemente copiato l'altra domanda e l'ha adattata per le chiavi
Claudiu

0

Funziona in Firefox e Chrome.

Avevo bisogno di aprire un file html speciale in locale (premendo Enterquando il file è selezionato in Esplora file in Windows), sia solo per visualizzare il file o per modificarlo in uno speciale editor online.

Quindi volevo distinguere tra queste due opzioni tenendo premuto il Ctrltasto o meno, mentre si premeva Enter.

Come tutti avete capito da tutte le risposte qui, questo sembra non essere realmente possibile, ma ecco un modo che imita questo comportamento in un modo che era accettabile per me.

Il modo in cui funziona è così:

Se tieni premuto il Ctrltasto -quando apri il file, un evento keydown non si attiverà mai nel codice javascript. Ma un evento keyup si attiverà (quando finalmente rilasci il Ctrltasto -key). Il codice lo cattura.

Il codice disattiva anche gli eventi chiave (sia keyup che keydown) non appena si verifica uno di essi. Quindi se premi il Ctrltasto dopo che il file è stato aperto, non accadrà nulla.

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

-3
$('#mytextbox').keydown(function (e) {
            if (e.keyCode == 13) {
                if (e.altKey) {
                    alert("alt is pressed");
                }
            }
 });

se premi alt + invio, vedrai l'avviso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.