Преобразование keyCode Javascript в charCode для неамериканской раскладки клавиатуры (например, azerty)

Быстрый фон:

  • при нажатии клавиши в браузере генерируются три события: keyDown, keyPress и keyUp.
  • keyDown и keyUp имеют свойство keyCode, которое примерно соответствует физической нажатой клавише.
  • keyPress также имеет набор свойств charCode, который учитывает клавиши-модификаторы и раскладку клавиатуры (A и a имеют одинаковый keyCode, но разные charCode).
  • все три события имеют свойства, указывающие, какие клавиши-модификаторы были нажаты во время этих событий.

Я главный разработчик noVNC, и у меня сложная проблема: noVNC нужен переведенный charCode< /strong> без использования события keyPress по следующим причинам:

  • noVNC необходимо отправлять события keyDown и keyUp отдельно на сервер VNC (иначе это не полностью функциональный клиент VNC).
  • что еще более важно, noVNC должен предотвращать действия клавиатуры по умолчанию при подключении, что означает вызов метода preventDefault() события keyDown. Побочным эффектом этого является также предотвращение срабатывания события keyPress.

Из-за различий в раскладках клавиатуры (т. е. разных сопоставлений keyCode и charCode) я решил, что noVNC потребуется таблица поиска для разных раскладок клавиатуры.

Но вот настоящая проблема: в альтернативных макетах некоторые разные физические клавиши имеют ОДИНАКОВЫЙ keyCode. Например, при azerty (французской) раскладке клавиатуры клавиши «-» (тире) и «_» подчеркивания генерируют keyCode 189. Ack!!!

Итак... как мне получить правильное сопоставление keyCode с charCode и одновременно предотвратить действия браузера по умолчанию?

Кстати, я подозреваю, что это решение будет применимо к другим интерактивным веб-приложениям и играм HTML5, поскольку вы часто хотите знать полную информацию о нажатой клавише, не вызывая какой-либо дополнительный ответ браузера на это нажатие.

Полезные ссылки:

Решение: см. мой пост ниже.


person kanaka    schedule 15.03.2011    source источник


Ответы (2)


Я решил свой вопрос. Это не 100% решение, но оно должно охватывать большую часть того, что необходимо. Надеемся, что когда поставщики браузеров начнут интегрировать DOM Level 3 Events, появится более чистое решение. .

Просто чтобы повторить основные ограничения:

  1. События нажатия клавиши и нажатия клавиши должны сообщаться/отправляться в то время, когда они действительно происходят. т.е. одновременной отправки клавиши вниз и клавиши во время события keyPress недостаточно.
  2. Многие комбинации клавиш должны быть полностью обработаны во время события keyDown либо потому, что они никогда не вызывают событие keyPress (например, клавиша Ctrl), либо потому, что действие по умолчанию должно быть остановлено в keyDown (WebKit), что предотвращает возникновение события keyPress.
  3. События key down и key должны сообщать о переведенном коде символа, а не о значении keyCode.

Без какого-либо нестандартного прозрения текущие реализации браузера, по-видимому, не позволяют полностью выполнить все три ограничения. Поэтому я решил немного ослабить ограничение №3.

  • В событии браузера keyDown добавьте событие в список нажатия клавиш и проверьте, является ли это безопасной комбинацией клавиш (отсутствие нежелательного поведения браузера по умолчанию):

    • Безопасно: ничего не делайте, пока не нажмете клавишу.

    • Небезопасно: немедленно сообщить/отправить событие нажатия клавиши. Здесь ограничение № 3 ослабляется, потому что эти ограниченные комбинации клавиш не преобразуются в код символа (во всяком случае, у многих из них их нет).

  • В браузерном событии keyPress (которое происходит сразу после события keyDown) проверьте, является ли это безопасной комбинацией клавиш:

    • Безопасно: сообщить/отправить событие нажатия клавиши. Обновите список нажатий клавиш, используя переведенный код символа (event.what).

    • Небезопасно: ничего не делать, так как об этом уже было сообщено/отправлено во время keyDown.

  • В событии браузера keyUp найдите и удалите соответствующее событие из списка нажатия клавиши и используйте переведенный код, чтобы сообщить/отправить событие нажатия клавиши.

Дополнительные ссылки для интересующихся:

person kanaka    schedule 06.04.2011

Это абсолютное минное поле, и я призываю вас не пытаться сделать это, если вы можете этого избежать. Существует не только длинная и запутанная история производителей браузеров, не согласных с ключевым поведением событий, но и тот факт, что они до сих пор не согласны и все еще регулярно меняют ключевое поведение своих браузеров.

Лучшее, что я могу предложить, и исчерпывающий ресурс по ключевым событиям браузера: http://unixpapa.com/js/key.html

Если вам придется это сделать, я думаю, вы получите множество таблиц сопоставления кодов ключей, которые очень быстро устареют. Удачи.

person Tim Down    schedule 15.03.2011
comment
Ну, так как другой вариант хуже, я застрял с сопоставлениями раскладок клавиатуры (если кто-то не может придумать готовое решение). Но сопоставления раскладок клавиатуры - это не проблема, о которой я спрашиваю (я могу до некоторой степени автоматизировать создание таблиц сопоставления), проблема в том, что в некоторых раскладках есть клавиши, которые, по-видимому, не могут быть сопоставлены. Вот о чем я спрашиваю. Я добавлю вашу ссылку unixpapa к вопросу. - person kanaka; 15.03.2011
comment
Кроме того, еще одним смягчающим фактором для ключевых событий является то, что noVNC поддерживает только браузеры с поддержкой Canvas (поэтому нет IE8 или ниже), так что это немного снижает сумасшествие. Более поздние браузеры несколько сошлись. - person kanaka; 15.03.2011
comment
Кроме того, раздел unixpapa о подавлении действий по умолчанию. В Chrome (9) вы должны подавить keyDown, чтобы полностью подавить действие по умолчанию. Не получается подавить его в keyPress. - person kanaka; 15.03.2011
comment
@kanaka: Больше я ничего не могу предложить. Если у двух клавиш один и тот же keyCode, и вам нужно использовать событие keydown, а не событие keypress, что, по-видимому, имеет место в вашей ситуации, то в текущих браузерах ничего нельзя сделать. - person Tim Down; 17.03.2011