Jak wykryć, czy wiele klawiszy jest naciskanych jednocześnie za pomocą JavaScript?

173

Próbuję stworzyć silnik gry JavaScript i napotkałem ten problem:

  • Kiedy naciskam, SPACEpostać skacze.
  • Kiedy naciskam, postać przesuwa się w prawo.

Problem polega na tym, że kiedy naciskam w prawo, a następnie naciskam spację, postać podskakuje, a następnie przestaje się poruszać.

Używam tej keydownfunkcji, aby nacisnąć klawisz. Jak mogę sprawdzić, czy naciśnięto kilka klawiszy jednocześnie?

XCS
źródło
3
Oto demonstracja strony internetowej, która automatycznie drukuje listę wszystkich naciśniętych klawiszy: stackoverflow.com/a/13651016/975097
Anderson Green

Odpowiedzi:

327

Uwaga: kod keyCode jest teraz przestarzały.

Wykrywanie wielokrotnych naciśnięć klawiszy jest łatwe, jeśli zrozumiesz tę koncepcję

Sposób, w jaki to robię, wygląda następująco:

var map = {}; // You could also use an array
onkeydown = onkeyup = function(e){
    e = e || event; // to deal with IE
    map[e.keyCode] = e.type == 'keydown';
    /* insert conditional here */
}

Ten kod jest bardzo prosty: ponieważ komputer wykonuje tylko jedno naciśnięcie klawisza na raz, tworzona jest tablica, aby śledzić wiele kluczy. Tablicy można następnie użyć do sprawdzenia jednego lub więcej kluczy naraz.

Aby to wyjaśnić, powiedzmy, że naciskasz Ai B, każdy wywołuje keydownzdarzenie, które ustawia map[e.keyCode]wartość e.type == keydown, co daje wartość true lub false . Teraz oba map[65]i map[66]są ustawione na true. Kiedy puścisz A, keyupzdarzenie zostaje wyzwolone, powodując, że ta sama logika określa przeciwny wynik dla map[65](A), który jest teraz fałszywy , ale ponieważ map[66](B) jest nadal „w dół” (nie wywołał zdarzenia klucza), pozostaje prawdą .

mapArray, dzięki obu imprez, wygląda następująco:

// keydown A 
// keydown B
[
    65:true,
    66:true
]
// keyup A
// keydown B
[
    65:false,
    66:true
]

Możesz teraz zrobić dwie rzeczy:

A) Rejestrator kluczy ( przykład ) można utworzyć jako odniesienie na później, gdy chcesz szybko znaleźć jeden lub więcej kodów kluczy. Zakładając, że zdefiniowałeś element html i wskazałeś na niego zmienną element.

element.innerHTML = '';
var i, l = map.length;
for(i = 0; i < l; i ++){
    if(map[i]){
        element.innerHTML += '<hr>' + i;
    }
}

Uwaga: możesz łatwo pobrać element według jego idatrybutu.

<div id="element"></div>

Tworzy to element html, do którego można łatwo odwołać się w javascript za pomocą element

alert(element); // [Object HTMLDivElement]

Nie musisz go nawet używać document.getElementById()ani $()chwytać. Jednak ze względu na kompatybilność $()szerzej zalecane jest używanie jQuery .

Po prostu upewnij się, że tag skryptu znajduje się po treści kodu HTML. Wskazówka dotycząca optymalizacji : większość znanych witryn umieszcza tag script po tagu body w celu optymalizacji. Dzieje się tak, ponieważ znacznik skryptu blokuje ładowanie dalszych elementów do czasu zakończenia pobierania skryptu. Umieszczenie go przed treścią umożliwia wcześniejsze załadowanie treści.

B (gdzie leży twoje zainteresowanie) Możesz sprawdzić jeden lub więcej kluczy w tym samym czasie, w którym /*insert conditional here*/był, weź ten przykład:

