Solved

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

Posted on 2008-10-02
19
3,015 Views
Last Modified: 2012-06-27
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
Comment
Question by:inampudi1
  • 9
  • 9
19 Comments
 
LVL 21

Expert Comment

by:ziolko
ID: 22621965
why don't you use OnKeyUp and OnKeyDown event handlers?

ziolko.
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22621977
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
 
LVL 21

Expert Comment

by:ziolko
ID: 22621994
Geert OnShortcut is triggered before before key up/down

ziolko.
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622016
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
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622097
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
 
LVL 21

Expert Comment

by:ziolko
ID: 22622103
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
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622111
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
 
LVL 21

Expert Comment

by:ziolko
ID: 22622115
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
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622155
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:inampudi1
ID: 22622286
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
 
LVL 21

Expert Comment

by:ziolko
ID: 22622299
Result is evaluated based on IsShortCut() function which checks ActionLists so I would check for Msg.Msg values

ziolko.
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622305
nope, it just means it was evaluated as being a shortcut
0
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622323
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
 
LVL 21

Expert Comment

by:ziolko
ID: 22622370
>>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
 
LVL 21

Accepted Solution

by:
ziolko earned 500 total points
ID: 22622374
 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
 
LVL 21

Expert Comment

by:ziolko
ID: 22622437
try this:

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


ziolko.
0
 
LVL 21

Expert Comment

by:ziolko
ID: 22622455
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
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22622457
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
 
LVL 37

Expert Comment

by:Geert Gruwez
ID: 22623787
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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video discusses moving either the default database or any database to a new volume.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now