检测带死键的键盘布局中的按键释放事件

编程语言 2026-07-10

在我们的Tcl/Tk应用程序中,我们通过套接字向主机应用程序发送按键事件(<KeyPress><KeyRelease>),由后者处理实际的按键事件。

这通常工作得相当好,因为我们可以将任意 <KeyRelease> 事件关联到相应的 <KeyPress> 事件。举例来说,在我的德语键盘上,可以通过按下 AltGr+e 输入字符 。这会产生以下事件:

事件 %k %A %K %N
KeyPress 108 (空) ISO_Level3_Shift 65027
KeyPress 26 8364
KeyRelease 26 (空) e 101
KeyRelease 108 (空) ISO_Level3_Shift 65027

如你所见,%A%K%N 在按下及释放 e 键时可能展开为不同的值,但 %k 是稳定的,因此我们可以用它来判断哪个松开事件对应哪个按下事件。

不幸的是,对于带死键的键盘布局,我们遇到了一堵难以逾越的墙:在这种情况下,我们无法将 <KeyRelease> 事件与 <KeyPress> 事件相关联。

例如,在带死键的德语键盘上,我可以通过按 ´-a 输入字母 á

当我对某个日志函数进行 bind all <KeyPress>bind all <KeyRelease> 的响应时,我会得到以下事件(按顺序):

事件 %k %A %K %N
KeyRelease 21 (空) ´ 180
KeyPress 0 á á 225
KeyRelease 38 (空) a 97

首先要注意的是,死键 ´ 不会产生 KeyPress 事件(只有一个 KeyRelease 事件)。

我们大概可以接受这一点,然而真正让人困惑的是,当按下 a 时,绑定变量之间没有对这两个事件给出明显的对应关系。

我如何知道产生字母 á 的按键何时被释放?这种方法要跨平台(Linux、Darwin、Windows)并适用于未知的键盘布局(我们曾收到来自法语、西班牙语和葡萄牙语用户的反馈,但社区实际上是全球性的)。

解决方案

潜在的问题在于,我们必须把按键按下传给一个库,该库将它们转换成要插入的文本(这可能比 á 复杂得多!),而我们只能从中得知用于 %A 替换的值。我们不能把按键释放传给这些库进行解码(除非在某些输入法的特定情形下;这东西相当复杂!),也不能用其他方式解码按键。我们拥有的是一种折中方案,能在大多数普通应用中做对的事,但你很可能应该完全忽略 <KeyRelease> 事件;尽管它们有 %A 替换,但它们并不太有用,且从按键码到字符序列的转换非常非平凡(并且也是有状态的)。

输入法是使用GUI时最让人头疼的事情之一。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章