if(map[17] && map[16] && map[65]){ // CTRL+SHIFT+A
    alert('Control Shift A');
}else if(map[17] && map[16] && map[66]){ // CTRL+SHIFT+B
    alert('Control Shift B');
}else if(map[17] && map[16] && map[67]){ // CTRL+SHIFT+C
    alert('Control Shift C');
}

Edycja : to nie jest najbardziej czytelny fragment. Czytelność jest ważna, więc możesz spróbować czegoś takiego, aby ułatwić oczy:

function test_key(selkey){
    var alias = {
        "ctrl":  17,
        "shift": 16,
        "A":     65,
        /* ... */
    };

    return key[selkey] || key[alias[selkey]];
}

function test_keys(){
    var keylist = arguments;

    for(var i = 0; i < keylist.length; i++)
        if(!test_key(keylist[i]))
            return false;

    return true;
}

Stosowanie:

test_keys(13, 16, 65)
test_keys('ctrl', 'shift', 'A')
test_key(65)
test_key('A')

Czy to jest lepsze?

if(test_keys('ctrl', 'shift')){
    if(test_key('A')){
        alert('Control Shift A');
    } else if(test_key('B')){
        alert('Control Shift B');
    } else if(test_key('C')){
        alert('Control Shift C');
    }
}

(koniec edycji)


Ten przykład sprawdza CtrlShiftA, CtrlShiftBorazCtrlShiftC

To takie proste :)

Uwagi

Śledzenie kodów kluczy

Zasadniczo dobrą praktyką jest dokumentowanie kodu, zwłaszcza takich rzeczy, jak kody kluczy (np. // CTRL+ENTER), Abyś mógł zapamiętać, jakie to były.

Powinieneś również umieścić kody kluczy w tej samej kolejności, co w dokumentacji ( CTRL+ENTER => map[17] && map[13]NIE map[13] && map[17]). W ten sposób nigdy nie będziesz zdezorientowany, gdy będziesz musiał wrócić i edytować kod.

Gotcha z łańcuchami if-else

Jeśli sprawdzasz kombinacje o różnych ilościach (jak CtrlShiftAltEnteri CtrlEnter), umieść mniejsze kombinacje po większych kombinacjach, w przeciwnym razie mniejsze kombinacje zastąpią większe kombinacje, jeśli są wystarczająco podobne. Przykład:

// Correct:
if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
    alert('Whoa, mr. power user');
}else if(map[17] && map[13]){ // CTRL+ENTER
    alert('You found me');
}else if(map[13]){ // ENTER
    alert('You pressed Enter. You win the prize!')
}

// Incorrect:
if(map[17] && map[13]){ // CTRL+ENTER
    alert('You found me');
}else if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
    alert('Whoa, mr. power user');
}else if(map[13]){ // ENTER
    alert('You pressed Enter. You win the prize!');
}
// What will go wrong: When trying to do CTRL+SHIFT+ENTER, it will
// detect CTRL+ENTER first, and override CTRL+SHIFT+ENTER.
// Removing the else's is not a proper solution, either
// as it will cause it to alert BOTH "Mr. Power user" AND "You Found Me"

Rozumiem: „Ta kombinacja klawiszy ciągle się aktywuje, mimo że nie naciskam klawiszy”

W przypadku alertów lub czegokolwiek, co jest aktywowane w oknie głównym, możesz chcieć włączyć map = []resetowanie tablicy po spełnieniu warunku. Dzieje się tak, ponieważ niektóre rzeczy, na przykład alert(), odciągają fokus od głównego okna i powodują, że zdarzenie „keyup” nie jest wyzwalane. Na przykład:

if(map[17] && map[13]){ // CTRL+ENTER
    alert('Oh noes, a bug!');
}
// When you Press any key after executing this, it will alert again, even though you 
// are clearly NOT pressing CTRL+ENTER
// The fix would look like this:

if(map[17] && map[13]){ // CTRL+ENTER
    alert('Take that, bug!');
    map = {};
}
// The bug no longer happens since the array is cleared

Gotcha: ustawienia domyślne przeglądarki

Oto irytująca rzecz, którą znalazłem, z dołączonym rozwiązaniem:

