如何为分配有 `VK_NUMPAD0` 的菜单项快捷方式显示 "NUMERIC KEYPAD"?

How to show "NUMERIC KEYPAD" for menu item shortcut assigned with `VK_NUMPAD0`?

在 Delphi 10.4.2 Win32 VCL 应用程序中,在 Windows10 X64(德语)上,我以编程方式设置了一些菜单项的快捷方式:

mRasterizedDoubleSize.Shortcut := VK_ADD;
mRasterizedHalveSize.Shortcut := VK_SUBTRACT;
mRasterizedResetToOriginalSVGSize.Shortcut := VK_NUMPAD0;

这会在 运行 时产生以下菜单:

(“ZEHNERTASTATUR”是德语数字键盘)

为什么第三个菜单项没有显示“Zehnertastatur”(数字小键盘)?

如何为分配给 VK_NUMPAD0 的菜单项快捷方式显示“ZEHNERTASTATUR”(数字键盘)?

我已在 Vcl.Menus 中针对此错误提交质量报告:https://quality.embarcadero.com/browse/RSP-33296 请为它投票!

编辑:我已经尝试过 Andreas 的建议,但它确实只在 运行 时以编程方式工作,而不是在对象检查器的设计时工作:

mRasterizedResetToOriginalSVGSize.Caption := mRasterizedResetToOriginalSVGSize.Caption + #9 + '0 (NUMPAD)  ';

难道没有在-运行-时间将单词“NUMPAD”翻译成当前系统语言的功能吗?

EDIT2:我试过这个来获取 VK_NUMPAD0 快捷方式的单词,但它只返回没有“NUMPAD”后缀的相同“0” :

var s: TShortCut;
s := ShortCut(VK_NUMPAD0, []);
CodeSite.Send('TformMain.FormCreate: ShortCutToText(s)', ShortCutToText(s));

EDIT3:我现在已经调试了 Vcl.Menus:错误似乎在 Vcl.Menus.ShortCutToText:而 VK_ADD ($6B) 是GetSpecialName(ShortCut) 正确翻译,VK_NUMPAD0 ($60) 未被 GetSpecialName(ShortCut)!

翻译

EDIT4:我找到了解决方案:

function MyGetSpecialName(ShortCut: TShortCut): string;
var
  ScanCode: Integer;
  KeyName: array[0..255] of Char;
begin
  Result := '';
  ScanCode := Winapi.Windows.MapVirtualKey(LoByte(Word(ShortCut)), 0) shl 16;
  if ScanCode <> 0 then
  begin
    if Winapi.Windows.GetKeyNameText(ScanCode, KeyName, Length(KeyName)) <> 0 then
      Result := KeyName;
  end;
end;

var s: System.Classes.TShortCut;
s := ShortCut(VK_NUMPAD0, []);
CodeSite.Send('ShortCutToText', MyGetSpecialName(s));

一种方法是这样的:

使用 TActionList。这是一般的好习惯。在此列表中定义您的操作,然后简单地将它们映射到菜单项、按钮、复选框等。操作列表功能是 VCL 恕我直言的最佳部分之一。

现在,创建一个名为 aResetZoomCaption = 'Reset zoom'#9'Numpad 0' 且没有 ShortCut 的操作。把它放在菜单栏上。

然后,创建一个名为 aResetZoomShortcutnew 操作,具有相同的 OnExecute(也可能相同的 OnUpdate)和快捷方式 Num 0(在设计时设置或在 运行 时以编程方式设置)。不要把它放在主菜单上。

结果:

当我按下小键盘 0(而不是 alpha 0)时触发操作。

这种方法有很多变体。也许您可以通过没有 ShortCut 但在其 SecondaryShortCuts 列表中使用 Num 0 的单个操作来使其工作。或者您可以使用表单的 KeyPreviewOnKeyPress 属性来代替“虚拟”操作。

多种选择。选择最适合您的特定场景的一种。

奖金备注

请注意,完全有可能在设计时使用 Object 检查器设置带制表符的标题。参见 example video

您或许可以使用 Win32 GetKeyNameText 功能进行本地化。以下代码改编自 VCL:

var
  name: array[0..128] of Char;
begin
  FillChar(name, SizeOf(name), 0);
  GetKeyNameText(MapVirtualKey(VK_NUMPAD0, 0) shl 16, @name[0], Length(name));
  // string(name) now is 'NUM 0' on my system

话虽如此,我个人并不介意快捷方式描述是 non-localized 还是手动本地化——就像应用程序的其余部分一样。

更新

关于如何使用本地化代码的说明:

procedure TForm5.FormCreate(Sender: TObject);
var
  name: array[0..128] of Char;
  NameAsANormalString: string;
begin
  FillChar(name, SizeOf(name), 0);
  GetKeyNameText(MapVirtualKey(VK_NUMPAD0, 0) shl 16, @name[0], Length(name));
  NameAsANormalString := name;
  ShowMessage(name);
end;

产生

在我的系统上。