I have a VCL form with many tframes
(referred to as tcellFrame) containing components arranged in a grid. I am using mouse clicks and arrow keys for the user to navigate between them. The mouse clicks work fine, but I had trouble with the arrow keys until I discovered this question thread: Delphi XE and Trapping Arrow Key with OnKeyDown
. The solution in Sertac Akyuz's answer does handle getting the arrow key messages to the form using
procedure TForm1.DialogKey(var Msg: TWMKey);
begin
case Msg.CharCode of
VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
if Assigned(onKeyDown) then
onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
else
inherited
end;
end;
but acts upon the form twice for each key stroke. Instead of moving to the left one cellframe, it moves two. Tracing the thread using the debugger demonstrates that the onkeydown event is called twice.
My onKeyDown
event is structured as follows:
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
i : integer;
g, r, c, str : string;
tmpFrame : tcellFrame; //frame component containing tlabels
begin
...
case key of
VK_UP:
begin
//calc new cell location values for g,r,c
str := ('Cell'+g+r+c);
picklist.Clear; // picklist is a form-wide tstringlist variable containing currently selected cellframes.
picklist.add (str);
TmpFrame := FindComponent(picklist [0]) as TCellFrame;
tmpframe.Color := pickClr;
end;
//VK_DOWN, VK_LEFT, VK_RIGHT: defined similarly to VK_UP
end;
end;
There is more code in Formkeydown
, but it is all internal calculations to determine the proper tcellframe name to place in the picklist.
My questions are:
In your CM_DIALOGKEY
message handler, return a non-zero value if you handle the key, then it won't be dispatched further.
procedure TForm1.DialogKey(var Msg: TWMKey);
begin
case Msg.CharCode of
VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT:
begin
if Assigned(onKeyDown) then
onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
Msg.Result := 1; // <-- add this
end;
else
inherited;
end;
end;
However, if you have KeyPreview=True
on the Form and the arrow keys are already being dispatched normally, then there is no need to handle CM_DIALOGKEY
at all, just let the Form's OnKey...
events get dispatched normally. You should not be firing the Form's OnKey...
events from a CM_DIALOGKEY
handler.
See A Key's Odyssey for more details.