Windows Hooks 不会触发事件并且 Windows 开始滞后。 (在 C# 中使用 globalmousekeyhook)
Posted
技术标签:
【中文标题】Windows Hooks 不会触发事件并且 Windows 开始滞后。 (在 C# 中使用 globalmousekeyhook)【英文标题】:Windows Hooks do not trigger events and windows starts lagging. (Using globalmousekeyhook in C#) 【发布时间】:2021-06-03 18:35:25 【问题描述】:我目前与Steelseries GameSense SDK 合作,为我的键盘和鼠标制作自己的效果等。
为了在点击和按下时点亮我的鼠标和键盘,我使用了globalmousekeyhook 库。
很遗憾,鼠标和键盘事件没有被触发。
另外,我的鼠标开始滞后,键盘输入延迟。
滞后和延迟只停留半分钟左右。
我怀疑 windows 删除了钩子,因为它检测到了滞后。
我也尝试了this example program,那里一切正常。
代码如下:
private static readonly IKeyboardMouseEvents GlobalHook = Hook.GlobalEvents();
static InputManager()
Logger.Log("Starting...", Logger.Type.Info);
GlobalHook.KeyDown += KeyEvent;
GlobalHook.MouseDownExt += MouseEvent;
Logger.Log("Ready!", Logger.Type.Info);
以及事件函数:
private static void KeyEvent(object sender, KeyEventArgs eventArgs)
Logger.Log(eventArgs.KeyCode.ToString());
private static void MouseEvent(object sender, MouseEventArgs eventArgs)
Logger.Log(eventArgs.Button.ToString());
你可以找到整个班级(和项目)here。
构造函数是程序中唯一被执行的东西。
关于延迟,我发现事件函数必须很快。在我的情况下这不是问题,因为Logger.Log()
函数很快,并且在使用Console.WriteLine()
时也会出现滞后。
正如我所说,示例程序运行良好。我尝试复制示例代码,但这没有任何区别。我的程序和示例程序之间唯一真正的区别是示例使用.Net Core,但我使用.Net Framework (4.8)。这可能是原因吗?如果是这个原因,有没有办法将这个库与 .Net Framework 一起使用? 我期待任何帮助。
【问题讨论】:
如果您尝试响应所有事件是正常的。您可以尝试登录一个新线程,但它也会使用不必要的系统资源。 private static void KeyEvent(object sender, KeyEventArgs eventArgs) Task.Run(() => Logger.Log(eventArgs.KeyCode.ToString()); ); @OlivierRogier 当我注释掉 Logger.Log() 并因此清空事件函数时,它甚至会滞后。同样不幸的是,链接的包装器不适合我的情况,因为我需要挂钩所有事件。 @aliassce 我尝试了您的建议,但仍然滞后。我链接的example 也记录了所有事件,但由于某种原因它并没有滞后。Console.ReadLine
in Program.Main()
正在阻止一切,无论如何您都没有运行消息循环,所以我不确定您期望发生什么。请注意,您提供的示例代码非常不同,它使用Application.Run(new ApplicationContext());
设置了一个消息循环我必须说我不明白为什么InputManager.Start
是空的并且所有连接代码都在静态构造函数。这听起来不太安全。
@Charlieface 我现在没有消息循环,因为我首先需要让鼠标和键盘挂钩工作。我希望控制台输出带有我单击的键或鼠标按钮(您可以在 KeyEvent
和 MouseEvent
函数中看到)。在调用任何其他方法之前调用静态构造函数。因此,当您调用 InputManager.Start()
时,它会运行构造函数。这样做的好处是,即使您调用类的任何方法,也会调用“start”函数。你能解释一下为什么Console.ReadLine()
会阻塞吗?是否有其他方法可以保持程序运行?
【参考方案1】:
有两个问题:
您需要一个消息泵才能接收挂钩消息。为此,您可以使用以下代码,如您链接的示例所示Application.Run(new ApplicationContext());
您现在尝试在同一个线程上做两件事:泵送消息并等待输入。相反,将它们分成不同的线程:
private static void Main(string[] args)
Logger.Log("Program started. Welcome.", Logger.Type.Info);
////GameSense.Controller.Start();
new Thread(() => Console.ReadLine()).Start();
InputManager.Start();
Application.Run(new ApplicationContext());
InputManager.End();
Application.Exit(); // needed to close down the message pump and end the other thread
【讨论】:
非常感谢!我对标准泵不太熟悉。今天学习了一些新东西! 刚刚检查:我必须在InputManager.Start()
之后的同一线程中调用 Application.Run(new ApplicationContext())
。它只能以这种方式工作。 (例子也是这样)
如果你愿意,你可以这样做,然后将Console.ReadLine
放在另一个线程中。我不认为这有什么不同
实际上只有将两者放在同一个线程上才有效。 Application.Run(new ApplicationContext())
启动新的标准管道(当我理解正确的时候?)并且 Console.ReadLine() 不会阻塞“旧”管道?它目前在 GitHub 上的工作方式。当我尝试您的代码时,它仍然滞后。
Application.Run
与管道没有任何关系,它会阻止您使用ReadLine
以上是关于Windows Hooks 不会触发事件并且 Windows 开始滞后。 (在 C# 中使用 globalmousekeyhook)的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Stripe 事件不会触发并且不会被 webhook 接收?
UserControl KeyDown 事件不会触发撤销 Windows 应用程序 KeyDown 事件
Redux-Toolkit 和 React Hooks - 存储更改不会触发重新渲染
react hooks之useDebounce useThrottle