c# 在任何地方检测鼠标点击(表单内部和外部)

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

是否可以检测 if 语句中任何地方(表单内部和外部)的鼠标单击 (Left/Right)?如果可能的话,怎么做?

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

...

}

当用户在表单控件外部单击时,它会失去焦点,您可以使用 that.which 意味着您必须使用表单控件的 _Deactivate(object sender, EventArgs e) 事件才能完成此工作。因为这将在表单失去焦点并且不再是活动表单时触发 。设Form1为表格,则事件如下:

private void Form1_Deactivate(object sender, EventArgs e)
{
    // Your code here to handle this event
}

如果我了解您对“从 window 外部单击”的需求并且 Hans Passant 的建议不符合您的需求,那么这是一个入门。您可能需要为 Form1_Click.

添加事件处理程序

注意:提供此代码是为了说明该概念。此示例中的线程同步并非 100% 正确。检查这个答案的历史,尝试一种有时会抛出异常的更“正确的线程”。作为替代方案,要消除所有线程问题,您可以让 StartWaitingForClickFromOutside 中的任务始终 运行 (也就是始终处于“侦听”模式),而不是尝试检测“表单内”或“在表单之外”状态和 starting/stopping 相应的循环。

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();
        }
    }
}

如果我对你的理解有误,你可能会发现这个有用:

一种方法是用无边框的形式覆盖整个屏幕,属性设置为透明(比完全透明高出百分之几,不确定完全透明是否有效,但你不会注意到差异)并且设置为最顶层的。然后使用表单中的事件。一旦检测到点击,这将不会影响表单下方的任何内容(在我的应用程序中这是我想要发生的事情)但是表单可以关闭并且在几分之一秒后模拟另一个鼠标点击以激活控件下。我使用 windows API 在 VB6 中使用鼠标挂钩没有问题,但似乎无法找到适用于 2019 版 .NET 的 c# 的东西,所以这是一个很好的解决方法。当然,要真正聪明,您可以使用不规则形式的方法使透明形式与鼠标形状相同并跟随它。 注意:我刚刚找到了完整的代码来使用钩子来完成它,凡人可以立即起床 运行! KeyboardMouseHooks C# 库 - CodePlex 存档 PS 如果您使用我的(愚蠢的)方法,请记住创建退出键或按钮,否则您将不得不重新启动计算机,除非按照建议将表单编程为在真正的点击后消失!

我知道这已经晚了,但也许它对某人有帮助。使用任何控件的 MouseUp 事件的 MouseEventArgs,您可以检查鼠标按钮和滚轮等。这是一个例子。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        this.MouseUp += Form1_MouseUp;
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        if(e.Button == MouseButtons.Left)
        {
            DoSomething_LeftClick();
        }
        else if(e.Button == MouseButtons.Right)
        {
            DoSomething_RightClick();
        }
    }

    private void DoSomething_LeftClick()
    {
        //Here some code
    }
    private void DoSomething_RightClick()
    {
        //Here some code
    }
}