Problem: Ponieważ przeglądarka zwykle ma domyślne działania na kombinacjach klawiszy (np. CtrlDAktywuje okno zakładek lub CtrlShiftCaktywuje skynote na maxthonie), możesz też chcieć dodać return falsepóźniej map = [], aby użytkownicy Twojej witryny nie byli sfrustrowani, gdy „Duplikat pliku” funkcja, CtrlDzamiast tego tworzy zakładki do strony.

if(map[17] && map[68]){ // CTRL+D
    alert('The bookmark window didn\'t pop up!');
    map = {};
    return false;
}

Bez return falseokno zakładek będzie pop-up, ku przerażeniu użytkownika.

Instrukcja return (nowa)

Okay, więc nie zawsze chcesz wyjść z funkcji w tym momencie. Dlatego event.preventDefault()jest tam funkcja. To, co robi, to ustawienie wewnętrznej flagi, która mówi interpreterowi, aby nie zezwalał przeglądarce na wykonanie jej domyślnej akcji. Po tym wykonywanie funkcji jest kontynuowane (natomiast returnnatychmiast opuści funkcję).

Zrozum to rozróżnienie, zanim zdecydujesz, czy użyć return falselube.preventDefault()

event.keyCode jest przestarzałe

Użytkownik SeanVieira wskazał w komentarzach, który event.keyCodejest przestarzały.

Tam podał doskonałą alternatywę event.key:, która zwraca ciąg znaków reprezentujący naciśnięty klawisz, na przykład "a"for Alub "Shift"for Shift.

Poszedłem do przodu i przygotowałem narzędzie do badania wspomnianych strun.

element.onevent vs element.addEventListener

Handlery zarejestrowane za pomocą addEventListenermożna łączyć i wywoływać w kolejności rejestracji, podczas gdy .oneventbezpośrednie ustawienie jest raczej agresywne i zastępuje wszystko, co miałeś wcześniej.

document.body.onkeydown = function(ev){
    // do some stuff
    ev.preventDefault(); // cancels default actions
    return false; // cancels this function as well as default actions
}

document.body.addEventListener("keydown", function(ev){
    // do some stuff
    ev.preventDefault() // cancels default actions
    return false; // cancels this function only
});

.oneventNieruchomość wydaje się przesłaniać wszystko i zachowanie ev.preventDefault()i return false;może być dość nieprzewidywalne.

W obu przypadkach obsługa zarejestrowana za pośrednictwem addEventlistenerwydaje się być łatwiejsza do napisania i uzasadnienia.

Istnieje również attachEvent("onevent", callback)niestandardowa implementacja Internet Explorera, ale jest to przestarzałe i nie dotyczy nawet JavaScript (dotyczy to ezoterycznego języka zwanego JScript ). Byłoby w twoim najlepszym interesie unikanie kodu poliglotowego tak bardzo, jak to możliwe.

Klasa pomocnicza

Aby rozwiązać problem / skargi, napisałem „klasę”, która wykonuje tę abstrakcję ( link wklejania ):

function Input(el){
    var parent = el,
        map = {},
        intervals = {};
    
    function ev_kdown(ev)
    {
        map[ev.key] = true;
        ev.preventDefault();
        return;
    }
    
    function ev_kup(ev)
    {
        map[ev.key] = false;
        ev.preventDefault();
        return;
    }
    
    function key_down(key)
    {
        return map[key];
    }

    function keys_down_array(array)
    {
        for(var i = 0; i < array.length; i++)
            if(!key_down(array[i]))
                return false;

        return true;
    }
    
    function keys_down_arguments()
    {
        return keys_down_array(Array.from(arguments));
    }
    
    function clear()
    {
        map = {};
    }
    
    function watch_loop(keylist, callback)
    {
        return function(){
            if(keys_down_array(keylist))
                callback();
        }
    }

    function watch(name, callback)
    {
        var keylist = Array.from(arguments).splice(2);

        intervals[name] = setInterval(watch_loop(keylist, callback), 1000/24);
    }

    function unwatch(name)
    {
        clearInterval(intervals[name]);
        delete intervals[name];
    }

    function detach()
    {
        parent.removeEventListener("keydown", ev_kdown);
        parent.removeEventListener("keyup", ev_kup);
    }
    
    function attach()
    {
        parent.addEventListener("keydown", ev_kdown);
        parent.addEventListener("keyup", ev_kup);
    }
    
    function Input()
    {
        attach();

        return {
            key_down: key_down,
            keys_down: keys_down_arguments,
            watch: watch,
            unwatch: unwatch,
            clear: clear,
            detach: detach
        };
    }
    
    return Input();
}

