Sprawdź, czy klucz jest wyłączony?

93

Czy istnieje sposób na wykrycie, czy klucz jest obecnie wyłączony w JavaScript?

Wiem o wydarzeniu „keydown”, ale nie tego potrzebuję. Jakiś czas PO naciśnięciu klawisza chcę mieć możliwość wykrycia, czy nadal jest wciśnięty.

PS Największym problemem wydaje się być to, że po pewnym czasie klucz zaczyna się powtarzać, odpalając zdarzenia keydown i keyup jak diabeł. Mam nadzieję, że istnieje tylko prosta funkcja isKeyDown (klucz), ale jeśli nie, to ten problem będzie musiał zostać rozwiązany / obejść.

Daniel X Moore
źródło
6
Częstym problemem związanym z odpowiedziami, które tutaj widzę, jest to, że jeśli przytrzymasz klawisz, a następnie zmienisz zakładki lub zmienisz fokus, puść klawisz w górę, a następnie przełączysz się z powrotem, kod będzie uważał, że klawisz jest wciśnięty, dopóki nie naciśniesz go ponownie lub nie poruszysz najedź myszą na stronę. :-(
Eric Mickelsen

Odpowiedzi:

73

Czy istnieje sposób na wykrycie, czy klucz jest obecnie wyłączony w JavaScript?

Nie. Jedyną możliwością jest monitorowanie każdego keyupi keydownpamiętanie.

po pewnym czasie klucz zaczyna się powtarzać, odpalając zdarzenia keydown i keyup jak diabeł.

Nie powinno. Na pewno będziesz keypresspowtarzać, aw wielu przeglądarkach również będziesz powtarzać keydown, ale jeśli się keyuppowtarza, jest to błąd.

Niestety nie jest to całkowicie niesłychany błąd: w Linuksie, Chromium i Firefoksie (gdy jest uruchamiany pod GTK +, który jest w popularnych dystrybucjach, takich jak Ubuntu), oba generują powtarzające się sekwencje keyup-keypress-keydown dla trzymanych kluczy, których nie da się odróżnić od kogoś, kto naprawdę szybko wbija klucz.

bobince
źródło
14
Pan jest dżentelmenem i uczonym. Chromium i Firefox na Ubuntu to moje główne środowisko programistyczne, więc to dokładnie wyjaśnia problem, który widziałem. Miejmy nadzieję, że będzie lepiej, w przeciwnym razie jedyne obejście to rozwiązanie polegające na hakowaniu timera.
Daniel X Moore
3
Tak, frustrujące jest to, że nie ma w tym postępu. Zobacz bugs.launchpad.net/ubuntu/+bug/369880 . Piszę grę przeglądarkową i moim rozwiązaniem na razie jest trzymanie się klawiszy modyfikujących (shift, ctrl itp.), Które w ogóle się nie powtarzają.
bobince
2
Nie, to jest możliwe, aby odróżnić je od prawdziwych powtarzanych znakom przez brak odpowiednich keyupzdarzeń.
mako
4
czy nadal tak jest, 8 lat później? Ta odpowiedź może wymagać aktualizacji.
Marco Lavagnino
3
pomoc dotycząca analizowania: (Linux && (Chromium || (Firefox && GTK +)))
bobince
134

Oprócz używania keyupi keydownnasłuchiwania do śledzenia, kiedy klucz spada i się cofa, w rzeczywistości istnieją pewne właściwości, które informują, czy określone klawisze są wyłączone.

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

To są dostępne dla wszystkich obiektów zdarzeń generowane przez przeglądarkę, takich jak te, z keydown, keyupi keypress, dzięki czemu nie trzeba używać mouseMove.

Próbowałem generować własne obiekty zdarzeń za pomocą document.createEvent('KeyboardEvent')i document.createEvent('KeyboardEvent')i szukałem e.shiftKeyi takich, ale nie miałem szczęścia.

Używam Chrome 17 na Macu

Devin G Rhode
źródło
Używam tego zarówno w nowych, jak i starych przeglądarkach, nawet w aplikacjach HTA
Jakob Sternberg
1
Czy istnieje sposób na zastosowanie tej odpowiedzi, gdy jakaś liczba jest obecnie niedostępna? Próbowałem z if (e.keyCode == 49) {console.log ("1 nie działa");} ale nie działa :(
Roberto Sepúlveda Bravo
Hej @ RobertoSepúlvedaBravo Robert wydaje się odpowiadać na pytanie dotyczące następnej odpowiedzi. ;)
Mark Odey
Właściwie nie powinieneś szukać e.shiftKey na keyup, jeśli masz na myśli Shift. Zamiast tego użyj e.shiftKey np. Onclick.
maciek
45

Moje rozwiązanie:

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

Mogę teraz sprawdzić, czy w innym miejscu skryptu naciśnięto dowolny klawisz, sprawdzając

pressedKeys["code of the key"]

Jeśli to prawda, naciśnięto klawisz.

Robert
źródło
2
Ponieważ klucze są już funkcją, inna nazwa zmiennej może być lepsza.
Raven
1
nie zadziała to przy wykrywaniu, czy klawisz Alt jest wciśnięty, czy nie we wszystkich przypadkach.
Michael
1
To jest świetne do wykrywania w górę / w dół / w lewo / w prawo
Jonathan Spiller,
11

Nie wierzę, że istnieje coś takiego jak funkcja isKeyDown, ale możesz napisać własną.

Zasadniczo utwórz tablicę, której długość jest liczbą kluczy, które chcesz monitorować. Następnie korzystając ze zdarzeń documents / pages / controls keyUp i keyDown, zaktualizuj tablicę o stan tego klucza.

Następnie napisz funkcję, która sprawdza, czy określony klawisz jest wyłączony i zwraca wartość 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];
}

