如何让透明Form获取鼠标进入事件?
How to make transparent Form get mouse enter events?
我想创建一个 Delphi 应用程序,当用户将鼠标移到屏幕的 top-left 一角时,它会执行一些有趣的操作。我想了想,打算用下面的策略来做:
创建一个非常小的 3x3 表单并使其透明并始终位于顶部。也让它没有标题栏或边框。
为窗体定义鼠标进入事件。
我在第 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的类型,表示事件
wParam
和 lParam
具有事件特定的含义
要传递消息,您应该调用 CallNextHookEx
- 但是对于某些挂钩,无论如何都会传递消息。
挂钩可以安装为 全局 挂钩 - 这意味着它们在与调用线程相同的桌面/WinStation 中拦截所有线程 运行 上的消息。因此,例如,如果您有多个用户通过 RD 连接,则挂钩仅特定于其中一个桌面。
我想创建一个 Delphi 应用程序,当用户将鼠标移到屏幕的 top-left 一角时,它会执行一些有趣的操作。我想了想,打算用下面的策略来做:
创建一个非常小的 3x3 表单并使其透明并始终位于顶部。也让它没有标题栏或边框。
为窗体定义鼠标进入事件。
我在第 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的类型,表示事件wParam
和lParam
具有事件特定的含义
要传递消息,您应该调用 CallNextHookEx
- 但是对于某些挂钩,无论如何都会传递消息。
挂钩可以安装为 全局 挂钩 - 这意味着它们在与调用线程相同的桌面/WinStation 中拦截所有线程 运行 上的消息。因此,例如,如果您有多个用户通过 RD 连接,则挂钩仅特定于其中一个桌面。