Ta klasa nie robi wszystkiego i nie poradzi sobie z każdym możliwym przypadkiem użycia. Nie jestem facetem z biblioteki. Ale do ogólnego użytku interaktywnego powinno być dobrze.

Aby użyć tej klasy, utwórz instancję i wskaż element, z którym chcesz skojarzyć wprowadzanie z klawiatury:

var input_txt = Input(document.getElementById("txt"));

input_txt.watch("print_5", function(){
    txt.value += "FIVE ";
}, "Control", "5");

To spowoduje dołączenie nowego odbiornika wejściowego do elementu z #txt(załóżmy, że jest to obszar tekstowy) i ustawienie punktu obserwacyjnego dla kombinacji klawiszy Ctrl+5. Gdy oba Ctrli 5są wyłączone, "FIVE "zostanie wywołana funkcja zwrotna, którą przekazałeś (w tym przypadku funkcja, która dodaje do obszaru tekstowego). Callback jest powiązany z nazwą print_5, więc aby je usunąć, wystarczy użyć:

input_txt.unwatch("print_5");

Aby odłączyć input_txtod txtelementu:

input_txt.detach();

W ten sposób odśmiecanie może odebrać obiekt ( input_txt), jeśli zostanie wyrzucony, i nie pozostanie stary odbiornik zdarzeń zombie.

Dla dokładności, oto krótkie odniesienie do API klasy, przedstawione w stylu C / Java, abyś wiedział, co zwracają i jakich argumentów oczekują.

Boolean  key_down (String key);

Zwraca truejeśli keyjest wyłączone, w przeciwnym razie false.

Boolean  keys_down (String key1, String key2, ...);

Zwraca, truejeśli wszystkie klucze key1 .. keyNsą wyłączone, w przeciwnym razie false.

void     watch (String name, Function callback, String key1, String key2, ...);

Tworzy "punkt obserwacyjny" taki, że naciśnięcie wszystkich keyNwywoła wywołanie zwrotne

void     unwatch (String name);

Usuwa wspomniany punkt obserwacyjny poprzez jego nazwę

void     clear (void);

Czyści pamięć podręczną „kluczy w dół”. Odpowiednik map = {}powyżej

void     detach (void);

Odłącza detektory ev_kdowni ev_kupod elementu nadrzędnego, umożliwiając bezpieczne pozbycie się instancji

Aktualizacja 2017-12-02 W odpowiedzi na prośbę o opublikowanie tego na github stworzyłem streszczenie .

Aktualizacja 2018-07-21 Od jakiegoś czasu bawię się programowaniem w stylu deklaratywnym, a teraz jest to mój ulubiony: skrzypce , pastebin

Generalnie będzie działać z przypadkami, które chcesz realistycznie (ctrl, alt, shift), ale jeśli musisz uderzyć, powiedzmy, a+ww tym samym czasie, nie byłoby zbyt trudno „połączyć” podejścia w wyszukiwanie wieloprzyciskowe.


Mam nadzieję, że ten dogłębnie wyjaśniony mini blog okazał się pomocny :)