To powinno osiągnąć to, czego chcesz.

FallenAvatar
źródło
1
To jest dobre i rzeczywiście jest częścią rozwiązania, ale nie rozwiązuje problemu powtarzającego się błędu keyup, którego doświadczam. Zobacz odpowiedź bobince'a.
Daniel X Moore
4
To nie jest dobre rozwiązanie, ponieważ będziesz pisać coraz więcej „ifów”. A "keyList = {};" bycie obiektem akceptuje "keyList [key] = true;" bez potrzeby wyliczania lub limitu, ponieważ wykorzystuje indeksy / właściwości ciągów i działa dla wszystkich kluczy.
SparK
6

Skończyło się tutaj, aby sprawdzić, czy coś jest już wbudowane w przeglądarkę, ale wygląda na to, że tak nie jest. Oto moje rozwiązanie (bardzo podobne do odpowiedzi Roberta):

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

Następnie możesz sprawdzić, czy klawisz jest wciśnięty is_key_down('ArrowLeft').

antonagestam
źródło
1

Inni ludzie już wcześniej zadawali tego rodzaju pytania (chociaż w tej chwili nie widzę tu żadnych oczywistych oszustów).

Myślę, że odpowiedź jest taka, że keydownwydarzenie (i jego bliźniak keyup) to wszystkie informacje, które otrzymujesz. Powtarzanie jest dość mocno połączone z systemem operacyjnym, a aplikacja nie ma zbyt wielu okazji, aby zapytać BIOS o aktualny stan klucza.

To, co możesz zrobić, a być może musisz zrobić, jeśli chcesz, aby to działało, to programowo odbić klucz. Zasadniczo możesz oceniać siebie keydowni keyupsiebie, ale zignoruj keyupzdarzenie, jeśli dzieje się to zbyt szybko po ostatnim keydown... lub zasadniczo powinieneś opóźnić swoją odpowiedź na keyuptyle długo, aby mieć pewność, że nie nastąpi kolejne keydownzdarzenie z czymś w rodzaju 0,25 sekundy keyup.

Wymagałoby to użycia działania timera i zarejestrowania milisekund dla poprzednich zdarzeń. Nie mogę powiedzieć, że to bardzo atrakcyjne rozwiązanie, ale ...

Carl Smotricz
źródło
2
Martwiłem się, że może do tego dojść.
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
źródło
Nie jestem pewien, czy String.fromCharCode (unicode); jest szybkim wyszukiwaniem lub nie, dlatego mam obiekt unicode_mapping. Może to być coś, co można wyciągnąć, aby nieco przyciąć ten kod, jeśli jest ultraszybki. Ponieważ będzie to wywoływane wielokrotnie w przypadku naciśnięć klawiszy, szybkość jest ważna, dlatego pesymistycznie dodałem mapowanie.
RobKohr
1

Poniższy kod jest tym, czego używam:

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

Gdy użytkownik przytrzymuje klawisz Alt przez jakiś czas (około 2 sekundy), pojawia się grupa etykiet (klasa = „klucz ukryty”). Po zwolnieniu klawisza Alt etykiety znikają. Używane są zarówno jQuery, jak i Bootstrap.

Jasio
źródło
a co się stanie, jeśli klawisz „Tab” zostanie naciśnięty, gdy klawisz Alt jest wciśnięty?
Michael
1

Wiem, że jest to bardzo stare pytanie, ale istnieje bardzo lekka (~ .5Kb) biblioteka JavaScript, która skutecznie „łata” niespójne uruchamianie programów obsługi zdarzeń klawiatury podczas korzystania z DOM API.

Biblioteka nazywa się Keydrown .

Oto przykładowy kod operacyjny, który sprawdził się w moich celach, po prostu zmieniając klucz, na którym ma być ustawiony słuchacz:

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

