如何让透明Form获取鼠标进入事件?

How to make transparent Form get mouse enter events?

我想创建一个 Delphi 应用程序,当用户将鼠标移到屏幕的 top-left 一角时,它会执行一些有趣的操作。我想了想,打算用下面的策略来做:

  1. 创建一个非常小的 3x3 表单并使其透明并始终位于顶部。也让它没有标题栏或边框。

  2. 为窗体定义鼠标进入事件。

我在第 1 步中使用以下代码:

procedure TopLeftForm.FormCreate(Sender: TObject);
begin
  FormStyle := fsStayOnTop;

  self.TransparentColor := true;
  self.TransparentColorValue := self.Color;
  self.BorderStyle := bsNone;
end;

问题是我发现当Form透明时,无法捕获鼠标进入事件。我可以使表单不透明以获得鼠标输入事件,但这样用户可以在 top-left 屏幕角落看到表单,这不是我想要的。

你对我的问题有什么建议?

您想要的是一个 'Hook',它可以为您提供有关鼠标事件的信息,而不是为您的程序准备的事件。题目太大,没法一次性给你一个how-to,不过这两个link应该会有帮助:

Understanding how to use Windows Hooks

Mouse Hook Tutorial with Delphi codes

为什么要使用 Windows 钩子?

Windows 环境是围绕传递的消息设计的。通常,一个程序只对直接发送到它自己的 windows 的消息感兴趣。尝试确保您的应用程序有一个 window 来获取消息,当其他应用程序位于您的同一位置时,它们会阻止其他应用程序接收这些消息,如果另一个 window 在您的上方,那么您就赢了'得到消息。如果您想了解 activity 正在发生的事情,通常不会发送给您 - 例如,在您的应用程序 window 之外单击鼠标。要使应用程序能够看到不是为自己指定的事件,可以使用 windows 挂钩。

有不同类型的挂钩,具体取决于您要访问的内容。鼠标挂钩适用于您在此处指定的内容。系统为所有已安装的挂钩维护一个 'Hook Chain' - 您有责任将消息传递到链下,并将您自己从链中卸载。

要访问消息,您的挂钩函数将如下所示(代码取自上面的第二个 link 并进行了改编):

function MouseHookHandler(ACode: Integer; WParam: WParam; LParam: LParam): LResult; stdcall;
var
  vMouseInfo: PMouseHookStruct;
begin
  if ACode < 0 then
    Result := CallNextHookEx(Data^.MouseHook, ACode, WParam, LParam)
  else
  begin
    vMouseInfo := PMouseHookStruct(Pointer(LParam));
    PostMessage(Data^.AppHandle, WM_CUSTOM_MOUSE, vMouseInfo^.pt.X, vMouseInfo^.pt.Y);
    // we dont want to block the mouse messages
    Result := CallNextHookEx(nil, ACode, WParam, LParam);
  end;
end;

在你的钩子函数中:

  • ACode依赖hook的类型,表示事件

  • wParamlParam 具有事件特定的含义

要传递消息,您应该调用 CallNextHookEx - 但是对于某些挂钩,无论如何都会传递消息。

挂钩可以安装为 全局 挂钩 - 这意味着它们在与调用线程相同的桌面/WinStation 中拦截所有线程 运行 上的消息。因此,例如,如果您有多个用户通过 RD 连接,则挂钩仅特定于其中一个桌面。