Search code examples
c#formswinformsclickmouse

c# Detect mouse clicks anywhere (Inside and Outside the Form)


Is this possible to detect a mouse click (Left/Right) anywhere (Inside and Outside the Form) in an if statement? And if it's possible, how?

if(MouseButtons.LeftButton == MouseButtonState.Pressed){

...

}

Solution

  • Here is a starter, if I understood your needs of "clicking from outside the window" and Hans Passant's suggestion doesn't fit your needs. You might need to add an event handler for Form1_Click.

    CAUTION: This code is provided to illustrate the concept. The threading synchronization in this sample is not 100% correct. Check the history of this answer for an attempt at a more "threading correct" one that sometimes throws exceptions. As an alternative, to get rid of all threading issues, you could have the task in StartWaitingForClickFromOutside be instead always running (aka be always in "listen" mode) as opposed to trying to detect the "within the form" or "outside the form" states and starting/stopping the loop accordingly.

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                this.MouseLeave += Form1_MouseLeave;
                this.Leave += Form1_Leave;
                this.Deactivate += Form1_Deactivate;
                this.MouseEnter += Form1_MouseEnter;
                this.Activated += Form1_Activated;
                this.Enter += Form1_Enter;
                this.VisibleChanged += Form1_VisibleChanged;
            }
    
            private AutoResetEvent are = new AutoResetEvent(false);
    
            // You could create just one handler, but this is to show what you need to link to
            private void Form1_MouseLeave(object sender, EventArgs e) => StartWaitingForClickFromOutside();
            private void Form1_Leave(object sender, EventArgs e) => StartWaitingForClickFromOutside();
            private void Form1_Deactivate(object sender, EventArgs e) => StartWaitingForClickFromOutside();
            private void StartWaitingForClickFromOutside()
            {
                are.Reset();
                var ctx = new SynchronizationContext();
    
                var task = Task.Run(() =>
                {
                    while (true)
                    {
                        if (are.WaitOne(1)) break;
                        if (MouseButtons == MouseButtons.Left)
                        {
                            ctx.Send(CLickFromOutside, null);
                            // You might need to put in a delay here and not break depending on what you want to accomplish
                            break;
                        }
                    }
                });
            }
    
            private void CLickFromOutside(object state) => MessageBox.Show("Clicked from outside of the window");
            private void Form1_MouseEnter(object sender, EventArgs e) => are.Set();
            private void Form1_Activated(object sender, EventArgs e) => are.Set();
            private void Form1_Enter(object sender, EventArgs e) => are.Set();
            private void Form1_VisibleChanged(object sender, EventArgs e)
            {
                if (Visible) are.Set();
                else StartWaitingForClickFromOutside();
            }
        }
    }
    

    If I understood you incorrectly, you might find this useful: Pass click event of child control to the parent control