Перевірити, якщо клавіша не працює?


93

Чи є спосіб виявити, чи на даний момент ключ не працює в JavaScript?

Я знаю про подію "keydown", але це не те, що мені потрібно. Деякий час ПІСЛЯ натискання клавіші я хочу мати можливість визначити, чи вона все ще натиснута.

PS Найбільшою проблемою, здається, є те, що через якийсь проміжок часу ключ починає повторюватись, запускаючи події клавіатури та клавіатури, як нечистий. Сподіваємось, існує просто проста функція isKeyDown (ключ), але якщо ні, то цю проблему потрібно буде подолати / вирішити.


6
Поширена проблема з відповідями, які я бачу тут, полягає в тому, що якщо утримувати клавішу натиснутою, а потім змінити вкладку або змінити фокус, відпустити клавішу вгору, а потім повернутися назад, код буде вважати, що клавіша опущена, доки ви не натиснете її ще раз або не перемістите наведіть курсор на сторінку. :-(
Ерік Мікельсен

Відповіді:


73

Чи є спосіб виявити, чи на даний момент ключ не працює в JavaScript?

Ні. Єдина можливість моніторингу кожного keyupі keydownі запам'ятовування.

через деякий проміжок часу клавіша починає повторюватися, запускаючи події клавіатури та клавіатури, як нечистий.

Не повинно. Ви точно отримаєте keypressповторення, і у багатьох браузерах ви також будете повторюватися keydown, але якщо keyupповторюється, це помилка.

На жаль, це не зовсім нечувана помилка: в Linux, Chromium та Firefox (коли вона працює під GTK +, що є в популярних дистрибутивах, таких як Ubuntu), обидва генерують повторювані послідовності натискання та натискання клавіш для утримуваних клавіш, яких неможливо відрізнити від того, хто дуже швидко забиває ключ.


14
Ви, сер, джентльмен і вчений. Chromium та Firefox на Ubuntu - це моє основне середовище розробки, тому це точно пояснює проблему, яку я бачив. Будемо сподіватися, що це покращиться, інакше вирішення проблеми з таймером може бути єдиним обхідним шляхом.
Даніель X Мур 02

3
Так, засмучує те, що в цьому немає прогресу. Див. Bugs.launchpad.net/ubuntu/+bug/369880 . Я пишу браузерну гру, і моє обхідне рішення - дотримуватися модифікаторських клавіш (shift, ctrl тощо), які взагалі не повторюються.
bobince

2
Ні, це можливо , щоб відрізнити їх від справжніх повітряних натискань їх відсутністю відповідних keyupподій.
mako

4
це все ще так, через 8 років? Можливо, цю відповідь потрібно оновити.
Marco Lavagnino

3
довідка щодо аналізу: (Linux && (Chromium || (Firefox && GTK +)))
bobince

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 Роберт, здається, відповідає на ваше запитання щодо наступної відповіді. ;)
Марк Одей

Насправді ви не повинні шукати e.shiftKey на клавіатурі, якщо ви маєте на увазі Shift. Замість цього використовуйте e.shiftKey на, наприклад, onclick.
maciek

45

Моє рішення:

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

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

pressedKeys["code of the key"]

Якщо це правда, клавіша натискається.


2
Оскільки ключі вже є функцією, інше ім'я змінної може бути кращим.
Ворон

1
це не спрацює для виявлення, якщо клавіша Alt відсутня або не у всіх випадках.
Майкл

1
Це чудово для виявлення вгору / вниз / вліво / вправо
Джонатан Спіллер

11

Я не вірю, що існує щось на зразок функції isKeyDown, але ви можете написати своє.

По суті, створіть масив, довжина якого - це кількість клавіш, які ви хочете контролювати. Потім, використовуючи документи / сторінки / елементи керування подіями keyUp та keyDown, оновіть масив із станом цього ключа.

Потім напишіть функцію, яка перевіряє, чи певний ключ не працює, і повертає 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];
}

Це має досягти того, що ви хочете.


1
Це добре, і справді є частиною рішення, але воно не стосується повторюваної помилки, яку я повторюю. Дивіться відповідь bobince.
Даніель X Мур,

4
Це не є гарним рішенням, оскільки ви будете писати все більше і більше якщо. "KeyList = {};" будучи об'єктом, приймає "keyList [key] = true;" без необхідності перерахування чи обмеження, оскільки він використовує рядкові індекси / властивості та працює для всіх ключів.
SparK

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
Я переживав, що це може дійти до цього.
Даніель X Мур,

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 секунд), з'являється група міток (клас = 'ключ прихований'). Коли клавішу Alt відпущено, мітки зникають. Використовуються як jQuery, так і Bootstrap.


і що станеться, якщо натиснути "Tab", коли Alt не працює?
Майкл

1

Я знаю, що це дуже давнє запитання, однак існує дуже легка (~ .5Kb) бібліотека 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-tabs відсутній або використовує клавішний жест, щоб відкрити нове вікно або вкладку браузера, то akeydown буде зареєстровано , що нормально, оскільки на той момент неможливо визначити, чи є ключ тим, що контролює веб-програма , або є стандартним ярликом браузера або ОС. Повернувшись на сторінку браузера, він все одно буде думати, що ключ утримується, хоча тим часом його випустили. Або якусь клавішу просто утримують, поки користувач переходить на іншу вкладку або програму за допомогою миші, а потім випускається за межі нашої сторінки.

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

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

Я впевнений, що там є бібліотека, яка абстрагується від цієї слабкості DOM, або, можливо, якась зміна стандарту DOM подбала про це, оскільки це досить давнє запитання.


натискання клавіш застаріло. Здається, це взагалі не працює в Chrome.
eadsjr

0

Подивіться на цю відповідь і використовуйте onkeyupі onkeydown. Ось більш конкретна інформація про ці події.


1
Посилання, яке ви цитуєте, стосується подій миші, де автоматичне повторення не є проблемою.
Carl Smotricz

натискання та зменшення клавіш не повторюються. натискання клавіші може.
Клавдіу

ну навіть якщо вони це роблять, я уявляв щось на зразок рішення TJMonk15, просто не хотів його писати
Клавдіу

1
Формулювання цих двох питань абсолютно однакове. Дивна випадковість, чи щось більше?
Мітч Ліндгрен,

2
@Mitch: вау ... це досить неймовірно. я не знаю, чому хтось робить два рахунки, щоб задати одне і те ж питання. або, швидше за все, ця людина просто скопіювала інше запитання та пристосувала його для ключів
Клавдіу

0

Це працює у Firefox та Chrome.

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

Тож я хотів розрізнити ці два варіанти, утримуючи Ctrl-кнопку чи ні, одночасно натискаючи Enter.

Як ви всі зрозуміли з усіх відповідей тут, це, здається, насправді неможливо, але ось спосіб імітує цю поведінку прийнятним для мене способом.

Це працює так:

Якщо Ctrlпри відкритті файлу утримувати клавішу -key, подія знижки клавіш ніколи не запускатиметься в коді javascript. Але подія клавіатури запускається (коли ви нарешті відпустите Ctrl-key). Код фіксує це.

Код також вимикає події клавіш (як клавіатуру, так і клавіатуру), як тільки відбувається одна з них. Отже, якщо Ctrlпісля відкриття файлу натиснути -key, нічого не трапиться.

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.