Braden Best
źródło
Właśnie dokonałem dużej aktualizacji tej odpowiedzi! Przykład keyloggera jest bardziej spójny, zaktualizowałem formatowanie, aby sekcja "notatki" była bardziej czytelna i dodałem nową notatkę o return falsevspreventDefault()
Braden Best.
A co z naciśnięciem / przytrzymaniem klawisza z fokusem na dokumencie, a następnie kliknięciem pola adresu URL, a następnie zwolnieniem klawisza. keyup nigdy nie jest uruchamiany, ale klucz jest aktywny, co powoduje, że lista jest niepoprawna. I odwrotnie: naciśnięcie / przytrzymanie klawisza w polu adresu URL, keydown nigdy nie jest odpalane, następnie skup się na dokumencie, a statusu keydown nie ma na liście. Zasadniczo za każdym razem, gdy dokument odzyskuje ostrość, nigdy nie można być pewnym statusu klucza.
user3015682
3
NB: keyCodejest przestarzałe - jeśli przełączysz się na key, otrzymasz rzeczywistą reprezentację znakową klucza, która może być ładna.
Sean Vieira,
1
@SeanVieira Z drugiej strony, możesz też robić dziwne rzeczy w C. Na przykład, czy wiesz, że myString[5]to to samo co 5[myString]i nawet nie da ci ostrzeżenia o kompilacji (nawet z -Wall -pedantic)? Dzieje się tak, ponieważ pointer[offset]notacja pobiera wskaźnik, dodaje przesunięcie, a następnie odwołuje się do wyniku, czyniąc myString[5]to samo, co *(myString + 5).
Braden Best
1
@inorganik czy masz na myśli klasę pomocnika? Czy streszczenia mogą być używane jak repozytoria? Tworzenie całego repozytorium dla małego fragmentu kodu byłoby żmudne. Jasne, podsumuję. Strzelam do dzisiejszego wieczoru. Góra o północy Time -ish
Braden Best
30

Powinieneś użyć zdarzenia keydown , aby śledzić naciśnięte klawisze, i powinieneś użyć zdarzenia keyup , aby śledzić, kiedy klawisze są zwolnione.

Zobacz ten przykład: http://jsfiddle.net/vor0nwe/mkHsU/

(Aktualizacja: odtwarzam kod tutaj, na wypadek bejdy jsfiddle.net :) HTML:

<ul id="log">
    <li>List of keys:</li>
</ul>

... i JavaScript (przy użyciu jQuery):

var log = $('#log')[0],
    pressedKeys = [];

$(document.body).keydown(function (evt) {
    var li = pressedKeys[evt.keyCode];
    if (!li) {
        li = log.appendChild(document.createElement('li'));
        pressedKeys[evt.keyCode] = li;
    }
    $(li).text('Down: ' + evt.keyCode);
    $(li).removeClass('key-up');
});

$(document.body).keyup(function (evt) {
    var li = pressedKeys[evt.keyCode];
    if (!li) {
       li = log.appendChild(document.createElement('li'));
    }
    $(li).text('Up: ' + evt.keyCode);
    $(li).addClass('key-up');
});

W tym przykładzie używam tablicy, aby śledzić, które klawisze są naciskane. W prawdziwej aplikacji możesz chcieć deletekażdego elementu po zwolnieniu skojarzonego z nim klucza.

Zauważ, że chociaż użyłem jQuery, aby ułatwić sobie pracę w tym przykładzie, koncepcja działa równie dobrze podczas pracy w „surowym” JavaScript.

Martijn
źródło
Ale jak myślałem, jest błąd. Jeśli przytrzymasz wciśnięty jeden przycisk, a następnie przełączysz się na inną kartę (lub stracisz ostrość), nadal trzymając przycisk, gdy ponownie skupisz się na rysie, pokaże się, że przycisk jest wciśnięty, nawet jeśli nie jest. : D
XCS
3
@Cristy: wtedy możesz również dodać onblurprocedurę obsługi zdarzeń, która usuwa wszystkie wciśnięte klawisze z tablicy. Gdy stracisz koncentrację, sensowne byłoby ponowne naciśnięcie wszystkich klawiszy. Niestety nie ma odpowiednika JS GetKeyboardState.
Martijn
1
Masz problem z wklejaniem na komputerze Mac (Chrome). Z powodzeniem pobiera keydown 91 (polecenie), keydown 86 (v), ale wtedy tylko kluczuje 91, pozostawiając 86 w dół. Lista klawiszy: w górę: 91, w dół: 86. Wydaje się, że dzieje się tak tylko wtedy, gdy puszczę klawisz polecenia jako drugi - jeśli puszczę go najpierw, poprawnie zarejestruje kluczowanie na obu.
James Alday,
2
Wygląda na to, że naciśnięcie trzech lub więcej klawiszy jednocześnie, przestaje wykrywać kolejne klawisze, dopóki nie podniesiesz jednego. (Testowane w przeglądarce Firefox 22)
Qvcool
1
@JamesAlday Ten sam problem. Najwyraźniej wpływa tylko na klawisz Meta (OS) na komputerach Mac. Zobacz problem nr 3 tutaj: bitspushedaround.com/…
Don McCurdy
20
document.onkeydown = keydown; 

