2

背景: 私のフォームには TWebBrowser があります。フォームを ESC で閉じたいのですが、TWebBrowser がキーストロークを食べてしまうので、キーボード フックを使用することにしました。

問題は、フォームを同時に複数のインスタンスで開くことができることです。

何をしても、状況によっては、フォームの 2 つのインスタンスが開いている場合、そのうちの 1 つを閉じると、もう 1 つも閉じます。

サンプルコードをいくつか添付しました。問題の原因についてのアイデアはありますか?

var
  EmailDetailsForm: TEmailDetailsForm;
  KeyboardHook: HHook;

implementation

function KeyboardHookProc(Code: Integer; wParam, lParam: LongInt): LongInt; stdcall;
var
  hWnd: THandle;
  I: Integer;
  F: TForm;
begin
  if Code < 0 then
    Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam)
  else begin
    case wParam of
      VK_ESCAPE:  
        if (lParam and $80000000) <> $00000000 then
        begin
          hWnd := GetForegroundWindow;
          for I := 0 to Screen.FormCount - 1 do
          begin
            F := Screen.Forms[I];
            if F.Handle = hWnd then
              if F is TEmailDetailsForm then
              begin
                PostMessage(hWnd, WM_CLOSE, 0, 0);
                Result := HC_SKIP;
                break;
              end;
          end; //for
        end; //if
      else
        Result := CallNextHookEx(KeyboardHook, Code, wParam, lParam);
    end;  //case
  end;  //if
end;

function TEmailDetailsForm.CheckInstance: Boolean;
var
  I, J: Integer;
  F: TForm;
begin
  Result := false;

  J := 0;

  for I := 0 to Screen.FormCount - 1 do
  begin
    F := Screen.Forms[I];
    if F is TEmailDetailsForm then
    begin
      J := J + 1;
      if J = 2 then
      begin
        Result := true;
        break;
      end;
    end;
  end;
end;

procedure TEmailDetailsForm.FormCreate(Sender: TObject);
begin
    if not CheckInstance then    
      KeyboardHook := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHookProc, 0, GetCurrentThreadId());
end;

procedure TEmailDetailsForm.FormDestroy(Sender: TObject);
begin
    if not CheckInstance then
      UnHookWindowsHookEx(KeyboardHook);
end;
4

3 に答える 3

1

代わりにこれを行うことができますTApplicationEvents.OnMessage。次のコードを使用して、アプリケーションのメイン フォームに TApplicationEvents コンポーネントをドロップします。

procedure TMainForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  C: TControl;
  H: HWND;
begin
  if (Msg.message = WM_KEYDOWN) and (Msg.wParam = VK_ESCAPE) then begin
    H := Msg.hwnd;
    while GetParent(H) <> 0 do
      H := GetParent(H);
    C := FindControl(H);
    if C is TEmailDetailsForm then begin
      TEmailDetailsForm(C).Close;
      Handled := True;
    end;
  end;
end;

代わりにキーボード フックを使用し続けたい場合は、特にグローバル変数を上書きしているため、フォームごとに 1 回ではなく、1 回だけフックする必要があります。HookCount グローバル変数を追加してみてください。それが唯一のフォームである場合にのみ、フック/フック解除します。

于 2010-04-05T15:45:48.067 に答える
0

背景: 私のフォームには TWebBrowser があります。フォームを ESC で閉じたいのですが、TWebBrowser がキーストロークを食べてしまうので、キーボード フックを使用することにしました。

もっと簡単な解決策があるかもしれません。フォームのKeyPreviewプロパティを に設定してみましたTrueか?

于 2010-04-04T23:35:30.483 に答える
0

どちらのフォームもキーボード通知を受け取るようにサインアップしているので、両方とも閉じます。「これは私のための ESC ですか?」と判断するコードをそこに入れる必要があります。おそらく、あなたがフォーカスのあるウィンドウであるかどうかを判断することによって。それがあなたの ESCape でない場合は、閉じないでください。

しかし、これはすべてかなり抜本的なようです。システム全体のキーボードを監視することなく、このアプリ内で ESC を検出するための、より簡単で邪魔にならない方法が必要です。

于 2010-04-05T01:16:36.407 に答える