C# 无法使用MouseKeyHook检测全局鼠标按下

C# 无法使用MouseKeyHook检测全局鼠标按下,c#,.net,C#,.net,在过去的几个小时里,我一直在研究如何在全球范围内检测鼠标左键点击,但没有聚焦,并且无意中发现了多篇提到使用的帖子,这些帖子是我通过NuGet安装的,我已经实现了如下所示: 使用Gma.System.MouseKeyHook; 使用制度; 名称空间鼠标钩子测试 { 班级计划 { 静态专用IKeyboardMouseEvents m_GlobalHook; 静态环[]args { 订阅 Console.ReadKey; } 静态公共无效订阅 { m_GlobalHook=Hook.GlobalEve

在过去的几个小时里,我一直在研究如何在全球范围内检测鼠标左键点击,但没有聚焦,并且无意中发现了多篇提到使用的帖子,这些帖子是我通过NuGet安装的,我已经实现了如下所示:

使用Gma.System.MouseKeyHook; 使用制度; 名称空间鼠标钩子测试 { 班级计划 { 静态专用IKeyboardMouseEvents m_GlobalHook; 静态环[]args { 订阅 Console.ReadKey; } 静态公共无效订阅 { m_GlobalHook=Hook.GlobalEvents; m_GlobalHook.MouseDownExt+=GlobalHookMouseDownExt; } 静态私有void GlobalHookMouseDownExtobject发送方,MouseEventExtArgs e { Console.WriteLineMouse单击。; } } } 当我运行它时,我的屏幕鼠标突然开始滞后到无法使用的地步。我甚至挣扎着关闭命令提示符,我也尝试过左右单击,但没有记录任何内容。我是在做一些完全愚蠢的事吗?我觉得有一点很明显我遗漏了,因为没有其他人有这个问题,或者如果有其他解决方案,我很乐意尝试。多谢各位

Visual Studio 2019, Windows 10 Pro,
Project:.NET Framework 4.7.2,控制台应用程序,以调试模式运行

原因是全局钩子将消息发布到线程的Win32消息队列。这是用于以表单形式将消息传递给WndProc的相同队列

要接收消息,必须使用Application.Run泵送消息队列。但在控制台应用程序中,没有Application.Run

已经有人为此付出了,但是我认为下面的可能是最好的

