私のTComponent
では、キーイベントをリッスンし、キーをインターセプトESC
してコンポーネントで処理し、キーストロークを消費/「食べる」ことで、たとえば所有者フォームがその段階でそれを処理しないようにするポイントがあります。TDragObject
ドラッグを開始したときと同じように、 を押してキャンセルしESC
ます。
問題は、それTDragObject
がAllocateHWnd
所有者フォームによって通知されることCN_KEYDOWN
です。しかし、誰も私のコンポーネントに通知しません。
WindowProc
フォームを自分のフォームに置き換える必要がありますか? はいの場合、いわば「本で」正しく行う方法は?
100%明確にするために:
TMyComponent = class(TComponent)
私は小さなテストを行いましたが、うまくいくようです:
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;
これが正しい/唯一のアプローチであるかどうか疑問に思っています。