2

背景:我的表单有一个 TWebBrowser。我想用 ESC 关闭表单,但 TWebBrowser 吃掉了击键 - 所以我决定使用键盘挂钩。

问题是表单可以同时在多个实例中打开。

无论我做什么,在某些情况下,如果我的表单打开了两个实例,关闭其中一个实例也会关闭另一个实例。

我附上了一些示例代码。关于导致问题的原因有什么想法吗?

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;

如果您想继续使用键盘挂钩,您应该只挂钩一次,而不是每个表单一次,特别是因为您正在覆盖全局变量。尝试添加一个 HookCount 全局变量,如果它是唯一的形式,则仅挂钩/取消挂钩。

于 2010-04-05T15:45:48.067 回答
0

背景:我的表单有一个 TWebBrowser。我想用 ESC 关闭表单,但 TWebBrowser 吃掉了击键 - 所以我决定使用键盘挂钩。

可能有一个更简单的解决方案。您是否尝试过将表单的KeyPreview属性设置为True

于 2010-04-04T23:35:30.483 回答
0

好吧,这两种形式都已注册以接收键盘通知,因此它们都关闭了。您需要在其中输入代码来决定“这个 ESC 适合我吗?”。也许通过确定您是否是焦点窗口。如果不是您的 ESCape,请不要关闭。

但是,这一切似乎相当激烈。必须有一种更简单、不显眼的方法来检测此 APP 中的 ESC,而无需监控整个系统的键盘。

于 2010-04-05T01:16:36.407 回答