Проверить, не выключен ли ключ?


94

Есть ли способ определить, не работает ли в данный момент ключ в JavaScript?

Я знаю о событии "keydown", но мне это не нужно. Через некоторое время ПОСЛЕ нажатия клавиши я хочу иметь возможность определять, нажата ли она еще.

PS Самая большая проблема, кажется, заключается в том, что через некоторый период времени клавиша начинает повторяться, запуская события keydown и keyup, как злодей. Надеюсь, есть простая функция isKeyDown (key), но если нет, то эту проблему нужно будет преодолеть / обойти.


6
Распространенная проблема с ответами, которые я вижу здесь, заключается в том, что если вы удерживаете клавишу, затем меняете вкладки или меняете фокус, отпускаете клавишу вверх, а затем переключаетесь назад, код будет считать, что клавиша нажата, пока вы не нажмете ее снова или не переместите указатель мыши на странице. :-(
Эрик Микельсен

Ответы:


74

Есть ли способ определить, не работает ли в данный момент ключ в JavaScript?

Неа. Единственная возможность мониторинга каждого keyupи keydownи запоминания.

через некоторый период времени клавиша начинает повторяться, вызывая события keydown и keyup, как злодей.

Не должно. Вы обязательно получите keypressповторение, и во многих браузерах вы также будете повторяться keydown, но если keyupповторяется, это ошибка.

К сожалению, это не совсем неслыханная ошибка: в Linux, Chromium и Firefox (когда он работает под GTK +, который есть в популярных дистрибутивах, таких как Ubuntu) оба генерируют повторяющиеся последовательности keyup-keypress-keydown для удерживаемых ключей, которых невозможно отличить от тех, кто очень быстро забивает ключ.


14
Вы, сэр, джентльмен и ученый. Chromium и Firefox в Ubuntu - моя основная среда разработки, так что это точно объясняет проблему, которую я видел. Надеюсь, это станет лучше, иначе это решение для взлома таймера может быть единственным решением.
Дэниел Икс Мур

3
Да, обидно, что в этом нет прогресса. См. Bugs.launchpad.net/ubuntu/+bug/369880 . Я пишу браузерную игру, и на данный момент мой обходной путь - придерживаться клавиш-модификаторов (shift, ctrl и т. Д.), Которые вообще не повторяются.
bob с 02

2
Нет, это возможно , чтобы отличить их от подлинных повторных нажатий их отсутствием соответствующих keyupсобытий.
mako

4
так ли это и 8 лет спустя? Этот ответ, возможно, потребуется обновить.
Марко Лаваньино

3
справка по синтаксическому анализу: (Linux && (Chromium || (Firefox && GTK +)))
bobince 08

134

В дополнение к использованию keyupи keydownслушателей , чтобы отслеживать , когда это ключ идет вниз и обратно вверх, то есть на самом деле некоторые свойства , которые говорят вам , если некоторые клавиши вниз.

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

Это доступно на все браузерные генерироваться объекты событий, такие , как из keydown, keyupи keypress, таким образом Вы не должны использовать MouseMove.

Я пытался создать свои собственные объекты событий с помощью document.createEvent('KeyboardEvent')и document.createEvent('KeyboardEvent')и искал e.shiftKeyи тому подобное, но мне не повезло.

Я использую Chrome 17 на Mac


Я использую это как в новых, так и в старых браузерах, даже в HTA
Якоб Штернберг

1
Есть ли способ реализовать этот ответ, когда какое-то число в настоящее время не работает? Я пробовал с if (e.keyCode == 49) {console.log ("1 не работает");}, но не работает :(
Роберто Сепульведа Браво

Привет, @ RobertoSepúlvedaBravo Роберт, кажется, отвечает на ваш вопрос в следующем ответе. ;)
Марк Одей 09

На самом деле вам не следует искать e.shiftKey при нажатии клавиш, если вы имеете в виду Shift. Вместо этого используйте e.shiftKey, например, для onclick.
maciek

46

Мое решение:

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

Теперь я могу проверить, нажата ли какая-либо клавиша где-нибудь еще в сценарии, проверив

pressedKeys["code of the key"]

Если это правда, клавиша нажата.


2
Поскольку ключи уже являются функцией, может быть лучше другое имя переменной.
Raven

1
это не сработает для определения того, нажата клавиша Alt или нет, во всех случаях.
Майкл

1
Это отлично подходит для обнаружения вверх / вниз / влево / вправо,
Джонатан Спиллер

11

Я не верю, что есть что-то вроде функции isKeyDown, но вы могли бы написать свою собственную.

По сути, создайте массив, длина которого равна количеству ключей, которые вы хотите отслеживать. Затем с помощью событий keyUp и keyDown documents / pages / controls обновите массив, указав состояние этого ключа.

Затем напишите функцию, которая проверяет, не нажата ли определенная клавиша, и возвращает логическое значение.

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

Это должно выполнить то, что вы хотите.


1
Это хорошо и действительно является частью решения, но не устраняет повторяющуюся ошибку нажатия клавиш, с которой я столкнулся. См. Ответ Бобинса.
Дэниел Икс Мур

5
Это не лучшее решение, так как вы будете писать все больше и больше «если». "KeyList = {};" будучи объектом, принимает "keyList [key] = true;" без необходимости перечисления или ограничения, поскольку он использует строковые индексы / свойства и работает для всех ключей.
SparK

Это работает, но очень сложно
scitronboy

6

Заканчивается здесь, чтобы проверить, было ли что-то встроено в браузер, но похоже, что это не так. Это мое решение (очень похоже на ответ Роберта):

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

Затем вы можете проверить, нажата ли клавиша, с помощью is_key_down('ArrowLeft').


1

Другие люди задавали подобные вопросы раньше (хотя сейчас я не вижу здесь очевидных дураков).

Я думаю, ответ состоит в том, что keydownсобытие (и его двойник keyup) - это вся информация, которую вы получаете. Повторение довольно прочно встроено в операционную систему, и прикладная программа не имеет особых возможностей запрашивать у BIOS фактическое состояние ключа.

Что вы можете сделать, и, возможно, придется, если вам нужно заставить это работать, - это программно разблокировать ключ. По сути, вы можете оценивать keydownи keyupсебя, но игнорировать keyupсобытие, если оно происходит слишком быстро после последнего keydown... или, по сути, вы должны отложить свой ответ на keyupдостаточно долгое время, чтобы быть уверенным, что за ним не последует другое keydownсобытие с примерно 0,25 секундами keyup.

Это потребует использования таймера и записи миллисекунд для предыдущих событий. Не могу сказать, что это очень привлекательное решение, но ...


2
Я боялся, что до этого дойдет.
Дэниел Икс Мур

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

Не уверен, что String.fromCharCode (unicode); быстрый поиск или нет, поэтому у меня есть объект unicode_mapping. Это может быть что-то, что нужно вытащить, чтобы немного урезать этот код, если он сверхбыстрый. Так как это будет вызываться многократно для нажатия клавиш, скорость важна, поэтому я пессимистично добавил отображение.
RobKohr

1

Я использую следующий код:

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

Когда пользователь удерживает нажатой клавишу Alt в течение некоторого времени (около 2 секунд), появляется группа меток (class = 'key hidden'). Когда клавиша Alt отпускается, метки исчезают. Используются оба jQuery и Bootstrap.


и что произойдет, если нажать "Tab" при нажатой клавише Alt?
Майкл

1

Я знаю, что это очень старый вопрос, однако существует очень легкая (~ .5 КБ) библиотека JavaScript, которая эффективно «исправляет» непоследовательный запуск обработчиков событий клавиатуры при использовании DOM API.

Библиотека - Keydrown .

Вот пример действующего кода, который хорошо сработал для моих целей, просто изменив ключ, на котором нужно установить слушателя:

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

Я включил Keydrown в свой клиентский JavaScript для правильной анимации паузы в игре Red Light Green Light, которую я пишу. Вы можете просмотреть всю игру здесь . (Примечание: если вы читаете это в будущем, игра должна иметь полный код и воспроизводиться :-D!)

Надеюсь, это поможет.


1

Я просмотрел выше ответы и предлагаемый keydown/ keyupподход работает только при особых обстоятельствах. Если пользователь отключает Alt-Tab или использует ключевой жест для открытия нового окна или вкладки браузера, тогда keydownбудет зарегистрирован a , и это нормально, потому что в этот момент невозможно определить, является ли ключ тем, что отслеживает веб-приложение. , либо стандартный ярлык браузера или ОС. Вернувшись на страницу браузера, он все равно будет думать, что ключ удерживается, хотя к тому времени он был выпущен. Или какая-то клавиша просто удерживается, пока пользователь переключается на другую вкладку или приложение с помощью мыши, а затем отпускается за пределы нашей страницы.

Клавиши-модификаторы ( Shiftи т. Д.) Можно отслеживать с помощью mousemoveи т. Д., Предполагая, что при переходе назад ожидается хотя бы одно взаимодействие с мышью, что часто имеет место.

Для большинства всех остальных клавиш (кроме модификаторов, Tab, Delete, но в то числе Space, Enter), мониторинг keypressбудет работать для большинства приложений - ключ удерживается в нажатом положении будет продолжать огнь. Однако есть некоторая задержка при сбросе ключа из-за периодичности keypressсрабатывания. В принципе, если keypressне продолжать стрелять, то можно исключить большинство ключей. Это в сочетании с модификаторами довольно герметично, хотя я не изучал, что делать с Tabи Backspace.

Я уверен, что есть какая-то библиотека, которая абстрагируется от этой слабости DOM, или, может быть, какое-то стандартное изменение DOM позаботилось об этом, поскольку это довольно старый вопрос.


keypress теперь не рекомендуется. Похоже, он вообще не работает в Chrome.
eadsjr

0

Посмотрите на этот ответ и используйте onkeyupи onkeydown. Вот более конкретная информация об этих событиях.


1
Ссылка, которую вы цитируете, предназначена для событий мыши, где автоповтор не является проблемой.
Карл Смотрич, 01

нажатие клавиши вверх и вниз не повторяется. нажатие клавиши мощи.
Claudiu

ну, даже если они это сделают, я представлял себе что-то вроде решения TJMonk15, просто не хотел об этом писать
Клаудиу

1
Формулировки этих двух вопросов абсолютно одинаковы. Странное совпадение или что-то большее?
Митч Линдгрен

2
@ Митч: вау ... это невероятно. Я не знаю, зачем кому-то создавать две учетные записи, чтобы задать один и тот же вопрос. или, что более вероятно, этот человек просто скопировал другой вопрос и адаптировал его для ключей
Клаудиу

0

Это работает в Firefox и Chrome.

Мне нужно было открыть специальный файл html локально (нажав, Enterкогда файл выбран в проводнике файлов в Windows), либо просто для просмотра файла, либо для его редактирования в специальном онлайн-редакторе.

Поэтому я хотел различать эти два параметра, удерживая Ctrlклавишу -клавишу или нет при нажатии Enter.

Как вы все поняли из всех ответов здесь, это кажется невозможным, но вот способ, который имитирует это поведение таким образом, который был приемлем для меня.

Это работает так:

Если вы удерживаете нажатой Ctrlклавишу при открытии файла, событие нажатия клавиши никогда не сработает в коде javascript. Но произойдет событие нажатия клавиши (когда вы наконец отпустите Ctrlклавишу). Код это фиксирует.

Код также отключает ключевые события (как нажатие, так и нажатие), как только происходит одно из них. Так что, если вы нажмете Ctrlклавишу после открытия файла, ничего не произойдет.

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

если вы нажмете alt + enter, вы увидите предупреждение.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.