Три свойства, три разных вопроса
KeyboardEvent предоставляет несколько способов идентифицировать клавишу, и они отвечают на действительно разные вопросы. event.key - это символ или именованное значение, получаемое нажатием после применения раскладки и модификаторов. Нажатие физической клавиши A даёт a, или A при удержании shift, или вообще другую букву на раскладке Dvorak или AZERTY. Именованные клавиши приходят как описательные строки, такие как Enter, Escape, ArrowLeft и F5.
event.code идентифицирует физическую позицию клавиши, используя не зависящее от раскладки имя, взятое из условной американской клавиатуры. Клавиша на позиции A всегда KeyA, независимо от того, что выдаёт раскладка пользователя. Цифры в верхнем ряду - это Digit1 по Digit0, а цифровая клавиатура сообщает Numpad1 и компания, чтобы вы могли отличить два ряда цифр.
event.keyCode и его двойник event.which - это устаревшие числовые идентификаторы. Оба официально устарели, оба всё ещё реализованы везде и оба непоследовательны между браузерами для пунктуации. Их стоит читать при сопровождении старого кода, но новая обработка сочетаний клавиш должна использовать key или code.
Выбор между key и code
Правило большого пальца простое: используйте code, когда важна позиция, и key, когда важен смысл. Игра, привязывающая передвижение к WASD, хочет code, потому что физический кластер под левой рукой игрока должен оставаться на месте на клавиатуре AZERTY, даже если он выдаёт ZQSD. Текстовый редактор, привязывающий «сохранить» к Ctrl+S, хочет key, потому что пользователь мыслит буквой S, а не клавишей рядом с A.
Флаги модификаторов - это отдельные логические значения: ctrlKey, shiftKey, altKey и metaKey. Проверяйте их явно, а не выводите из key, и помните, что основной модификатор сочетания - Command на macOS и Control в остальных системах. Распространённый шаблон - принимать event.metaKey || event.ctrlKey, чтобы один обработчик покрывал обе платформы.
event.location различает продублированные клавиши. Это 0 для обычной клавиши, 1 для левого члена пары, такой как левый Shift, 2 для правого и 3 для клавиши на цифровой клавиатуре.
Практические подводные камни
Не каждая клавиша генерирует ожидаемые события. Браузер резервирует некоторые комбинации для себя - Ctrl+W, Ctrl+T и Command+Q обычно закрывают вкладки или завершают приложение раньше, чем страница их увидит, и preventDefault не может их вернуть. Проверяйте любое сочетание в реальном окне браузера, а не предполагайте, что оно дойдёт до вашего обработчика.
Удержание клавиши порождает поток повторяющихся событий с event.repeat, равным true после первого. Игнорируйте повторы, когда сочетание должно сработать один раз, и учитывайте их, когда поведение непрерывно, например прокрутка или перемещение курсора.
Наконец, keydown и keyup описывают клавиши, а keypress описывал символы и был удалён из стандарта. Для текстового ввода лучше слушать событие input или читать beforeinput, которые гораздо надёжнее обрабатывают композицию, автозаполнение и мобильные клавиатуры, чем любое событие уровня клавиш.