Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can my TComponent intercept the ESC key and handle it?

In my TComponent, there is a point where I want to listen to key events and intercept the ESC key and handle it in my component, consume/"eat" the keystroke, so that for example the owner form won't handle it at that stage. Just like in TDragObject when you start do drag and cancel it by pressing ESC.

Problem is that TDragObject has AllocateHWnd that is notified by it's owner form with CN_KEYDOWN. But no one notifies my component.

Do I need to replace the form's WindowProc with my own? If yes, then how to do it correctly "by the book" so to speak?


Just to be 100% clear:

TMyComponent = class(TComponent)

I made a small test and it seems to work:

TMyComponent = class(TComponent)
  private
    FOldWindowProc: TWndMethod;
    FParentForm: TCustomForm;
    procedure FormWindowProc(var Message: TMessage);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;    
end;

...

constructor TMyComponent.Create(AOwner: TComponent);
begin
  if not (AOwner is TWinControl) then
    raise Exception.Create('TMyComponent.Create: Owner must be a TWinControl');
  inherited Create(AOwner);
  // hook parent form
  FParentForm := GetParentForm(TWinControl(Owner));
  if Assigned(FParentForm) then
  begin
    FOldWindowProc := FParentForm.WindowProc;
    FParentForm.WindowProc := FormWindowProc;
  end;
end;

destructor TMyComponent.Destroy;
begin
  // unhook parent form
  if Assigned(FParentForm) then
    FParentForm.WindowProc := FOldWindowProc;
  inherited;
end;

procedure TMyComponent.FormWindowProc(var Message: TMessage);
begin
  FOldWindowProc(Message);
  if Message.Msg = CM_CHILDKEY then // CM_CHILDKEY -> CM_DIALOGKEY -> CM_DIALOGCHAR
  begin
    OutputDebugString('CM_CHILDKEY');
    if Message.WParam = VK_ESCAPE then
    begin
      Beep;
      // do my stuff...
      Message.Result := 1; // consume keystroke
    end;
  end;
end; 

I'm wondering if this is the right/only approach.

like image 230
Vlad Avatar asked Jan 15 '13 21:01

Vlad


1 Answers

One way might be to create a TApplicationEvents object inside of your component, and then use its OnMessage event to peek at messages from the main thread message queue, such as keystrokes, before the rest of the VCL processes them.

like image 153
Remy Lebeau Avatar answered Nov 18 '22 04:11

Remy Lebeau