function keydown (evt) { 

    if (!evt) evt = event; 

    if (evt.ctrlKey && evt.altKey && evt.keyCode === 115) {

        alert("CTRL+ALT+F4"); 

    } else if (evt.shiftKey && evt.keyCode === 9) { 

        alert("Shift+TAB");

    } 

}
Eduardo La Hoz Miranda
źródło
1
To było wszystko, czego chciałem, najlepsza odpowiedź
Randall Coding
7

Użyłem w ten sposób (musiałem sprawdzić, gdzie jest wciśnięty Shift + Ctrl):

// create some object to save all pressed keys
var keys = {
    shift: false,
    ctrl: false
};

$(document.body).keydown(function(event) {
// save status of the button 'pressed' == 'true'
    if (event.keyCode == 16) {
        keys["shift"] = true;
    } else if (event.keyCode == 17) {
        keys["ctrl"] = true;
    }
    if (keys["shift"] && keys["ctrl"]) {
        $("#convert").trigger("click"); // or do anything else
    }
});

$(document.body).keyup(function(event) {
    // reset status of the button 'released' == 'false'
    if (event.keyCode == 16) {
        keys["shift"] = false;
    } else if (event.keyCode == 17) {
        keys["ctrl"] = false;
    }
});
Szyk
źródło
5

kto potrzebuje pełnego przykładowego kodu. Dodano Prawo + Lewo

var keyPressed = {};
document.addEventListener('keydown', function(e) {

   keyPressed[e.key + e.location] = true;

    if(keyPressed.Shift1 == true && keyPressed.Control1 == true){
        // Left shift+CONTROL pressed!
        keyPressed = {}; // reset key map
    }
    if(keyPressed.Shift2 == true && keyPressed.Control2 == true){
        // Right shift+CONTROL pressed!
        keyPressed = {};
    }

}, false);

document.addEventListener('keyup', function(e) {
   keyPressed[e.key + e.location] = false;

   keyPressed = {};
}, false);
Reza Ramezanpour
źródło
3

Spraw, aby keydown wywoływał nawet wiele funkcji, przy czym każda funkcja sprawdza określony klawisz i odpowiednio reaguje.

document.keydown = function (key) {

    checkKey("x");
    checkKey("y");
};
AnonimowyGość
źródło
2

Spróbuję dodać keypress Eventobsługę na keydown. Na przykład:

window.onkeydown = function() {
    // evaluate key and call respective handler
    window.onkeypress = function() {
       // evaluate key and call respective handler
    }
}

window.onkeyup = function() {
    window.onkeypress = void(0) ;
}

To tylko ma na celu zilustrowanie wzoru; Nie będę tutaj wchodził w szczegóły (zwłaszcza nie do Eventrejestracji na poziomie 2 + konkretnej przeglądarki ).

Odeślij proszę, czy to pomaga, czy nie.

