65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 全局鼠标和键盘钩子处理

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (599投票s)

2004年6月4日

CPOL

6分钟阅读

viewsIcon

17697318

downloadIcon

219580

该类允许您捕获键盘和鼠标,以及/或者检测它们的活动,即使应用程序在后台运行或根本没有用户界面。

新闻

这篇文章发表于 2004 年,并于 2006 年和 2008 年更新。在此期间,我一直收到大量积极的反馈和推荐。此外,还有许多有用的贡献,通常以论坛代码片段的形式发布。现在,我决定不独自发布另一个版本,而是邀请大家积极参与。所以请充满热情,随时加入项目:globalmousekeyhook.codeplex.com

您可以帮助:
  • 贡献代码。
  • 创建问题项,请求附加功能或报告缺陷。
  • 为您感兴趣的功能和修复投票。
  • 在不同环境中测试组件。
  • 编写开发者文档。

这将使我们能够保持本原创文章的更新。

感谢大家在 CodeProject 论坛上提供的所有精彩评论,并期待您在 globalmousekeyhook.codeplex.com 的精彩贡献!

引言

该类允许您捕获键盘和鼠标,以及/或者检测它们的活动,即使应用程序在后台运行或根本没有用户界面。该类使用 KeyEventArgsMouseEventArgs 引发通用的 .NET 事件,因此您可以轻松获取所需的任何信息。

背景

有许多应用程序在后台运行并检测用户的不活动状态以更改其模式。例如,MSN Messenger(或其他任何即时通讯工具)。我本来打算编写一个这样的应用程序,所以我搜索了 MSDN 并找到了“正好”需要的东西:“318804 - HOW TO: Set a Windows Hook in Visual C# .NET”。这篇文章描述了如何捕获鼠标移动,但它只在应用程序处于活动状态时才有效。在这篇文章的结尾,我发现了这个解释:“.NET Framework 不支持全局钩子。您不能在 Microsoft .NET Framework 中实现全局钩子…”。无论如何,我继续研究,并发现了一些例外。存在 WH_KEYBOARD_LLWH_MOUSE_LL 钩子,它们可以全局安装。因此,我basically 用 WH_MOUSE_LL 替换了 MSDN 示例中的 WH_MOUSE,它就能工作了。

第二步是将接收到的信息提取到 .NET EventArgs 中并引发相应的事件。

我在 CodeProject 上找到了一个类似的帖子,是 Michael Kennedy 的“Global System Hooks in .NET”,但我 dislike 的是,其中有一个 C++ 的非托管 DLL 是该解决方案的主要部分。这个非托管 DLL 是用 C++ 编写的,而且有许多类,使得将其集成到我自己的小型应用程序中变得复杂。

修订

这篇文章发表于 2004 年,并于 2006 年更新。在此期间,我一直收到大量积极的反馈和推荐。此外,技术也取得了一些进步,例如 .NET Framework 3.5 或 Visual Studio 2008。所以我决定再次更新它。

我对解决方案进行了重构和改进,使其更加灵活、稳定和高效。但这种重构也带来了一些缺点:

  1. 代码行数和文件数量增加。
  2. 与旧版 .NET 的向后兼容性丢失。

因此,我打算仍然提供旧版本供下载。

使用代码 [版本 2]

简单方法

如果您正在开发 Windows Forms 应用程序并倾向于拖放式编程,程序集 Gma.UserActivityMonitor.dll 中有一个名为 GlobalEventProvider组件。只需将其拖放到您的窗体上,然后通过属性编辑器事件选项卡创建事件。

替代方法

使用 static HookManager 提供的事件。请注意,事件中的 sender 对象始终为 null

有关更多使用提示,请参阅所附演示应用程序的源代码。

使用代码 [版本 1]

要将此类用在您的应用程序中,您只需创建一个实例并挂接您想处理的事件。钩子在对象创建时自动安装,但您可以使用相应的 public 方法来停止和开始监听。

UserActivityHook actHook;
void MainFormLoad(object sender, System.EventArgs e)
{
    actHook= new UserActivityHook(); // crate an instance

    // hang on events

    actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);
    actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
    actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
    actHook.KeyUp+=new KeyEventHandler(MyKeyUp);
}

现在,一个处理事件的示例

public void MouseMoved(object sender, MouseEventArgs e)
{
    labelMousePosition.Text=String.Format("x={0}  y={1}", e.X, e.Y);
    if (e.Clicks>0) LogWrite("MouseButton     - " + e.Button.ToString());
}

从 [版本 0] 到 [版本 1] 的更改和更新

我想感谢大家在讨论论坛上提供的所有有益评论。在本文于 2004 年 6 月 4 日发布后,出现了很多错误和建议。同样的主题反复出现,我不得不参考讨论中的先前帖子,因此我决定修改代码并发布一个 FAQ。这是最重要更改的列表:

  • 项目已转换为 Visual Studio 2005。
  • 大写字母问题已解决。
  • 鼠标滚轮信息现在包含在事件参数中。
  • 更好的异常处理。
  • 使用事件参数的 Handled 属性取消键盘事件。
  • 函数的 XML 文档。

FAQ [版本 1]

提问

由于调用 SetWindowsHookEx 时出现异常错误,项目无法在 Visual Studio .NET 2005 的调试模式下运行。为什么?这是 .NET 2.0 的问题吗?

答案

编译后的发布版本运行正常,所以不可能是 .NET 2.0 的问题。为了解决这个问题,您只需取消项目属性中名为“启用 Visual Studio 托管进程”的复选框。在菜单:项目 -> 项目属性... -> 调试 -> 启用 Visual Studio 托管进程。

提问

我需要在处理某些按键后抑制它们。

答案

只需在您已处理的按键事件中将 e.Handled 属性设置为 true。这可以防止按键被其他应用程序处理。

提问

是否可以将您的全局钩子转换为应用程序钩子,只捕获应用程序内的按键和鼠标移动?

答案

是的。只需使用...

private const int WH_MOUSE = 7;
private const int WH_KEYBOARD = 2;

... 替换

private const int WH_MOUSE_LL = 14;
private const int WH_KEYBOARD_LL = 13;

提问

在 Win98 (Windows ME, Windows 95) 上可以工作吗?

答案

可以,也可以不可以。全局钩子 WH_MOUSE_LLWH_KEYBOARD_LL 只能在 Windows NT/2000/XP 下监视。在其他情况下,您只能使用应用程序钩子(WH_MOUSEWH_KEYBOARD),它们只捕获应用程序内的按键和鼠标移动。

提问

当我通过点击标题栏上的X按钮关闭应用程序时,会有一个延迟。如果我通过其他事件(如按钮点击)关闭应用程序,则工作正常。

答案

这是 Microsoft 的一个已知 bug。它与 Windows 主题有关。如果您禁用 Windows 主题,问题就会消失。另一种选择是让钩子代码在辅助线程中运行。

提问

如何捕获组合键,例如 Ctrl+Shift+A?

答案

您需要跟踪哪些键被按下但未被释放。只有最近按下的键会发送 KeyDown 消息,但其他键在释放时仍会发送 KeyUp。因此,如果您设置三个标志 IsCtrlDownIsShiftDownIsADown,并在 KeyDown 时将其设置为 true,在 KeyUp 时设置为 false,那么表达式 (IsCtrlDown && IsShiftDown && IsADown) 就会得到所需的结果。

提问

它能与 .NET Framework 1.1 和 Visual Studio 2003 一起使用吗?

答案

是的。文件 UserActivityHook.cs 可以在 Visual Studio 2003 .NET 1.1 项目中直接使用,无需任何更改。

© . All rights reserved.