Клавиатура: keydown и keyup
Прежде чем перейти к клавиатуре, обратите внимание, что на современных устройствах есть и другие способы «ввести что-то». Например, распознавание речи (это особенно актуально на мобильных устройствах) или Копировать/Вставить с помощью мыши.
Поэтому, если мы хотим корректно отслеживать ввод в поле , то одних клавиатурных событий недостаточно. Существует специальное событие input , чтобы отслеживать любые изменения в поле . И оно справляется с такой задачей намного лучше. Мы рассмотрим его позже в главе События: change, input, cut, copy, paste.
События клавиатуры же должны использоваться, если мы хотим обрабатывать взаимодействие пользователя именно с клавиатурой (в том числе виртуальной). К примеру, если нам нужно реагировать на стрелочные клавиши Up и Down или горячие клавиши (включая комбинации клавиш).
Тестовый стенд
Для того, чтобы лучше понять, как работают события клавиатуры, можно использовать тестовый стенд ниже.
Сфокусируйтесь на поле и нажмите какую-нибудь клавишу.
События keydown и keyup
Событие keydown происходит при нажатии клавиши, а keyup – при отпускании.
event.code и event.key
Свойство key объекта события позволяет получить символ, а свойство code – «физический код клавиши».
К примеру, одну и ту же клавишу Z можно нажать с клавишей Shift и без неё. В результате получится два разных символа: z в нижнем регистре и Z в верхнем регистре.
Свойство event.key – это непосредственно символ, и он может различаться. Но event.code всегда будет тот же:
Клавиша | event.key | event.code |
---|---|---|
Z | z (нижний регистр) | KeyZ |
Shift + Z | Z (Верхний регистр) | KeyZ |
Если пользователь работает с разными языками, то при переключении на другой язык символ изменится с «Z» на совершенно другой. Получившееся станет новым значением event.key , тогда как event.code останется тем же: «KeyZ» .
У каждой клавиши есть код, который зависит от её расположения на клавиатуре. Подробно о клавишных кодах можно прочитать в спецификации о кодах событий UI.
- Буквенные клавиши имеют коды по типу «Key » : «KeyA» , «KeyB» и т.д.
- Коды числовых клавиш строятся по принципу: «Digit » : «Digit0» , «Digit1» и т.д.
- Код специальных клавиш – это их имя: «Enter» , «Backspace» , «Tab» и т.д.
Существует несколько широко распространённых раскладок клавиатуры, и в спецификации приведены клавишные коды к каждой из них.
Можно их прочитать в разделе спецификации, посвящённом буквенно-цифровым клавишам или просто нажмите нужную клавишу на тестовом стенде выше и посмотрите.
Выглядит очевидно, но многие всё равно ошибаются.
Пожалуйста, избегайте опечаток: правильно KeyZ , а не keyZ . Условие event.code==»keyZ» работать не будет: первая буква в слове «Key» должна быть заглавная.
А что, если клавиша не буквенно-цифровая? Например, Shift или F1 , или какая-либо другая специальная клавиша? В таких случаях значение свойства event.key примерно тоже, что и у event.code :
Клавиша | event.key | event.code |
---|---|---|
F1 | F1 | F1 |
Backspace | Backspace | Backspace |
Shift | Shift | ShiftRight или ShiftLeft |
Обратите внимание, что event.code точно указывает, какая именно клавиша нажата. Так, большинство клавиатур имеют по две клавиши Shift : слева и справа. event.code уточняет, какая именно из них была нажата, в то время как event.key сообщает о «смысле» клавиши: что вообще было нажато ( Shift ).
Допустим, мы хотим обработать горячую клавишу Ctrl + Z (или Cmd + Z для Mac). Большинство текстовых редакторов к этой комбинации подключают действие «Отменить». Мы можем поставить обработчик событий на keydown и проверять, какая клавиша была нажата.
Здесь возникает дилемма: в нашем обработчике стоит проверять значение event.key или event.code ?
С одной стороны, значение event.key – это символ, он изменяется в зависимости от языка, и если у пользователя установлено в ОС несколько языков, и он переключается между ними, нажатие на одну и ту же клавишу будет давать разные символы. Так что имеет смысл проверять event.code , ведь его значение всегда одно и тоже.
Вот пример кода:
С другой стороны, с event.code тоже есть проблемы. На разных раскладках к одной и той же клавише могут быть привязаны разные символы.
Например, вот схема стандартной (US) раскладки («QWERTY») и под ней немецкой («QWERTZ») раскладки (из Википедии):
Для одной и той же клавиши в американской раскладке значение event.code равно «Z», в то время как в немецкой «Y».
Буквально, для пользователей с немецкой раскладкой event.code при нажатии на Y будет равен KeyZ .
Если мы будем проверять в нашем коде event.code == ‘KeyZ’ , то для людей с немецкой раскладкой такая проверка сработает, когда они нажимают Y .
Звучит очень странно, но это и в самом деле так. В спецификации прямо упоминается такое поведение.
Так что event.code может содержать неправильный символ при неожиданной раскладке. Одни и те же буквы на разных раскладках могут сопоставляться с разными физическими клавишами, что приводит к разным кодам. К счастью, это происходит не со всеми кодами, а с несколькими, например KeyA , KeyQ , KeyZ (как мы уже видели), и не происходит со специальными клавишами, такими как Shift . Вы можете найти полный список проблемных кодов в спецификации.
Чтобы отслеживать символы, зависящие от раскладки, event.key надёжнее.
С другой стороны, преимущество event.code заключается в том, что его значение всегда остаётся неизменным, будучи привязанным к физическому местоположению клавиши, даже если пользователь меняет язык. Так что горячие клавиши, использующие это свойство, будут работать даже в случае переключения языка.
Хотим поддерживать клавиши, меняющиеся при раскладке? Тогда event.key – верный выбор.
Или мы хотим, чтобы горячая клавиша срабатывала даже после переключения на другой язык? Тогда event.code может быть лучше.
Автоповтор
При долгом нажатии клавиши возникает автоповтор: keydown срабатывает снова и снова, и когда клавишу отпускают, то отрабатывает keyup . Так что ситуация, когда много keydown и один keyup , абсолютно нормальна.
Для событий, вызванных автоповтором, у объекта события свойство event.repeat равно true .
Действия по умолчанию
Действия по умолчанию весьма разнообразны, много чего можно инициировать нажатием на клавиатуре.
- Появление символа (самое очевидное).
- Удаление символа (клавиша Delete ).
- Прокрутка страницы (клавиша PageDown ).
- Открытие диалогового окна браузера «Сохранить» ( Ctrl + S )
- …и так далее.
Предотвращение стандартного действия с помощью event.preventDefault() работает практически во всех сценариях, кроме тех, которые происходят на уровне операционной системы. Например, комбинация Alt + F4 инициирует закрытие браузера в Windows, что бы мы ни делали в JavaScript.
Для примера, ниже ожидает телефонный номер, так что ничего кроме чисел, + , () или — принято не будет:
Заметьте, что специальные клавиши, такие как Backspace , Left , Right , Ctrl + V , в этом поле для ввода не работают. Это побочный эффект чересчур жёсткого фильтра checkPhoneKey .
Добавим ему немного больше свободы:
Теперь стрелочки и удаление прекрасно работают.
…Впрочем, мы всё равно можем ввести в что угодно с помощью правого клика мыши и пункта «Вставить» контекстного меню. Так что такой фильтр не обладает 100% надёжностью. Мы можем просто оставить всё как есть, потому что в большинстве случаев это работает. Альтернатива – отслеживать событие input , оно генерируется после любых изменений в поле , и мы можем проверять новое значение и подчёркивать/изменять его, если оно не подходит.
«Дела минувших дней»
В прошлом существовало также событие keypress , а также свойства keyCode , charCode , which у объекта события.
Но количество браузерных несовместимостей при работе с ними было столь велико, что у разработчиков спецификации не было другого выхода, кроме как объявить их устаревшими и создать новые, современные события (которые и описываются в этой главе). Старый код ещё работает, так как браузеры продолжают поддерживать и keypress , и keyCode с charCode , и which , но более нет никакой необходимости в их использовании.
Итого
Нажатие клавиши всегда генерирует клавиатурное событие, будь то буквенно-цифровая клавиша или специальная типа Shift или Ctrl и т.д. Единственным исключением является клавиша Fn , которая присутствует на клавиатуре некоторых ноутбуков. События на клавиатуре для неё нет, потому что она обычно работает на уровне более низком, чем даже ОС.
- keydown – при нажатии на клавишу (если клавиша остаётся нажатой, происходит автоповтор),
- keyup – при отпускании клавиши.
Главные свойства для работы с клавиатурными событиями:
- code – «код клавиши» ( «KeyA» , «ArrowLeft» и так далее), особый код, привязанный к физическому расположению клавиши на клавиатуре.
- key – символ ( «A» , «a» и так далее), для не буквенно-цифровых групп клавиш (таких как Esc ) обычно имеет то же значение, что и code .
В прошлом события клавиатуры иногда использовались для отслеживания ввода данных пользователем в полях формы. Это ненадёжно, потому как ввод данных не обязательно может осуществляться с помощью клавиатуры. Существуют события input и change специально для обработки ввода (рассмотренные позже в главе События: change, input, cut, copy, paste). Они срабатывают в результате любого ввода, включая Копировать/Вставить мышью и распознавание речи.
События клавиатуры же должны использоваться только по назначению – для клавиатуры. Например, чтобы реагировать на горячие или специальные клавиши.
Задачи
Отследить одновременное нажатие
Создайте функцию runOnKeys(func, code1, code2, . code_n) , которая запускает func при одновременном нажатии клавиш с кодами code1 , code2 , …, code_n .
Например, код ниже выведет alert при одновременном нажатии клавиш «Q» и «W» (в любом регистре, в любой раскладке)
Необходимо использовать два обработчика событий: document.onkeydown и document.onkeyup .
Создадим множество pressed = new Set() , в которое будем записывать клавиши, нажатые в данный момент.
В первом обработчике будем добавлять в него значения, а во втором удалять. Каждый раз, как отрабатывает keydown , будем проверять – все ли нужные клавиши нажаты, и, если да – выводить сообщение.
Источник
jQuery .keypress & .keydown .which
Ok so what is the difference in .keypress and .keydown/.keyup? At present I am using .keydown which returns a .which value of 38 for my key, now if i change it to .keypress it returns a value of 109 for that same key. What is the difference and why are the values different for the same key?
5 Answers 5
If you press a button it fires a keydown and releasing it fires a keyup . The keypress usually comes between those two.
keydown and keyup talk about which key has been changed. keypress tells which character that key represents.
Note that this is all browser-dependent!
I’ll be d$%^@d, there really is a difference with keypress and all this time I never realized. lol
See my fiddle and try something like the letter «r»
Somehow I never paid attention to this
«The two properties are keyCode and charCode . Put (too) simply, keyCode says something about the actual keyboard key the user pressed, while charCode gives the ASCII value of the resulting character. These bits of information need not be the same; for instance, a lower case ‘a’ and an upper case ‘A’ have the same keyCode , because the user presses the same key, but a different charCode because the resulting character is different.
Explorer and Opera do not support charCode . However, they give the character information in keyCode , but only with onkeypress . onkeydown and -up keyCode contains key information.»
Источник
Checking if a key exists in a JavaScript object?
How do I check if a particular key exists in a JavaScript object or array?
If a key doesn’t exist, and I try to access it, will it return false? Or throw an error?
25 Answers 25
Checking for undefined-ness is not an accurate way of testing whether a key exists. What if the key exists but the value is actually undefined ?
You should instead use the in operator:
If you want to check if a key doesn’t exist, remember to use parenthesis:
Or, if you want to particularly test for properties of the object instance (and not inherited properties), use hasOwnProperty :
For performance comparison between the methods that are in , hasOwnProperty and key is undefined , see this benchmark
Quick Answer
How do I check if a particular key exists in a JavaScript object or array? If a key doesn’t exist and I try to access it, will it return false? Or throw an error?
Accessing directly a missing property using (associative) array style or object style will return an undefined constant.
The slow and reliable in operator and hasOwnProperty method
As people have already mentioned here, you could have an object with a property associated with an «undefined» constant.
In that case, you will have to use hasOwnProperty or in operator to know if the key is really there. But, but at what price?
in operator and hasOwnProperty are «methods» that use the Property Descriptor mechanism in Javascript (similar to Java reflection in the Java language).
The Property Descriptor type is used to explain the manipulation and reification of named property attributes. Values of the Property Descriptor type are records composed of named fields where each field’s name is an attribute name and its value is a corresponding attribute value as specified in 8.6.1. In addition, any field may be present or absent.
On the other hand, calling an object method or key will use Javascript [[Get]] mechanism. That is a far way faster!
Benchmark
.
Using in operator
Accessing elements directly (brackets style)
Accessing elements directly (object style)
EDIT: What is the reason to assign to a property the undefined value?
That question puzzles me. In Javascript, there are at least two references for absent objects to avoid problems like this: null and undefined .
null is the primitive value that represents the intentional absence of any object value, or in short terms, the confirmed lack of value. On the other hand, undefined is an unknown value (not defined). If there is a property that will be used later with a proper value consider use null reference instead of undefined because in the initial moment the property is confirmed to lack value.
Advice
Avoid objects with undefined values. Check directly whenever possible and use null to initialize property values. Otherwise, use the slow in operator or hasOwnProperty() method.
EDIT: 12/04/2018 — NOT RELEVANT ANYMORE
As people have commented, modern versions of the Javascript engines (with firefox exception) have changed the approach for access properties. The current implementation is slower than the previous one for this particular case but the difference between access key and object is neglectable.
Источник