FK82
źródło
1
To by nie zadziałało: naciśnięcie klawisza nie uruchamia się na wielu klawiszach, które wyzwalają klawisze w dół i klawisz . Ponadto nie wszystkie przeglądarki wielokrotnie wyzwalają zdarzenia keydown.
Martijn
Quirksmode mówi, że się mylisz: quirksmode.org/dom/events/keys.html . Ale nie będę się z tym kłócił, ponieważ nie przetestowałem mojej propozycji.
FK82,
Cytat z tej strony: „Gdy użytkownik naciska klawisze specjalne, takie jak klawisze strzałek, przeglądarka NIE powinna uruchamiać zdarzeń związanych z naciśnięciem klawisza” . Jeśli chodzi o powtórzenia, to Opera i Konqueror nie robią tego poprawnie.
Martijn
2

Jeśli jeden z wciśniętych klawiszy to Alt / Crtl / Shift, możesz użyć tej metody:

document.body.addEventListener('keydown', keysDown(actions) );

function actions() {
   // do stuff here
}

// simultaneous pressing Alt + R
function keysDown (cb) {
  return function (zEvent) {
    if (zEvent.altKey &&  zEvent.code === "KeyR" ) {
      return cb()
    }
  }
}
Michael Lester
źródło
2
    $(document).ready(function () {
        // using ascii 17 for ctrl, 18 for alt and 83 for "S"
        // ctr+alt+S
        var map = { 17: false, 18: false, 83: false };
        $(document).keyup(function (e) {
            if (e.keyCode in map) {
                map[e.keyCode] = true;
                if (map[17] && map[18] && map[83]) {
                    // Write your own code here, what  you want to do
                    map[17] = false;
                    map[18] = false;
                    map[83] = false;
                }
            }
            else {
                // if u press any other key apart from that "map" will reset.
                map[17] = false;
                map[18] = false;
                map[83] = false;
            }
        });

    });
Prosun Chakraborty
źródło
Dziękuję za Twój wkład. spróbuj nie tylko kod pocztowy, dodaj wyjaśnienie.
Tim Rutter
2

Nie jest to metoda uniwersalna, ale w niektórych przypadkach jest przydatna. Jest to przydatne w przypadku kombinacji takich jak CTRL+ somethinglub Shift+ somethinglub CTRL+ Shift+ somethingitp.

Przykład: Jeśli chcesz wydrukować stronę za pomocą CTRL+ P, po pierwszym naciśnięciu klawisza zawsze CTRLnastępuje P. To samo z CTRL+ S, CTRL+ Ui innymi kombinacjami.

document.addEventListener('keydown',function(e){
      
    //SHIFT + something
    if(e.shiftKey){
        switch(e.code){

            case 'KeyS':
                console.log('Shift + S');
                break;

        }
    }

    //CTRL + SHIFT + something
    if(e.ctrlKey && e.shiftKey){
        switch(e.code){

            case 'KeyS':
                console.log('CTRL + Shift + S');
                break;

        }
    }

});

Jakub Muda
źródło
1
case 65: //A
jp = 1;
setTimeout("jp = 0;", 100);

if(pj > 0) {
ABFunction();
pj = 0;
}
break;

case 66: //B
pj = 1;
setTimeout("pj = 0;", 100);

if(jp > 0) {
ABFunction();
jp = 0;
}
break;

Wiem, że nie jest to najlepszy sposób.

Anonimowy
źródło
-1
Easiest, and most Effective Method

//check key press
    function loop(){
        //>>key<< can be any string representing a letter eg: "a", "b", "ctrl",
        if(map[*key*]==true){
         //do something
        }
        //multiple keys
        if(map["x"]==true&&map["ctrl"]==true){
         console.log("x, and ctrl are being held down together")
        }
    }

//>>>variable which will hold all key information<<
    var map={}

//Key Event Listeners
    window.addEventListener("keydown", btnd, true);
    window.addEventListener("keyup", btnu, true);

    //Handle button down
      function btnd(e) {
      map[e.key] = true;
      }

    //Handle Button up
      function btnu(e) {
      map[e.key] = false;
      }

//>>>If you want to see the state of every Key on the Keybaord<<<
    setInterval(() => {
                for (var x in map) {
                    log += "|" + x + "=" + map[x];
                }
                console.log(log);
                log = "";
            }, 300);
Flyingwizard
źródło