Włączyłem Keydrown do mojego JavaScript po stronie klienta, aby uzyskać odpowiednią animację pauzy w grze Red Light Green Light, którą piszę. Możesz obejrzeć całą grę tutaj . (Uwaga: jeśli czytasz to w przyszłości, kod gry powinien być kompletny i możliwy do odtworzenia :-D!)

Mam nadzieję, że to pomoże.

buildpax
źródło
1

Przeskanowałem powyższe odpowiedzi i zaproponowane keydown/ keyuppodejście działa tylko w szczególnych okolicznościach. Jeśli użytkownik opuści alt-tab lub użyje gestu klawisza, aby otworzyć nowe okno lub kartę przeglądarki, keydownzostanie zarejestrowany a, co jest w porządku, ponieważ w tym momencie nie można stwierdzić, czy klucz jest czymś, co monitoruje aplikacja internetowa lub jest standardowym skrótem przeglądarki lub systemu operacyjnego. Wracając do strony przeglądarki, nadal będzie myśleć, że klucz jest wstrzymany, chociaż został w międzyczasie wydany. Lub jakiś klawisz jest po prostu przytrzymywany, podczas gdy użytkownik przechodzi do innej karty lub aplikacji za pomocą myszy, a następnie zwalniany poza naszą stroną.

Klawisze modyfikujące ( Shiftitp.) Mogą być monitorowane za pomocą mousemoveitp., Przy założeniu, że podczas cofania tabulatorem spodziewana jest przynajmniej jedna interakcja myszy, co często ma miejsce.

Dla większości wszystkie inne klawisze (oprócz modyfikatorów Tab, Deleteale w tym Space, Enter), monitoring keypressbędzie pracować dla większości zastosowań - klucz przytrzymany nadal będzie ogień. Istnieje jednak pewne opóźnienie w resetowaniu klucza ze względu na okresowość keypressodpalania. Zasadniczo, jeśli keypressnie strzela dalej, można wykluczyć większość klawiszy. To w połączeniu z modyfikatorami jest dość szczelne, chociaż nie zbadałem, co zrobić z Tabi Backspace.

Jestem pewien, że jest jakaś biblioteka, która streszcza tę słabość DOM, a może jakaś standardowa zmiana DOM załatwiła to, ponieważ jest to dość stare pytanie.

Robert Monfera
źródło
keypress jest teraz przestarzałe. Wygląda na to, że w ogóle nie działa w Chrome.
eadsjr
0

Spójrz na odpowiedź i użyj onkeyupi onkeydown. Oto bardziej szczegółowe informacje o tych wydarzeniach.

Claudiu
źródło
1
Cytowane łącze dotyczy zdarzeń myszy, w przypadku których automatyczne powtarzanie nie stanowi problemu.
Carl Smotricz
Klawisze w górę i w dół nie będą się powtarzać. naciśnięcie klawisza może.
Claudiu
cóż, nawet jeśli tak, wyobrażałem sobie coś w rodzaju rozwiązania TJMonk15, po prostu nie chciałem tego pisać
Claudiu
1
Sformułowanie tych dwóch pytań jest dokładnie takie samo. Dziwny zbieg okoliczności czy coś więcej?
Mitch Lindgren
2
@Mitch: wow ... to całkiem niewiarygodne. nie wiem, dlaczego ktoś miałby założyć dwa konta, aby zadać to samo pytanie. lub bardziej prawdopodobne, że ta osoba po prostu skopiowała drugie pytanie i dostosowała je do kluczy
Claudiu,
0

Działa to w przeglądarkach Firefox i Chrome.

Musiałem otworzyć specjalny plik html lokalnie (naciskając, Entergdy plik jest zaznaczony w eksploratorze plików w systemie Windows), albo tylko w celu przeglądania pliku, albo do edycji w specjalnym edytorze online.

Chciałem więc rozróżnić te dwie opcje, przytrzymując klawisz Ctrl-klawisz lub nie, jednocześnie naciskając Enter.

Jak wszyscy zrozumieliście ze wszystkich odpowiedzi tutaj, wydaje się, że nie jest to naprawdę możliwe, ale tutaj jest sposób, który naśladuje to zachowanie w sposób, który był dla mnie akceptowalny.

Działa to następująco:

Jeśli przytrzymasz klawisz Ctrl-key podczas otwierania pliku, zdarzenie keydown nigdy nie zostanie uruchomione w kodzie javascript. Ale zdarzenie keyup zostanie uruchomione (kiedy w końcu zwolnisz Ctrl-klucz). Kod to wychwytuje.

Kod wyłącza również keyevents (zarówno keyup, jak i keydown), gdy tylko wystąpi któreś z nich. Jeśli więc naciśniesz klawisz Ctrl-klucz po otwarciu pliku, nic się nie stanie.

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

jeśli naciśniesz alt + enter, zobaczysz alert.

Mokarom
źródło