How can I efficiently tell if the mouse is over a top-level window?
By "over", I mean that the mouse pointer is within the client rectangle of the top-level window and there is no other top-level window over my window at the location of the mouse pointer. In other words, if the user clicked the event would be sent to my top-level window (or one of its child windows).
I am writing in C# using Windows Forms, but I don't mind using p/invoke to make Win32 calls.
You could use the WinAPI function WindowFromPoint
. Its C# signature is:
[DllImport("user32.dll")]
static extern IntPtr WindowFromPoint(POINT Point);
Note that POINT
here is not the same as System.Drawing.Point
, but PInvoke provides a declaration for POINT
that includes an implicit conversion between the two.
If you don’t already know the mouse cursor position, GetCursorPos
finds it:
[DllImport("user32.dll")]
static extern bool GetCursorPos(out POINT lpPoint);
However, the WinAPI calls lots of things “windows”: controls inside a window are also “windows”. Therefore, you might not get a top-level window in the intuitive sense (you might get a radio button, panel, or something else). You could iteratively apply the GetParent
function to walk up the GUI hierarchy:
[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);
Once you find a window with no parent, that window will be a top-level window. Since the point you originally passed in belongs to a control that is not covered by another window, the top-level window is necessarily the one the point belongs to.
After you obtain the window handle you can use Control.FromHandle() to get a reference to the control. Then check the relative mouse position to see if its it is the client area of the form or control. Like this:
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With