Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect if the mouse is inside the whole form and child controls?

I need to detect when the user moves the mouse over the Form and all its child controls and also when it leaves the Form. I tried the MouseEnter and MouseLeave events of the Form, I tried the WM_MOUSEMOVE & WM_MOUSELEAVE and WM_NCMOUSEMOVE & WM_NCMOUSELEAVE pairs of windows messages but none seem to work as I want...

Most of my Form is occupied by child controls of many sorts, there's not much client area visible. This means that if I move the mouse very quickly the mouse movement will not be detected, although the mouse is inside the Form.

For instance, I have a TextBox that is docked at the bottom and between the desktop and the TextBox, there's only a very small border. If I quickly move the mouse from the bottom into the TextBox, the mouse movement won't be detected, but the mouse is inside the TextBox, therefore, inside the Form.

How can I achieve what I need?

like image 439
rfgamaral Avatar asked Jun 12 '09 13:06

rfgamaral


2 Answers

You can hook the main message loop and preprocess/postprocess any (WM_MOUSEMOVE) message what you want.

public class Form1 : Form {
    private MouseMoveMessageFilter mouseMessageFilter;
    protected override void OnLoad(EventArgs e) {
        base.OnLoad( e );

        this.mouseMessageFilter = new MouseMoveMessageFilter();
        this.mouseMessageFilter.TargetForm = this;
        Application.AddMessageFilter(this.mouseMessageFilter);
    }

    protected override void OnClosed(EventArgs e) {
        base.OnClosed(e);
        Application.RemoveMessageFilter(this.mouseMessageFilter);
    }

    private class MouseMoveMessageFilter : IMessageFilter {
        public Form TargetForm { get; set; }

        public bool PreFilterMessage( ref Message m ) {
            int numMsg = m.Msg;
            if ( numMsg == 0x0200 /*WM_MOUSEMOVE*/)
                this.TargetForm.Text = string.Format($"X:{Control.MousePosition.X}, Y:{Control.MousePosition.Y}");

            return false;
        }
    }
}
like image 108
TcKs Avatar answered Oct 06 '22 00:10

TcKs


How about this: In your form's OnLoad, recursively go through all of the child controls (and their children) and hook up the MouseEnter event.

Then whenever the mouse enters any descendant, the event handler will be called. Similarly, you could hook up MouseMove and/or MouseLeave events.

protected override void OnLoad()
{
   HookupMouseEnterEvents(this);
}

private void HookupMouseEnterEvents(Control control)
{
   foreach (Control childControl in control.Controls)
   {
      childControl.MouseEnter += new MouseEventHandler(mouseEnter);

      // Recurse on this child to get all of its descendents.
      HookupMouseEnterEvents(childControl);
   }
}
like image 26
NascarEd Avatar answered Oct 05 '22 23:10

NascarEd