将Javascript的keyCode转换为非美式键盘布局(例如azerty)的charCode

17

快速背景:

  • 在浏览器中按下键时,会生成三个事件:keyDownkeyPresskeyUp
  • keyDownkeyUp 有一个 keyCode 属性,该属性大致表示按下的物理键。
  • keyPress 还设置了一个 charCode 属性,考虑到修饰键和键盘布局(A 和 a 具有相同的 keyCode,但具有不同的 charCode)。
  • 这三个事件都有指示在这些事件期间按下了哪些修改键的属性。

我是主要的 noVNC 开发人员,我面临一个棘手的问题:noVNC 需要翻译后的 charCode 值,而不使用 keyPress 事件,原因如下:

  • noVNC 需要将 keyDown 和 keyUp 事件分别发送到 VNC 服务器(否则它不是一个完全功能的 VNC 客户端)。
  • 更重要的是,noVNC 需要在连接时防止默认的键盘操作,这意味着调用 keyDown 事件的 preventDefault() 方法。这会导致 keyPress 事件也无法触发。

由于键盘布局的差异(即不同的 keyCode 到 charCode 映射),我已确定 noVNC 需要一个查找表来处理不同的键盘布局。

但是这里真正的问题是:在备选布局中,一些不同的物理键具有相同的keyCode。例如,在azerty(法语)键盘布局中,'-'(破折号)和'_'(下划线)键都会生成keyCode 189.啊!!!

那么...我如何同时获得适当的keyCode到charCode映射并防止默认浏览器操作呢?

顺便说一句,我怀疑这个解决方案适用于其他交互式Web应用程序和HTML5游戏,因为您经常希望能够了解按下的键的完整信息,而不触发任何其他浏览器响应该按键。

有用的链接:

解决方案:请参见下面的我的帖子。

2个回答

9
我已经解决了自己的问题。这不是一个100%的解决方案,但应该涵盖大部分所需内容。希望在浏览器厂商开始集成DOM Level 3 Events时会有更清晰的解决方案。
再次强调主要约束条件:
  1. 按键按下和松开事件应在它们实际发生的时候报告/发送。即在keyPress事件期间同时发送按键按下和松开事件是不充分的。
  2. 许多按键组合必须在keyDown事件中完全处理,因为它们从不触发keyPress事件(即Ctrl键),或者因为必须在keyDown中停止默认操作(WebKit),这样做会阻止keyPress事件的发生。
  3. 按键按下和松开事件应报告转换后的字符代码而不是keyCode值。
如果没有某些突破性的想法,当前的浏览器实现似乎无法完全满足所有三个约束条件。因此,我决定稍微放松第三个约束条件。
  • 在浏览器的keyDown事件中,将事件添加到按键列表中,并检查它是否是安全(没有不良浏览器默认行为)的按键组合:

    • 安全:什么都不做,直到按下键。

    • 不安全:立即报告/发送按键事件。这里放松了第3个约束条件,因为这些有限的键组合不会转换为字符代码(许多键组合无论如何都没有字符代码)。

  • 在浏览器的keyPress事件中(紧随keyDown事件之后),检查它是否是安全的按键组合:

    • 安全:报告/发送按键事件。使用翻译后的字符代码(event.which)更新按键列表。

    • 不安全:什么也不做,因为它已经在keyDown期间报告/发送过了。

  • 在浏览器的keyUp事件中,从按键列表中找到并删除匹配的事件,并使用翻译后的代码报告/发送按键释放事件。

一些其他有趣的链接:


3

如果可能的话,我强烈建议您不要尝试这个绝对棘手的问题。不仅是浏览器厂商在关键事件行为上长期存在纠纷和混乱的历史,而且他们仍然没有达成一致,并且仍在定期更改其浏览器的关键行为。

以下是我能提供的最佳资源,也是有关浏览器键盘事件的权威资料:http://unixpapa.com/js/key.html

如果你必须这么做,我认为你将会得到大量的键码映射表,这些表很快就会过时。祝你好运。


好吧,既然另一个选项更糟糕,我只能使用键盘布局映射(除非有人能提供现成的解决方案)。但是键盘布局映射不是我要问的问题(我可以在一定程度上自动创建映射表),问题是某些布局似乎无法映射某些按键。这就是我要问的问题。我会将您的unixpapa链接添加到问题中。 - kanaka
另外,对于关键事件的另一个缓解因素是noVNC仅支持具有Canvas支持的浏览器(因此不支持IE8或更低版本),这减少了一些疯狂的情况。最近的浏览器已经有所收敛。 - kanaka
此外,Unixpapa网站上的“抑制默认操作”部分。在Chrome(9)中,您必须抑制keyDown才能完全抑制默认操作。在keyPress中抑制它是无效的。 - kanaka
@kanaka:我没有更多的建议了。如果两个键具有相同的keyCode,并且您必须使用“keydown”事件而不是“keypress”事件(这似乎是您的情况),那么在当前浏览器中无法做任何事情。 - Tim Down

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接