简体   繁体   English

c# 检测任意位置的鼠标点击(表单内部和外部)

[英]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?这是否可以在 if 语句中的任何位置(表单内部和外部)检测鼠标单击(左/右)? And if it's possible, how?如果可能的话,怎么做?

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

...

}

When user clicks outside the form control, it losses the focus and you can make use of that.which means you have to use the _Deactivate(object sender, EventArgs e) event of the form control to make this work.当用户在表单控件之外单击时,它会失去焦点,您可以使用它。这意味着您必须使用表单控件的_Deactivate(object sender, EventArgs e)事件才能使其工作。 Since which will trigger when the form loses focus and is no longer the active form .因为 which 将在表单失去焦点并且不再是活动表单时触发。 Let Form1 be the form, then the event will be like the following:Form1为表单,那么事件将如下所示:

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

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.如果我了解您对“从窗口外单击”的需求并且 Hans Passant 的建议不符合您的需求,那么这是一个首发。 You might need to add an event handler for Form1_Click .您可能需要为Form1_Click添加事件处理程序。

CAUTION: This code is provided to illustrate the concept.注意:提供此代码是为了说明这个概念。 The threading synchronization in this sample is not 100% correct.此示例中的线程同步不是 100% 正确的。 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.作为替代方案,要摆脱所有线程问题,您可以让 StartWaitingForClickFromOutside 中的任务始终运行(也就是始终处于“侦听”模式),而不是尝试检测“表单内”或“表单外” " 状态并相应地启动/停止循环。

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如果我对您的理解不正确,您可能会发现这很有用: 将子控件的单击事件传递给父控件

One method is to cover the entire screen with a borderless form with the properties set to transparent (a few percent above completely transparent, not sure if total transparency works but you won't notice the difference) and also set to topmost.一种方法是用无边框的窗体覆盖整个屏幕,并将属性设置为透明(比完全透明高几个百分点,不确定全透明是否有效,但您不会注意到差异),并将其设置为最顶层。 Then use the events from the form.然后使用表单中的事件。 As soon as a click is detected this will not affect anything underneath the form (which in my application is something I want to happen) but the form could be closed and another mouse click simulated a fraction of a second later to activate the controls that are underneath.一旦检测到点击,这不会影响表单下方的任何内容(在我的应用程序中这是我想要发生的事情),但是可以关闭表单,并且在几分之一秒后模拟另一个鼠标点击以激活控件下。 I had no problem using the windows API to use mouse hooks in VB6 but cannot seem to find something that works in c# with the 2019 version of .NET so this is a good workaround.我在 VB6 中使用 Windows API 使用鼠标钩子没有问题,但似乎找不到适用于 2019 版 .NET 的 c# 的东西,所以这是一个很好的解决方法。 Of course to be really clever you could use an irregular forms method to make the transparent form the same shape as the mouse and follow it.当然,要真正聪明,您可以使用不规则形状的方法使透明形状与鼠标形状相同并跟随它。 Note: I have just found the complete code to do it using hooks that mere mortals can get up and running at once!注意:我刚刚找到了完整的代码来使用普通人可以立即启动并运行的钩子! KeyboardMouseHooks C# Library - CodePlex Archive PS if you use my (dumb) method remember to create an escape key or button or you will have to restart your computer unless the form is programmed to disappear for real clicks as suggested! KeyboardMouseHooks C# 库 - CodePlex Archive PS 如果您使用我的(愚蠢的)方法,请记住创建一个转义键或按钮,否则您将不得不重新启动计算机,除非该表单被编程为按照建议消失以进行真正的点击!

I know this is late but maybe it helps someone.我知道这已经晚了,但也许它可以帮助某人。 Using the MouseEventArgs of the MouseUp event of any control you can check for mouse button and wheel among other things.使用任何控件的MouseUp事件的MouseEventArgs ,您可以检查鼠标按钮和滚轮等。 Here is an example.这是一个例子。

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
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM