I'm testing a component inheriting from TDBMemo
that can show asterisks instead of the actual data (swapping the DataField
to an internalCalc
field with asterisks when 'in hidden mode').
Editing the control is not very useful 'in hidden mode' so I have an OnKeyPress
that 'eats' all key presses except the combinations that paste text (Ctrlv and ShiftIns).
A procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
then makes sure that the 'original' dataset field is updated, not the 'asterisked' one.
This is the OnKeyPress handler:
procedure TPasteCatchDBMemo.PasteCatchDBMemoKeyPress(Sender: TObject; var Key: Char);
var
lCtrl,
lShift,
lPaste: Boolean;
begin
if not FPasswordMode then Exit; // Everything allowed
lCtrl := (GetKeyState(VK_CONTROL) < 0); // High bit set
lShift := (GetKeyState(VK_SHIFT) < 0);
lPaste := lCtrl and ((Key = 'V') or (Key = 'v') or (Key = #$16))
or
lShift and (GetKeyState(VK_INSERT) < 0);
if not lPaste then
Key := #0;
end;
Question: If I press Ctrlv, the value for Key
is not 'V' (decimal 86) or 'v' (decimal 118). It is the #$16 (decimal 22) that I had to add to make this work.
Where does this #$16 come from?
This is a Delphi 12, Win32 or Win64, test app.
V is the 22nd letter of the alphabet. Thus, ^V = #22
.
Personally, I often take advantage of this fact:
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
case Key of
^A:
ShowMessage('User wants to select all.');
^Z:
ShowMessage('User wants to undo.');
^Y:
ShowMessage('User wants to redo.');
^X:
ShowMessage('User wants to cut.');
^C:
ShowMessage('User wants to copy.');
^V:
ShowMessage('User wants to paste.');
end;
end;
The historical and technical details of this syntax (the caret syntax) and design (these "chars" being sent to the OnKeyPress
handler) can be found in several other Q&As on StackOverflow: