When using a full-size keyboard, there is a row of keypad on the right side of the keyboard
However, the numeric key value of this keypad is different from that of the ordinary keyboard.
The standard numeric key value in the ANSI code is $30... $39, and the keypad key value is $60... $69
This problem arises. When we set the limit cut of action in the Attribute Editor, we use a text representation, while in the VCL architecture, the character representation of the limit cut does not differentiate the size of the keyboard number key.
Let's take a look at the text to convert it into a cut:
In the menus unit: texttoshortcut (Text: string): tshortcut; Function
function TextToShortCut(Text: string): TShortCut; { If the front of Text is equal to Front then remove the matching piece from Text and return True, otherwise return False } function CompareFront(var Text: string; const Front: string): Boolean; begin Result := False; if (Length(Text) >= Length(Front)) and (AnsiStrLIComp(PChar(Text), PChar(Front), Length(Front)) = 0) then begin Result := True; Delete(Text, 1, Length(Front)); end; end;var Key: TShortCut; Shift: TShortCut;begin Result := 0; Shift := 0; while True do begin if CompareFront(Text, MenuKeyCaps[mkcShift]) then Shift := Shift or scShift else if CompareFront(Text, ‘^‘) then Shift := Shift or scCtrl else if CompareFront(Text, MenuKeyCaps[mkcCtrl]) then Shift := Shift or scCtrl else if CompareFront(Text, MenuKeyCaps[mkcAlt]) then Shift := Shift or scAlt else Break; end; if Text = ‘‘ then Exit; 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;end;
Pay attention to the lines highlighted. Actually, it is $08 ~ Make a comparison between all the characters of $255 and the passed characters, so our focus is on shortcuttotext:
function ShortCutToText(ShortCut: TShortCut): string;var Name: string;begin case WordRec(ShortCut).Lo of $08, $09: Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcBkSp) + WordRec(ShortCut).Lo - $08)]; $0D: Name := MenuKeyCaps[mkcEnter]; $1B: Name := MenuKeyCaps[mkcEsc]; $20..$28: Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcSpace) + WordRec(ShortCut).Lo - $20)]; $2D..$2E: Name := MenuKeyCaps[TMenuKeyCap(Ord(mkcIns) + WordRec(ShortCut).Lo - $2D)]; $30..$39: Name := Chr(WordRec(ShortCut).Lo - $30 + Ord(‘0‘)); $41..$5A: Name := Chr(WordRec(ShortCut).Lo - $41 + Ord(‘A‘)); $60..$69: Name := Chr(WordRec(ShortCut).Lo - $60 + Ord(‘0‘)); $70..$87: Name := ‘F‘ + IntToStr(WordRec(ShortCut).Lo - $6F); else Name := GetSpecialName(ShortCut); end; if Name <> ‘‘ then begin Result := ‘‘; if ShortCut and scShift <> 0 then Result := Result + MenuKeyCaps[mkcShift]; if ShortCut and scCtrl <> 0 then Result := Result + MenuKeyCaps[mkcCtrl]; if ShortCut and scAlt <> 0 then Result := Result + MenuKeyCaps[mkcAlt]; Result := Result + Name; end else Result := ‘‘;end;
Obviously, the standard and keypad numeric keys are all mapped to 0 ~ 9, then the standard keyboard will be recognized when texttoshortcut is used.
Therefore, in general, you cannot set the keypad hotkeys In the Attribute Editor. You can only solve this problem through code:
In code mode, the cut attribute of action is a tshortcut type: tshortcut = low (Word) .. High (Word); that is, it is an ANSI character
Then we can directly use the key value to set the shortcut cut, and bypass the text conversion step, so as to achieve the purpose of using the keypad shortcut:
Action1.ShortCut := Menus.ShortCut(VK_NUMPAD0, [ssCtrl]);
In this way, you can easily set a Ctrl + keypad 0 shortcut.
So, if you want to set both the standard key 0 and keypad 0, how can this action be activated?
This requires another attribute: secondaryshortcuts, which is actually a tstringlist
property SecondaryShortCuts: TShortCutList TShortCutList = class(TStringList) private function GetShortCuts(Index: Integer): TShortCut; public function Add(const S: String): Integer; override; function IndexOfShortCut(const Shortcut: TShortCut): Integer; property ShortCuts[Index: Integer]: TShortCut read GetShortCuts; end;
OK. Now another problem occurs. We write multiple shortcut keys to secondaryshortcuts, which is the add method. Unfortunately .... add is a text, so we can go back to the problem at the beginning, the text cannot distinguish the size of the keyboard number key, what to do... -_-
Some people may say that the keyboard is set to the shortcut, and the big keyboard uses secondaryshortcuts and OK. Of course this is okay... but it is never an orthodox solution (programmer's paranoia)
Study code:
function TShortCutList.Add(const S: String): Integer;begin Result := inherited Add(S); Objects[Result] := TObject(TextToShortCut(S));end;function TShortCutList.GetShortCuts(Index: Integer): TShortCut;begin Result := TShortCut(Objects[Index]);end;
There seems to be a way to solve this problem. During the add operation, the export cut is forced to be converted to the tobject type and saved in objects (in fact, it is a clever way, so I always do it myself... ^_^)
The string is not read when the shortcut is read, and the object is read directly. Can we directly write objects? Try:
Action1.SecondaryShortCuts.AddObject(‘Ctrl+Num0‘, TObject(Menus.ShortCut(VK_NUMPAD0, [ssCtrl])));
OK. The test is completely feasible... the problem is solved perfectly.