Прежде чем перейти к клавиатуре, обратите внимание, что на современных устройствах есть и другие способы «ввести что-то». Например, распознавание речи (это особенно актуально на мобильных устройствах) или Копировать/Вставить с помощью мыши.
Поэтому, если мы хотим корректно отслеживать ввод в поле <input>
, то одних клавиатурных событий недостаточно. Существует специальное событие input
, чтобы отслеживать любые изменения в поле <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"
.«KeyZ» и другие клавишные коды
У каждой клавиши есть код, который зависит от её расположения на клавиатуре. Подробно о клавишных кодах можно прочитать в спецификации о кодах событий UI.
Например:
- Буквенные клавиши имеют коды по типу
"Key<буква>"
:"KeyA"
,"KeyB"
и т.д. - Коды числовых клавиш строятся по принципу:
"Digit<число>"
:"Digit0"
,"Digit1"
и т.д. - Код специальных клавиш – это их имя:
"Enter"
,"Backspace"
,"Tab"
и т.д.
Существует несколько широко распространённых раскладок клавиатуры, и в спецификации приведены клавишные коды к каждой из них.
Можно их прочитать в разделе спецификации, посвящённом буквенно-цифровым клавишам или просто нажмите нужную клавишу на тестовом стенде выше и посмотрите.Регистр важен: "KeyZ"
, а не "keyZ"
Выглядит очевидно, но многие всё равно ошибаются.
Пожалуйста, избегайте опечаток: правильно 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
, ведь его значение всегда одно и тоже.
Вот пример кода:
document.addEventListener('keydown', function(event) {
if (event.code == 'KeyZ' && (event.ctrlKey || event.metaKey)) {
alert('Отменить!')
}
});
С другой стороны, с 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
может быть лучше.