Solved

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

Posted on 2008-10-02
19
3,087 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Independent Software Vendors: 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!

 
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
 

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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…

751 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