如何判断鼠标是否位于顶级窗口之外?

如何有效地判断鼠标是否位于顶级窗口之外?

通过“over”,我的意思是鼠标指针位于顶级窗口的客户端矩形内, 并且在鼠标指针位置的窗口上没有其他顶级窗口。 换句话说,如果用户点击该事件将被发送到我的顶级窗口(或其子窗口之一)。

我使用Windows Forms在C#中编写,但我不介意使用p / invoke来进行Win32调用。

您可以使用WinAPI函数WindowFromPoint 。 它的C#签名是:

 [DllImport("user32.dll")] static extern IntPtr WindowFromPoint(POINT Point); 

请注意,此处的POINTSystem.Drawing.Point ,但PInvoke 为POINT提供了一个声明,其中包含两者之间的隐式转换 。

如果您还不知道鼠标光标位置, GetCursorPos找到它:

 [DllImport("user32.dll")] static extern bool GetCursorPos(out POINT lpPoint); 

但是,WinAPI调用很多东西“windows”:窗口​​内的控件也是“windows”。 因此,您可能无法直观地获得顶级窗口 (您可能会获得一个单选按钮,面板或其他内容)。 您可以迭代地应用GetParent函数来遍历GUI层次结构:

 [DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)] public static extern IntPtr GetParent(IntPtr hWnd); 

找到没有父级的窗口后,该窗口将成为顶级窗口。 由于您最初传入的点属于另一个窗口未覆盖的控件,因此顶级窗口必然是该点所属的窗口。

获取窗口句柄后,可以使用Control.FromHandle()来获取对控件的引用。 然后检查相对鼠标位置以查看它是否是窗体或控件的客户区域。 像这样:

  private void timer1_Tick(object sender, EventArgs e) { var hdl = WindowFromPoint(Control.MousePosition); var ctl = Control.FromHandle(hdl); if (ctl != null) { var rel = ctl.PointToClient(Control.MousePosition); if (ctl.ClientRectangle.Contains(rel)) { Console.WriteLine("Found {0}", ctl.Name); return; } } Console.WriteLine("No match"); } [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern IntPtr WindowFromPoint(Point loc);