Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically create a Shortcut STRING for the DELETE key?

In a Delphi 10.4.2 Win32 VCL Application in Windows 10 x64, I use this code to programmatically create a Shortcut STRING for the DELETE key on a popup menu item:

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

This is the source-code:

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;

However, instead of getting the shortcut string for the normal DELETE key, I get the shortcut string for the (auxiliary?) Comma/Delete key on the Numeric keypad:

enter image description here

As I have a German language Windows, here are the translations:

KOMMA = comma
ZEHNERTASTATUR = numeric keypad
The default Delete key on a German keyboard has the label "entf" (abbreviation for "Entfernen")

The keypress of the comma key on the numeric keypad does work as a Delete command if the numeric keypad is set to work for navigation commands. However, I need to get the string for the NORMAL DELETE key. How can I do that?

like image 944
user1580348 Avatar asked Mar 01 '23 13:03

user1580348


1 Answers

From the documentation for GetKeyNameText:

24 Extended-key flag. Distinguishes some keys on an enhanced keyboard.

This says that it uses bit 24 in the LPARAM-styled argument as the extended-key flag.

Then, in About Keyboard Input:

Extended-Key Flag

The extended-key flag indicates whether the keystroke message originated from one of the additional keys on the enhanced keyboard. The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad. The extended-key flag is set if the key is an extended key.

(body text emphasis mine).

Therefore, I conclude, that you can use

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;

to get the name of the Del key between the alphabetical and numeric parts of the keyboard.

Of course, you probably don't want to set this bit for other keys, so you need to refactor your code. Unfortunately, it seems like VK_DELETE can map to two physical keys.

Here's one approach:

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;

and add this parameter to your MyShortcutToString as well (which only need to pass it to 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;
like image 68
Andreas Rejbrand Avatar answered Mar 16 '23 02:03

Andreas Rejbrand