快速背景:
- 当在浏览器中按下一个键时,会生成三个事件:keyDown、keyPress 和 keyUp。
- keyDown 和 keyUp 有一个 keyCode 属性,它大约是按下的物理键。
- keyPress 还具有 charCode 属性集,它考虑了修饰键和键盘布局(A 和 a 具有相同的 keyCode 但具有不同的 charCode)。
- 所有三个事件都具有指示在这些事件期间按下了哪些修改键的属性。
我是主noVNC开发人员和我遇到了一个棘手的问题:noVNC 需要翻译的 charCode 值而不使用 keyPress 事件,原因如下:
- noVNC 需要将 keyDown 和 keyUp 事件分别发送到 VNC 服务器(否则它不是一个功能齐全的 VNC 客户端)。
- 更重要的是,noVNC 需要在连接时阻止默认键盘操作,这意味着调用 keyDown 事件的 preventDefault() 方法。这也有阻止触发 keyPress 事件的副作用。
由于键盘布局的差异(即不同的 keyCode 到 charCode 映射),我确定 noVNC 将需要一个用于不同键盘布局的查找表。
但真正的问题是:在备用布局上,一些不同的物理键具有SAME keyCode。例如,对于 azerty(法语)键盘布局,“-”(破折号)和“_”下划线键均生成 keyCode 189。Ack!!!
那么...我如何获得正确的 keyCode 到 charCode 映射并同时阻止默认浏览器操作?
顺便说一句,我怀疑此解决方案将适用于其他交互式 Web 应用程序和 HTML5 游戏,因为您通常希望能够了解有关所按按键的完整信息,而不触发对该按键的任何其他浏览器响应。
有用的链接:
- Here是一个有用的测试页,显示了三个事件和一些其他有用的属性。
- Summary Javascript 中关键事件的疯狂状态(感谢@Tim)
- 怪癖模式 Detecting keystrokes
- 怪癖模式 Events - key events
- noVNC issue对问题进行更多讨论。
解决方案:请参阅下面的帖子。
最佳答案
我已经解决了我自己的问题。它不是 100% 的解决方案,但它应该涵盖大部分所需内容。希望当浏览器 vendor 开始集成时会有一个更清洁的解决方案 DOM Level 3 Events .
只是重申主要限制条件:
- 按键按下和按键弹起事件应该在实际发生时报告/发送。 IE。在 keyPress 事件期间同时发送按键和按键是不够的。
- 许多组合键必须在 keyDown 事件期间完全处理,因为它们永远不会触发 keyPress 事件(即 Ctrl 键),或者因为默认操作必须在 keyDown (WebKit) 中停止,这样做可以防止 keyPress 事件发生。
- 按键和按键事件应该报告翻译后的字符代码,而不是 keyCode 值。
如果没有一些开箱即用的顿悟,当前的浏览器实现似乎会阻止完全满足所有三个约束。所以我决定稍微放宽约束 #3。
在浏览器 keyDown 事件中将事件添加到按键列表并检查它是否是安全的(没有不良的浏览器默认行为)组合键:
安全:在 keyPress 之前什么都不做。
不安全:立即报告/发送按键按下事件。这是约束 #3 放宽的地方,因为这些有限的组合键没有转换为字符代码(尽管其中许多组合没有它们)。
在浏览器 keyPress 事件(在 keyDown 事件之后立即发生)检查它是否是一个安全的组合键:
Safe:报告/发送按键按下事件。使用翻译后的字符代码 (event.which) 更新按键列表。
不安全:什么都不做,因为它已经在 keyDown 期间报告/发送。
在浏览器 keyUp 事件中,从按下键列表中找到并删除匹配的事件,并使用翻译后的代码报告/发送按下键事件。
一些有趣的额外链接:
- noVNC commit随着变化。
- 一些 wiki notes关于与 noVNC 相关的问题。
- 这个解决方案有been adopted在 RedHat 的 Broadway project (HTML5 GTK+ backend) .
关于javascript - 将 Javascript keyCode 转换为非美国键盘布局的 charCode(即 azerty),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5306132/