这是一个看似简单的问题,答案却长得惊人。首先,我将处理一些基础知识,然后通过 VCL 代码遵循 ShortCut 最终得出 - 我希望 - 一个令人满意的结论。
什么是快捷方式?
ShortCut 表示一个或多个可导致操作的键的特殊键盘组合。 特殊对于赋予特定组合键意义的程序员来说是特殊的。
在 Delphi 中,ShortCut 的类型为 TShortCut,它被声明为 Word 范围 (0..65535) 内的整数。快捷方式通常由几个键构成,例如:
CTRL+K = scCtrl + Ord('K') = 16384 + 75 = 16459。
如何指定快捷方式?
ShortCuts 可以分配给 Action 的 ShortCut 或 SecondaryShortCuts 属性或 MenuItem 的 ShortCut 属性,从而在 ShortCut 的键盘组合时调用该 Action 的 OnExecute 事件或 MenuItem 的 OnClick 事件被按下。
要处理 Action 的 ShortCut,需要启用该 Action,并将其添加到未暂停的 ActionList 或附加到已启用的 MenuItem。同样,要处理 MenuItem 的 ShortCut,需要将 MenuItem 添加到 Menu。
ShortCut 也可以从 Application's、Form's 或 ApplicationEvents'OnShortCut 事件中解释。在这些事件中,Msg 参数在其CharCode 成员中保存键码,以及可能的特殊键,如 Shift、Ctrl 或 Alt可以使用GetKeyState提取:
procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
if (Msg.CharCode = Ord('K')) and (GetKeyState(VK_CONTROL) < 0) then
begin
Caption := 'CTRL+K pressed';
Handled := True;
end;
end;
如果Handled 参数设置为True,则将跳过对该密钥的任何后续处理。
快捷方式是如何捕获的?
VCL 不保留所有指定快捷方式的列表。 (怎么可能?)。因此,all 击键可能是快捷方式。这正是 VCL 解释 ShortCuts 的方式:通过评估每个按下的键。
Peter below 写了一篇优秀而全面的文章,通过 VCL 处理A Key's Odyssey。简而言之,一个 ShortCut 被捕获如下:
-
TApplication.Run 接收发送到应用程序的每条 Windows 消息,
-
TApplication.ProcessMessage 调用 IsKeyMsg 将消息(如果是 WM_KEYDOWN 消息)传递给 focused Control 的 CN_KEYDOWN 消息处理程序。
ShortCut 是如何处理的?
TWinControl.CNKeyDown 检查该键是否为菜单键(我们将看到此 menu 的定义超出了物理菜单):
-
TWinControl.IsMenuKey 首先检查该键是否是控件中的快捷方式或其父项的 PopupMenu 之一,
- 如果未处理,则调用
TCustomForm.IsShortCut2),检查该键是否是控件所在表单的快捷方式,
-
OnShortCut 表单的事件被调用,如果已分配,
- 如果未处理,它会检查该键是否是 Form 的 MainMenu(参见 1))中的快捷方式(如果有)
- 如果未处理,它会将密钥分派给表单拥有的所有 ActionLists(仍在讨论活动表单)。在 Delphi 版本 10 (BDS2006) 之前,这些 ActionList 需要由 Form 直接拥有,并保存在受保护的(在需要时可以进行干预)字段
FActionLists 中。 That was considered a bug 和从 BDS2006 开始,该字段已被删除,并且 ActionLists 也可以由 Form 间接拥有。
- 如果未处理,则调用
Application.IsShortCut(通过CM_APPKEYDOWN),
- 应用程序的
OnShortCut事件被触发,这包括项目内所有ApplicationEvents组件的OnShortCut事件,如果有分配的话,
- 如果未处理,则调用 MainForm 的
IsShortCut 例程(参见 2)),但仅在启用 MainForm 时 >。例如。当活动表单是模态表单时,MainForm 将被禁用。这将触发 MainForm 的 OnShortCut 事件 或将遍历所有直接或间接拥有的 MainForm 的 ActionLists(取决于上面提到的 Delphi 版本)。
那么,ShortCut 什么时候处理?
什么时候:
- 为 PopupMenu 中启用的 MenuItem 设置,该菜单项附加到当前聚焦的 Control 或其任何父级,
- 为 MainMenu 中启用的 MenuItem 设置,该菜单项显示在当前活动的 Form 或 MainForm 上,但仅在启用 MainForm 时,
- 为当前活动表单或 MainForm 拥有的未暂停 ActionList 中启用的 Action 设置,但仅当 MainForm 启用时,
- 在当前活动窗体或 MainForm 的
OnShortCut 事件中捕获,但仅在启用 MainForm 时,
- 在 Applicaton 或任何 ApplicationEvents 组件的
OnShortCut 事件中捕获。
什么时候没有处理快捷方式?
当它被设置为:
- 禁用的 MenuItem,
- 没有菜单的 MenuItem,
- MainMenu 中未附加到表单的 MenuItem,
- PopupMenu 中附加到同级的 MenuItem,
- 已禁用的操作,
- 没有 ActionList 的动作,
- ActionList 中的一个 Action,不属于当前活动的 Form 或 MainForm。例如:另一个表单、数据模块、应用程序、实用程序单元等...
- ActionList 中的一个 Action,不直接由当前活动的 Form 或 BDS2006 以下 Delphi 版本中的 MainForm 所有。