Delphi 捷径什么时候点火?

Delphi 捷径什么时候点火?,delphi,keyboard-shortcuts,vcl,Delphi,Keyboard Shortcuts,Vcl,昨天我发现了一种情况,在我预期的情况下,键盘快捷键没有启动 具体情况是:我按下了MDI子级上ActionList操作的快捷键组合,而MDI窗体上的侧栏被聚焦 我一直认为捷径可以在全球范围内发挥作用。他们到底在什么情况下开火?这是一个看似简单的问题,答案却出人意料地长。首先,我将处理一些基础知识,然后按照VCL代码的捷径进行操作,以最终得出—我希望—一个令人满意的结论 什么是捷径? 快捷键表示导致操作的一个或多个键的特殊键盘组合。特殊的意思是对赋予特定组合键意义的程序员来说是特殊的 在Delphi

昨天我发现了一种情况,在我预期的情况下,键盘快捷键没有启动

具体情况是:我按下了MDI子级上ActionList操作的快捷键组合,而MDI窗体上的侧栏被聚焦


我一直认为捷径可以在全球范围内发挥作用。他们到底在什么情况下开火?

这是一个看似简单的问题,答案却出人意料地长。首先,我将处理一些基础知识,然后按照VCL代码的捷径进行操作,以最终得出—我希望—一个令人满意的结论

什么是捷径? 快捷键表示导致操作的一个或多个键的特殊键盘组合。特殊的意思是对赋予特定组合键意义的程序员来说是特殊的

在Delphi中,快捷方式的类型为
TShortCut
,它被声明为
Word
范围(0..65535)内的整数。快捷方式通常由多个键构成,例如:

CTRL+K=
scCtrl
+
Ord('K')
=
16384
+
75
=
16459

如何指定快捷方式? 快捷键可以分配给动作的
ShortCut
secondary ShortCuts
属性或菜单项的
ShortCut
属性,从而在按下快捷键的键盘组合时调用该动作的
OnExecute
事件或菜单项的
OnClick
事件

要处理操作的快捷方式,必须启用该操作,并将其添加到未挂起的操作列表或附加到已启用的菜单项。同样,要处理菜单项的快捷方式,需要将菜单项添加到菜单中

快捷方式也可以从“s”、“a”或“OnShortCut”事件中进行解释。在这些事件中,
Msg
参数将keycode保存在其
CharCode
成员中,可以使用以下方法提取特殊键,如Shift、Ctrl或Alt:

procedure TForm1.FormShortCut(var Msg:TWMKey;var Handled:Boolean);
开始
如果(Msg.CharCode=Ord('K'))和(GetKeyState(VK_控制)<0),则
开始
标题:='CTRL+K按下';
已处理:=真;
结束;
结束;
如果
Handled
参数设置为
True
,则将跳过对密钥的任何后续处理

如何找到捷径? VCL不保留所有指定快捷方式的列表。(怎么可能呢?)。因此,所有按键都可能是一种快捷方式。这正是VCL解释快捷方式的方式:通过计算按下的每个键

彼得在下面写了一篇优秀而全面的文章,通过VCL处理。简而言之,一个快捷方式如下所示:

  • TApplication.Run
    拾取发送到应用程序的每个Windows消息
  • TApplication.ProcessMessage
    调用
    IsKeyMsg
    ,如果出现
    WM\u KEYDOWN
    消息,则将消息传递到
    CN\u KEYDOWN
    聚焦控件的
    消息处理程序
快捷方式是如何处理的?
TWinControl.CNKeyDown
检查键是否为菜单键(我们将看到此菜单的定义超出了物理菜单):

  • 首先检查该键是控件的快捷键还是其父控件的弹出菜单中的快捷键,
    • 1)遍历其所有(子)菜单项,并使用快捷方式(如果有)调用已启用菜单项的
      OnClick
      事件处理程序
  • 如果未处理,则通过调用2)检查该键是否是控件所在窗体的快捷方式,
    • 如果已分配,则调用表单的事件
    • 如果未处理,它将检查该键是否是窗体主菜单中的快捷键(请参见1)),如果有
    • 如果未处理,它会将密钥分派给表单所拥有的所有操作列表(仍在谈论活动表单)。在Delphi版本10(BDS2006)之前,这些操作列表需要由表单直接拥有,并保存在受保护的字段中(在需要时可以进行干预)。从2006年起,该领域被取消,行动清单也可以间接归表格所有。
      • 遍历其所有操作并调用已启用操作的
        HandleShortCut
        ,并在其
        ShortCut
        SecondaryShortCuts
        属性(如果有)中设置快捷方式
  • 如果未处理,则调用(通过
    CM\u APPKEYDOWN
    ),
    • 启动应用程序的事件,这包括项目中所有ApplicationEvents组件的事件(如果有)
    • 如果未处理,它将调用MainForm的
      IsShortCut
      例程(请参见2)),但仅在启用MainForm时调用。例如,当活动窗体是模态窗体时,主窗体将被禁用。这将触发主窗体的
      OnShortCut
      事件,或者将遍历主窗体的所有直接或间接拥有的操作列表(取决于上面提到的Delphi版本)
那么,什么时候处理快捷方式? 如果是:

  • 为连接到当前聚焦控件或其任何父控件的弹出菜单中的已启用菜单项设置
  • 设置当前活动窗体或主窗体上显示的主菜单中的已启用菜单项,但仅当主窗体已启用时
  • 为当前活动窗体或MainForm拥有的未挂起操作列表中的已启用操作设置,但仅当MainForm已启用时
  • 在当前活动窗体或
    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;