Автоповтор
При долгом нажатии клавиши возникает автоповтор: keydown
срабатывает снова и снова, и когда клавишу отпускают, то отрабатывает keyup
. Так что ситуация, когда много keydown
и один keyup
, абсолютно нормальна.
Для событий, вызванных автоповтором, у объекта события свойство event.repeat
равно true
.
Действия по умолчанию
Действия по умолчанию весьма разнообразны, много чего можно инициировать нажатием на клавиатуре.
Для примера:
- Появление символа (самое очевидное).
- Удаление символа (клавиша Delete).
- Прокрутка страницы (клавиша PageDown).
- Открытие диалогового окна браузера «Сохранить» (Ctrl+S)
- …и так далее.
Предотвращение стандартного действия с помощью event.preventDefault()
работает практически во всех сценариях, кроме тех, которые происходят на уровне операционной системы. Например, комбинация Alt+F4 инициирует закрытие браузера в Windows, что бы мы ни делали в JavaScript.
Для примера, <input>
ниже ожидает телефонный номер, так что ничего кроме чисел, +
, ()
или -
принято не будет:
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-';
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Введите телефон" type="tel">
Заметьте, что специальные клавиши, такие как Backspace, Left, Right, Ctrl+V, в этом поле для ввода не работают. Это побочный эффект чересчур жёсткого фильтра checkPhoneKey
.
Добавим ему немного больше свободы:
<script>
function checkPhoneKey(key) {
return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')' || key == '-' ||
key == 'ArrowLeft' || key == 'ArrowRight' || key == 'Delete' || key == 'Backspace';
}
</script>
<input onkeydown="return checkPhoneKey(event.key)" placeholder="Введите телефон" type="tel">
Теперь стрелочки и удаление прекрасно работают.
…Впрочем, мы всё равно можем ввести в <input>
что угодно с помощью правого клика мыши и пункта «Вставить» контекстного меню. Так что такой фильтр не обладает 100% надёжностью. Мы можем просто оставить всё как есть, потому что в большинстве случаев это работает. Альтернатива – отслеживать событие input
, оно генерируется после любых изменений в поле <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). Они срабатывают в результате любого ввода, включая Копировать/Вставить мышью и распознавание речи.
События клавиатуры же должны использоваться только по назначению – для клавиатуры. Например, чтобы реагировать на горячие или специальные клавиши.
Практика
Отследить одновременное нажатие
важность: 5
Создайте функцию runOnKeys(func, code1, code2, ... code_n)
, которая запускает func
при одновременном нажатии клавиш с кодами code1
, code2
, …, code_n
.
Например, код ниже выведет alert
при одновременном нажатии клавиш "Q"
и "W"
(в любом регистре, в любой раскладке)
runOnKeys(
() => alert("Привет!"),
"KeyQ",
"KeyW"
);
Подсказка
Необходимо использовать два обработчика событий: document.onkeydown
и document.onkeyup
.
Создадим множество pressed = new Set()
, в которое будем записывать клавиши, нажатые в данный момент.
В первом обработчике будем добавлять в него значения, а во втором удалять. Каждый раз, как отрабатывает keydown
, будем проверять – все ли нужные клавиши нажаты, и, если да – выводить сообщение.