【问题标题】:Programmatically create a Shortcut STRING for the DELETE key?以编程方式为 DELETE 键创建快捷方式字符串?
【发布时间】:2021-08-29 06:21:59
【问题描述】:

在 Windows 10 x64 中的 Delphi 10.4.2 Win32 VCL 应用程序中,我使用此代码以编程方式为弹出菜单项上的 DELETE 键创建快捷方式字符串:

mGalleryDeleteSelected.Caption := mGalleryDeleteSelected.Caption + #9 + MyShortcutToString(VK_DELETE, []) + ' ';

这是源代码:

function MyGetKeyName(AKey: Integer): string;
var
  name: array[0..128] of Char;
begin
  FillChar(name, SizeOf(name), 0);
  GetKeyNameText(MapVirtualKey(AKey, 0) shl 16, @name[0], Length(name));
  Result := name;
end;

function MyModifierVirtualKey(AModifier: Integer): Integer;
begin
  case AModifier of
    Ord(ssShift):
      Result := VK_SHIFT;
    Ord(ssCtrl):
      Result := VK_CONTROL;
    Ord(ssAlt):
      Result := VK_MENU;
  else
    Result := 0;
  end;
end;

function MyShortcutToString(AKey: Integer; AShiftState: TShiftState = []): string;
begin
  Result := '';
  for var Modifier in AShiftState do
  begin
    var ModifierKey := MyModifierVirtualKey(Ord(Modifier));
    if ModifierKey <> 0 then
      Result := Result + IfThen(not Result.IsEmpty, '+') + MyGetKeyName(ModifierKey);
  end;
  Result := Result + IfThen(not Result.IsEmpty, '+') + MyGetKeyName(AKey);
end;

但是,我没有获得普通 DELETE 键的快捷方式字符串,而是获得了数字键盘上(辅助?)逗号/删除键的快捷方式字符串:

因为我有一个德语 Windows,这里是翻译:

KOMMA = 逗号
ZEHNERTASTATUR = 数字小键盘
德语键盘上的默认 Delete 键带有标签“entf”(“Entfernen”的缩写)

如果数字小键盘设置为用于导航命令,则按数字小键盘上的逗号键确实可以作为删除命令。但是,我需要获取 NORMAL DELETE 键的字符串。我该怎么做?

【问题讨论】:

    标签: delphi keyboard-shortcuts delphi-10.4-sydney


    【解决方案1】:

    来自GetKeyNameText 的文档:

    24 扩展键标志。区分增强型键盘上的一些键。

    这表示它使用 LPARAM 样式参数中的第 24 位作为扩展键标志。

    然后,在About Keyboard Input

    扩展键标志

    扩展键标志指示击键消息是否源自增强键盘上的附加键之一。扩展键由键盘右侧的 ALT 和 CTRL 键组成; 数字键盘左侧集群中的 INS、DEL、HOME、END、PAGE UP、PAGE DOWN 和箭头键;数字锁定键; BREAK (CTRL+PAUSE) 键;打印 SCRN 键;以及数字键盘中的除 (/) 和 ENTER 键。如果密钥是扩展密钥,则设置扩展密钥标志。

    (正文强调我的)。

    因此,我得出结论,您可以使用

    function MyGetKeyName(AKey: Integer): string;
    var
      name: array[0..128] of Char;
    begin
      FillChar(name, SizeOf(name), 0);             // ADD THIS! 
      GetKeyNameText(MapVirtualKey(AKey, 0) shl 16 or 1 shl 24, @name[0], Length(name));
      Result := name;
    end;
    

    获取键盘字母和数字部分之间的Del 键的名称。

    当然,您可能不想为其他键设置此位,因此您需要重构代码。不幸的是,VK_DELETE 似乎可以映射到两个物理键。

    这是一种方法:

    function MyGetKeyName(AKey: Integer; AExtended: Boolean = False): string;
    var
      name: array[0..128] of Char;
    begin
      FillChar(name, SizeOf(name), 0);
      if                                             // ADD THIS! 
        GetKeyNameText(MapVirtualKey(AKey, 0) shl 16 or Cardinal(Ord(AExtended)) shl 24,
          @name[0], Length(name)) <> 0
      then
        Result := name
      else
        Result := '';
    end;
    

    并将此参数也添加到您的MyShortcutToString(只需将其传递给MyGetKeyName):

    function MyShortcutToString(AKey: Integer; AShiftState: TShiftState = [];
      AExtended: Boolean = False): string;
    begin
      Result := '';
      for var Modifier in AShiftState do
      begin
        var ModifierKey := MyModifierVirtualKey(Ord(Modifier));
        if ModifierKey <> 0 then
          Result := Result + IfThen(not Result.IsEmpty, '+') + MyGetKeyName(ModifierKey);
      end;
      Result := Result + IfThen(not Result.IsEmpty, '+') + MyGetKeyName(AKey, AExtended);
    end;
    

    【讨论】:

    • 一如既往,您的解决方案巧妙且解释清楚!令人惊讶的是,一个只有 105 个键的键盘可以放入多少扩展位!在接下来的几天里,我会打坐每一个点,看看我是否会开悟。谢谢!
    • 顺便说一句,这里编译器会发出一个关于组合有符号和无符号类型的警告(扩大了两个操作数):GetKeyNameText(MapVirtualKey(AKey, 0) shl 16 or Ord(AExtended) shl 24, @name[0], Length(name));
    • @user1580348:已修复。
    • 您应该检查 GetKeyNameText 的返回值是否有错误。我认为您也不需要将数组填充为零。
    • @DavidHeffernan:我怀疑GetKeyNameText 如果发生错误不会触及缓冲区(或将其设置为空字符串),在这种情况下,该函数将相当合理地返回空字符串,但是你是对的:这没有明确记录,您应该始终检查返回值。关于归零,我认为这是最佳实践,但同意在这种情况下可能没有必要。但是当然,由于当前编写的代码,如果GetKeyNameText 失败,则需要清零
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 2020-03-07
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多