6

这甚至可能吗?例如 Notepad++ 就可以做到,但简单地尝试将其分配给操作或菜单项等组件是行不通的。它分配给的事件根本不会触发。

所以,我把我的问题带到了谷歌。纳达。然后,我尝试逐步了解各种快捷功能,在本例中为 TextToShortCut 和 ShortCutToText。

第一个,TextToShortCut,将诸如“Ctrl+A”(一个字符串)之类的东西转换为以下 16 位值:

(uint)A | (uint)Ctrl

工作正常,主要是。但是,我观察到以下奇怪现象:

// Try converting back and forward...
TextToShortCut('Ctrl+/') = 16495

// That's incorrect. It should be:
Ord('/') or scCtrl = 16431

// Incorrect too
ShortCutToText(16495) = 'Ctrl+/'

// This is the shortcut the first line actually creates (Ctrl+o)
Ord('o') or scCtrl = 16495 // wut?

// Which is invalid, cause only caps are used
ShortCutToText(16431) = ''

这里发生了什么?目前,我认为错误在于 TextToShortCut 的最后部分:在处理完 + 号之前的部分(本例中为“Ctrl”)后,它将尝试为剩余部分(“/”)找到快捷方式。但是,在其当前形式中,+ 之后的部分本身也必须是一个有效的快捷方式。

for Key := $08 to $255 do { Copy range from table in ShortCutToText }
  if AnsiCompareText(Text, ShortCutToText(Key)) = 0 then
  begin
    Result := Key or Shift;
    Exit;
  end;

所以,因为:

ShortCutToText('/') = 0 (failure)
MapVirtualKey('/',MAPVK_VK_TO_VSC) = 0 (failure)

...循环无法将“/”检测为有效的快捷方式。

这是一些 VCL 错误还是我错过了什么?

这是一个概念证明(是的,我正在截取代码的屏幕截图,但是将其与 Component Palette 混合在一起比直接使用此代码要快):

编辑1:

在此处输入图像描述

编辑2:

手动将 16431 分配给菜单项不起作用。

4

2 回答 2

12

如果将OnShortCut事件处理程序分配给菜单的 parent TForm,您将看到按Ctrl+会产生16575/的值,这是 VCL 在为快捷键处理分派击键时在内部使用的函数。TShortCutMenus.ShortCutFromMessage()

ShortCutToText(16495)和return ,所以ShortCutToText(16575)'Ctrl+/'我们分解一下:

scCtrl = $4000
16495 = $406F
16575 = $40BF

两个快捷方式都有scCtrl标志。

ShortCutToText($6F)并且ShortCutToText($BF)都返回'/'。这是因为为虚拟键( ) 和( -美国键盘的键)MapVirtualKey()返回相同的扫描代码 ($350000 )。$6FVK_DIVIDE$BFVK_OEM_2/?

调度快捷方式时,VCL 会精确比较TShortCut值。因此,当您将 16495 指定为快捷方式时,它不会触发,因为系统正在报告 16575 的快捷方式,即使它们都映射到Ctrl+/.

当我将 16575 分配给a or的ShortCut属性时,按+会按预期触发该项目。TMenuItemTActionCtrl/

所以诀窍是系统报告了一个使用VK_OEM_2虚拟键的快捷方式/,但您希望它使用VK_DIVIDE虚拟键代替。

于 2013-09-10T17:23:25.823 回答
7

Key对事件处理程序的简单调查OnKeyDown显示了两种不同类型的正斜杠:

  • /在数字小键盘上 = 111(与CTRL=结合16575
  • /旁边的 shift 键 = 191(结合CTRL= 16495

不可能创建一个同时响应两者的快捷方式。

但是,您可以附加一个具有SecondaryShortCuts属性的操作,而不是在 memu 项目上设置快捷方式。然后使用:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Action1.ShortCut := 16575;
  Action1.SecondaryShortCuts.Add('Ctrl+/');
end;
于 2013-09-10T17:40:20.323 回答