使用Gma.System.MouseKeyHook; 使用制度; 使用System.Windows.Forms; 名称空间鼠标钩子测试 { 班级计划 { 静态专用IKeyboardMouseEvents m_GlobalHook; 静态环[]args { //在另一个后台线程上运行泵 //如果没有泵/同步上下文,运行感觉是个坏主意 var pumpThread=newthreadpumpqueue{IsBackground=true}; pumpThread.Start; Console.ReadKey; Application.Exit;//关闭泵 } [StatThread]//我认为这是确保线程安全所必需的 静态泵 { 订阅 应用程序。运行; } 静态公共无效订阅 { m_GlobalHook=Hook.GlobalEvents; m_GlobalHook.MouseDownExt+=GlobalHookMouseDownExt; } 静态私有void GlobalHookMouseDownExtobject发送方,MouseEventExtArgs e { Console.WriteLineMouse单击。; } } }
原因是消息由全局钩子发布到线程的Win32消息队列。这是用于以表单形式将消息传递给WndProc的相同队列

要接收消息,必须使用Application.Run泵送消息队列。但在控制台应用程序中,没有Application.Run

已经有人为此付出了,但是我认为下面的可能是最好的

使用Gma.System.MouseKeyHook; 使用制度; 使用System.Windows.Forms; 名称空间鼠标钩子测试 { 班级计划 { 静态专用IKeyboardMouseEvents m_GlobalHook; 静态环[]args { //在另一个后台线程上运行泵 //如果没有泵/同步上下文,运行感觉是个坏主意 var pumpThread=newthreadpumpqueue{IsBackground=true}; pumpThread.Start; Console.ReadKey; Application.Exit;//关闭泵 } [StatThread]//我认为这是确保线程安全所必需的 静态泵 { 订阅 应用程序。运行; } 静态公共无效订阅 { m_GlobalHook=Hook.GlobalEvents; m_GlobalHook.MouseDownExt+=GlobalHookMouseDownExt; } 静态私有void GlobalHookMouseDownExtobject发送方,MouseEventExtArgs e { Console.WriteLineMouse单击。; } } }
事实上,我和往常一样在玩游戏,寻找不同的方法来完成它,然后偶然发现了包含鼠标的方法,所以我导入了user32 DLL并启动了一个循环,每50毫秒检查鼠标左键状态0x01,发现这是最佳时间,并将其扔到线程中,这样它就不会阻塞主线程

使用制度; 使用System.Runtime.InteropServices; 使用系统线程; 名称空间鼠标钩子测试 { 班级计划 { 静态环[]args { 螺纹=新螺纹检测; 线程。开始; } //导入包含函数的DLL并获取它。 [DllImportuser32.dll] 公共静态外部短GetKeyStateint vKey; //跟踪鼠标左键状态的一个非常简单的实现。 静态空隙检测 { short-oldState=GetKeyState0x01; 虽然是真的 { short newState=GetKeyState0x01; 如果oldState!=newState { oldState=newState; 如果newState<0 { 点击鼠标; } } 线程50; } } 鼠标单击时的静态无效 { 控制台。WriteLineClicked!; } } } 可能有一个更好的解决方案,我找不到,所以我为什么要用这个。我最初是基于对我的确切问题的回答,但它是用Python编写的,所以我将其转换为C。我厌倦了看到我的问题的唯一答案是“使用某个第三方库”,无论出于何种原因,它对我都不正常工作,并且还将内存使用从30mb降低到7mb:


我也在Windows 7上测试过它,效果非常好。

我实际上像往常一样到处玩,寻找不同的方法来实现它,然后偶然发现了包括鼠标在内的,因此,我导入了user32 DLL并启动了一个循环,每50毫秒检查一次鼠标左键状态0x01,发现这是最佳时间,并将其放入线程中,这样它就不会阻塞主线程

使用制度; 使用System.Runtime.InteropServices; 使用系统线程; 名称空间鼠标钩子测试 { 班级计划 { 静态环[]args { 螺纹=新螺纹检测; 线程。开始; } //导入包含函数的DLL并获取它。 [DllImportuser32.dll] 公共静态外部短GetKeyStateint vKey; //跟踪鼠标左键状态的一个非常简单的实现。 静态空隙检测 { short-oldState=GetKeyState0x01; 虽然是真的 { short newState=GetKeyState0x01; 如果oldState!=newState { oldState=newState; 如果newState<0 { 点击鼠标; } } 线程50; } } 鼠标单击时的静态无效 { 控制台。WriteLineClicked!; } } } 可能有一个更好的解决方案,我找不到,所以我为什么要用这个。我最初是基于对我的确切问题的回答,但它是用Python编写的,所以我将其转换为C。我厌倦了看到我的问题的唯一答案是“使用某个第三方库”,无论出于何种原因,它对我都不正常工作,并且还将内存使用从30mb降低到7mb:


我也在Windows 7上测试了它,效果非常好。

同样的情况仍然存在,没有记录鼠标点击。强烈的鼠标延迟+没有记录。已移动订阅到另一个线程。我认为它现在应该可以工作了这次它开始记录点击,但是滞后持续存在,但是现在它是波浪形的,当滞后消失2秒时,点击被记录,但是当它回来时,它们不再被记录。更具体地说,最初几秒它工作正常,然后滞后出现,让我的朋友也测试了一下,结果也一样。看起来ReadKey可能有一个bug。尝试使用ReadLine代替。同样的情况仍然发生,并且没有记录鼠标单击。强烈的鼠标延迟+没有记录。已移动订阅到其他线程。我认为它现在应该可以工作了这次它开始记录点击,但是滞后持续存在,但是现在它是波浪形的,当滞后消失2秒时,点击被记录,但是当它回来时,它们不再被记录。更具体地说,最初几秒它工作正常,然后滞后出现,让我的朋友也测试了一下,结果也一样。看起来ReadKey可能有一个bug。请改用ReadLine