Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3188
  • Last Modified:

How do I Identify Key Down, Key Up, Key Press events in FormShortCut of a Form.

Hi,
  I want to do some job in key down of one of the Arrow Keys and some other job in key up of that same Arrow Key. FormShortCut is firing two times for a single press  of a key. I think it is firing once for Key Down and firing once for Key Up.  How can I Identify that Key is Down or Up or Pressed from FormShortCut of MainForm. The TWMKey structure is as follows, which is the one of the parameters of FormShortCut,
  TWMKey = packed record
    Msg: Cardinal;
    CharCode: Word;
    Unused: Word;
    KeyData: Longint;
    Result: Longint;
  end;
Which variable tells that which key event is fired.
0
inampudi1
Asked:
inampudi1
  • 9
  • 9
1 Solution
 
ziolkoCommented:
why don't you use OnKeyUp and OnKeyDown event handlers?

ziolko.
0
 
Geert GruwezOracle dbaCommented:
you have an OnKeyDown event and an OnKeyUp event
you could use this to set a parameter for the direction

type
  TKeyDirection = (kdNone, kdDown, kdUp);

  TForm1 = class(TForm)
    procedure FormKeyUp(Sender: TObject; var Key: Word;  Shift: TShiftState);
    procedure FormKeyDown(Sender: TObject; var Key: Word;  Shift: TShiftState);
  private
    fKeyDirection: TKeyDirection;
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  fKeyDirection := kdNone;
end;

procedure FormKeyUp(Sender: TObject; var Key: Word;  Shift: TShiftState);
begin
  fKeyDirection := kdUp;
  inherited;
end;

procedure FormKeyDown(Sender: TObject; var Key: Word;  Shift: TShiftState);
begin
  fKeyDirection := kdDown;
  inherited;
end;
0
 
ziolkoCommented:
Geert OnShortcut is triggered before before key up/down

ziolko.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Geert GruwezOracle dbaCommented:
only thought about OnKeyDown, OnKeyUp first ...
can't think of 2 things at the same time (i'm only a man)

look into the code it's fired by the Application and WM_APPKEYDOWN

0
 
Geert GruwezOracle dbaCommented:
with below code you can find the order of the events

FormShortCut allways fires

The OnkeyDown and OnKeyUp only fire with Form1.KeyPreview := True;
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ExtCtrls, StdCtrls;
 
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Panel1: TPanel;
    MainMenu: TMainMenu;
    est1: TMenuItem;
    est21: TMenuItem;
    est31: TMenuItem;
    procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean);
    procedure FormKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
  private
    function ShiftString(Shift: TShiftState): string;
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Memo1.Lines.Add('ShortCut' +
    Format('Msg=%d, CharCode=%d, Unused=%d, KeyData=%d, Result=%d',
      [Msg.Msg, Msg.CharCode, Msg.Unused, Msg.KeyData, Msg.Result]));
end;
 
function TForm1.ShiftString(Shift: TShiftState): string;
begin
  Result := '';
  if ssCtrl in Shift then
    Result := Result + 'Ctrl,';
  if ssLeft in Shift then
    Result := Result + 'Left,';
  if ssRight in Shift then
    Result := Result + 'Right,';
  if ssMiddle in Shift then
    Result := Result + 'Middle,';
  if ssDouble in Shift then
    Result := Result + 'Double,';
  if ssShift in Shift then
    Result := Result + 'Shift,';
  if ssAlt in Shift then
    Result := Result + 'Alt,';
  if (Result <> '') then
    Delete(Result, Length(Result), 1);
end;
 
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  Memo1.Lines.Add('KeyUp ' +
    Format('Key=%d, Shift=%s',
      [Key, ShiftString(Shift)]));
end;
 
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  Memo1.Lines.Add('KeyDown ' +
    Format('Key=%d, Shift=%s',
      [Key, ShiftString(Shift)]));
end;
 
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  Memo1.Lines.Add('KeyPress ' +
    Format('Key=%s',
      [Key]));
end;
 
end.

Open in new window

0
 
ziolkoCommented:
OnShortCut indeed with one arrow keystroke event is triggered two times,
first time:
  Msg.Msg = CN_KEYDOWN
second time:
  Msg.Msg = CM_APPKEYDOWN

ziolko.
0
 
Geert GruwezOracle dbaCommented:
Memo1
ShortCutMsg=48384, CharCode=65, Unused=0, KeyData=1048577, Result=1
ShortCutMsg=45078, CharCode=65, Unused=0, KeyData=1048577, Result=0
KeyDown Key=65, Shift=
KeyPress Key=a
a
KeyUp Key=65, Shift=

this is what i got from the test application and just pressing "a"

The difference is Result = 1 and Result = 0 and the ShortCutMsg ...
as ... ah you found the Msg id's ziolko, nice
0
 
ziolkoCommented:
procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  if Msg.Msg = CN_KEYDOWN then
    Memo1.Lines.Add('first trigger');
  if Msg.Msg = CM_APPKEYDOWN then
    Memo1.Lines.Add('second trigger');
end;

ziolko.
0
 
Geert GruwezOracle dbaCommented:
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=21495809, Result=1
ShortCutMsg=45078, CharCode=38, Unused=0, KeyData=21495809, Result=0
KeyDown Key=38, Shift=
KeyUp Key=38, Shift=

this is for the up arrow
you only get Key Up with KeyPreview := True
0
 
inampudi1Author Commented:
Hi,


I got the solution....
TMainFrm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
in this
Msg.Result  will give  wether key down or up.
if Msg.Result  = 0 means key up.
0
 
ziolkoCommented:
Result is evaluated based on IsShortCut() function which checks ActionLists so I would check for Msg.Msg values

ziolko.
0
 
Geert GruwezOracle dbaCommented:
nope, it just means it was evaluated as being a shortcut
0
 
Geert GruwezOracle dbaCommented:
just try it with holding down your arrow key ...
my app gives this when holding down the arrow key a second
the onkeyup is only shown at the end

ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=21495809, Result=1
ShortCutMsg=45078, CharCode=38, Unused=0, KeyData=21495809, Result=0
KeyDown Key=38, Shift=
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=1095237633, Result=1
ShortCutMsg=45078, CharCode=38, Unused=0, KeyData=1095237633, Result=0
KeyDown Key=38, Shift=
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=1095237633, Result=1
ShortCutMsg=45078, CharCode=38, Unused=0, KeyData=1095237633, Result=0
KeyDown Key=38, Shift=
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=1095237633, Result=1
ShortCutMsg=45078, CharCode=38, Unused=0, KeyData=1095237633, Result=0
KeyDown Key=38, Shift=
KeyUp Key=38, Shift=
0
 
ziolkoCommented:
>>nope, it just means it was evaluated as being a shortcut
yup, but look how it's evaluated:

function TCustomForm.IsShortCut(var Message: TWMKey): Boolean;

  function DispatchShortCut(const Owner: TComponent) : Boolean;
  var
    I: Integer;
    Component: TComponent;
  begin
    Result := False;
    { Dispatch to all children }
    for I := 0 to Owner.ComponentCount - 1 do
    begin
      Component := Owner.Components[I];
      if Component is TCustomActionList then
      begin
        if TCustomActionList(Component).IsShortCut(Message) then
        begin
          Result := True;
          Exit;
        end
      end
      else
      begin
        Result := DispatchShortCut(Component);
        if Result then
          Break;
      end;
    end;
  end;

begin
  Result := False;
  if Assigned(FOnShortCut) then FOnShortCut(Message, Result);
  Result := Result or (Menu <> nil) and (Menu.WindowHandle <> 0) and
    Menu.IsShortCut(Message) or DispatchShortCut(Self);
end;

ziolko.
0
 
ziolkoCommented:
 if IsShortCut(Message) then
    Message.Result := 1
  else
    Message.Result := 0;

so are you sure that Result = 1 is alwyas keydown and 0 is keyup?

ziolko.
0
 
ziolkoCommented:
try this:

procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Handled := True;
  Memo1.Lines.Add(IntToStr(Msg.Result));
end;


ziolko.
0
 
ziolkoCommented:
ok, not the best example as Handled := True; will cause OnShortCut to trigger only once per keystroke but still I beleive that checking .Msg is better than .Result

ziolko.
0
 
Geert GruwezOracle dbaCommented:
lol, only message with Result = 1

and holding down the arrow key:

ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=21495809, Result=1
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=1095237633, Result=1
...
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=1095237633, Result=1
ShortCutMsg=48384, CharCode=38, Unused=0, KeyData=1095237633, Result=1
KeyUp Key=38, Shift=
0
 
Geert GruwezOracle dbaCommented:
Have you assigned the ShortCut key to the menu ?

Do you want your app to do an action before and after the Action/Menu to which the shortcut is assigned ?

or are you just using this event to catch OnKeyUp and OnKeyDown ?
this last thing, i believe, is impossible
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 9
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now