Tcl/Tk:在法语键盘上触发的菜单栏加速器
Tcl/Tk: menu bar accelerators triggered on French keyboards
这让我们困惑了一段时间:
在我们的 Tcl/Tk 应用程序中,我们使用菜单项的键盘快捷键来触发某些操作。
基本上我们在菜单里设置了一个-accelerator
。根据 documentation,这是为了“仅显示”,因此我们还为与匹配菜单相同的命令添加了一些键盘绑定。
因为我们有很多这样的快捷键,简单的修改键绑定(例如 Control+n )已经不够了,我们开始使用多个修饰符(例如 Control+Shift+n)。
代码是这样的:
# case insensitive version 'bind' - in case the user pressed CapsLock
proc bind_capslock {tag seq_prefix seq_nocase script} {
bind $tag <${seq_prefix}-[string tolower ${seq_nocase}]> $script
bind $tag <${seq_prefix}-[string toupper ${seq_nocase}]> $script
}
if { [tk windowingsystem] == "aqua" } {
set modifier "Mod1"
set accelerator "Command"
} else {
set modifier "Control"
set accelerator $modifier
}
menu .menubar
. configure -menu .menubar
menu .menubar.edit
.menubar add cascade -menu .menubar.edit -label Edit
.menubar.edit add command -label "Test Me" \
-command {puts "you menued $accelerator-Shift-N"} \
-accelerator "${accelerator}-Shift-N"
bind_capslock all $modifier-Shift-Key N {puts "you pressed $modifier-Shift-N"}
通常,菜单 -command
与绑定 script
相同(这里有所不同以证明我的观点)。
现在,上面的代码在 Linux、Windows 和 macOS 上运行良好:
- 如果我导航到菜单并 select
Test Me
,它将打印出“你选择了 Command-Shift-N”
- 如果我改为按 Cmd+Shift+n,它将打印出“ 您按下了 Command-Shift-N"
万岁!
不幸的是,这似乎不适用于法语键盘布局的 macOS:
- 如果我导航到菜单 select
Test Me
,它会打印出“you menued Command-Shift-N”(酷!)
- 如果我改为按 Cmd+Shift+n,它将打印出两者“您选择了 Command-Shift-N”和 “您按下了 Command-Shift-N”。 =75=]
因此,无论出于何种原因,指定为菜单 -accelerator
触发器 的快捷方式,即使文档明确提到 -accelerator
是 [=44] =]仅供展示.
由于两个动作调用的 commands/scripts 完全相同,我们最终会重复调用该命令!
我们做错了什么?为什么此行为仅在法语键盘布局(而不是美国或德语布局)上触发,并且仅在 macOS 上触发(而不是 Linux 或 Windows)?
最重要的是:我们如何解决这个问题? (我们怎样才能快速修复?正确的修复方法是什么?)
问题出现在不久前 (Tcl/Tk 8.5),但在 Tcl/Tk-8.6.12 中仍然存在。
macOS 是 10.15 (Catalina),但其他版本也受到影响。
问题是菜单在 macOS 上的工作方式与 Tk 真正期望的不同。特别是,我们使用 NSMenuItem
并立即设置一个选择器(即调用回调处理程序)。但是如果设置了加速器,那么菜单也会在事件真正到达Tk之前捕获加速器描述的键序列,然后also将事件传递给我们;这是本机 GUI 行为,无法真正修复。 (macOS 上的 Tk 已经 方式 比理智更深入地了解本机 GUI 的内容。)
最简单的事情就是不要在 macOS 上放置这些绑定。
否则……将事件处理推迟到空闲事件处理程序。像那样,您可以用少量代码实现简单的第一个事件处理程序获胜规则。您指定的事件处理程序稍晚运行,但这对于与键盘绑定或菜单回调相关的任何事情都无关紧要!
# Most of your code doesn't need to change
set ::currentMenuAction {}
proc scheduleMenuAction script {
global currentMenuAction
if {$currentMenuAction eq ""} {
# Prepend a command to clear the variable
set act "set ::currentMenuAction {};$script"
set currentMenuAction [after idle $act]
}
}
# I don't like using lots of backslashes; your mileage may vary
.menubar.edit add command -label "Test Me" -command {
scheduleMenuAction {puts "you menued $accelerator-Shift-N"}
} -accelerator "${accelerator}-Shift-N"
bind_capslock all $modifier-Shift-Key N {
scheduleMenuAction {puts "you pressed $modifier-Shift-N"}
}
这让我们困惑了一段时间: 在我们的 Tcl/Tk 应用程序中,我们使用菜单项的键盘快捷键来触发某些操作。
基本上我们在菜单里设置了一个-accelerator
。根据 documentation,这是为了“仅显示”,因此我们还为与匹配菜单相同的命令添加了一些键盘绑定。
因为我们有很多这样的快捷键,简单的修改键绑定(例如 Control+n )已经不够了,我们开始使用多个修饰符(例如 Control+Shift+n)。
代码是这样的:
# case insensitive version 'bind' - in case the user pressed CapsLock
proc bind_capslock {tag seq_prefix seq_nocase script} {
bind $tag <${seq_prefix}-[string tolower ${seq_nocase}]> $script
bind $tag <${seq_prefix}-[string toupper ${seq_nocase}]> $script
}
if { [tk windowingsystem] == "aqua" } {
set modifier "Mod1"
set accelerator "Command"
} else {
set modifier "Control"
set accelerator $modifier
}
menu .menubar
. configure -menu .menubar
menu .menubar.edit
.menubar add cascade -menu .menubar.edit -label Edit
.menubar.edit add command -label "Test Me" \
-command {puts "you menued $accelerator-Shift-N"} \
-accelerator "${accelerator}-Shift-N"
bind_capslock all $modifier-Shift-Key N {puts "you pressed $modifier-Shift-N"}
通常,菜单 -command
与绑定 script
相同(这里有所不同以证明我的观点)。
现在,上面的代码在 Linux、Windows 和 macOS 上运行良好:
- 如果我导航到菜单并 select
Test Me
,它将打印出“你选择了 Command-Shift-N” - 如果我改为按 Cmd+Shift+n,它将打印出“ 您按下了 Command-Shift-N"
万岁!
不幸的是,这似乎不适用于法语键盘布局的 macOS:
- 如果我导航到菜单 select
Test Me
,它会打印出“you menued Command-Shift-N”(酷!) - 如果我改为按 Cmd+Shift+n,它将打印出两者“您选择了 Command-Shift-N”和 “您按下了 Command-Shift-N”。 =75=]
因此,无论出于何种原因,指定为菜单 -accelerator
触发器 的快捷方式,即使文档明确提到 -accelerator
是 [=44] =]仅供展示.
由于两个动作调用的 commands/scripts 完全相同,我们最终会重复调用该命令!
我们做错了什么?为什么此行为仅在法语键盘布局(而不是美国或德语布局)上触发,并且仅在 macOS 上触发(而不是 Linux 或 Windows)? 最重要的是:我们如何解决这个问题? (我们怎样才能快速修复?正确的修复方法是什么?)
问题出现在不久前 (Tcl/Tk 8.5),但在 Tcl/Tk-8.6.12 中仍然存在。 macOS 是 10.15 (Catalina),但其他版本也受到影响。
问题是菜单在 macOS 上的工作方式与 Tk 真正期望的不同。特别是,我们使用 NSMenuItem
并立即设置一个选择器(即调用回调处理程序)。但是如果设置了加速器,那么菜单也会在事件真正到达Tk之前捕获加速器描述的键序列,然后also将事件传递给我们;这是本机 GUI 行为,无法真正修复。 (macOS 上的 Tk 已经 方式 比理智更深入地了解本机 GUI 的内容。)
最简单的事情就是不要在 macOS 上放置这些绑定。
否则……将事件处理推迟到空闲事件处理程序。像那样,您可以用少量代码实现简单的第一个事件处理程序获胜规则。您指定的事件处理程序稍晚运行,但这对于与键盘绑定或菜单回调相关的任何事情都无关紧要!
# Most of your code doesn't need to change
set ::currentMenuAction {}
proc scheduleMenuAction script {
global currentMenuAction
if {$currentMenuAction eq ""} {
# Prepend a command to clear the variable
set act "set ::currentMenuAction {};$script"
set currentMenuAction [after idle $act]
}
}
# I don't like using lots of backslashes; your mileage may vary
.menubar.edit add command -label "Test Me" -command {
scheduleMenuAction {puts "you menued $accelerator-Shift-N"}
} -accelerator "${accelerator}-Shift-N"
bind_capslock all $modifier-Shift-Key N {
scheduleMenuAction {puts "you pressed $modifier-Shift-N"}
}