C# 在程序焦点之外捕捉按键操作(键盘钩子的使用)

本文主要是介绍C# 在程序焦点之外捕捉按键操作(键盘钩子的使用),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在程序中捕捉用户的按键行为很容易,但是假如程序最小化了或者隐藏到系统托盘了,这时因为程序已经失去焦点了我们想捕捉按键行为就不是那么容易了。怎么办呢?这就要使用键盘钩子了。

关于键盘钩子,下面这个网友描述的很详尽,我就不班门弄斧了,转载过来以备不时之需。原文:http://www.cnblogs.com/hocylan/archive/2008/01/14/1038390.html


概要

1 目的:完成简单的监控和屏蔽

2 技术:钩子(系统监控必须全局钩子)

3 步骤:

   A 安装钩子

   B 回调函数

   C 处理函数

   D 普通业务处理

   ……

4 完成

下载源程序和运行程序

http://files.cnblogs.com/hocylan/KeyboardHook.rar

运行界面如下:

说明:

C++中实现该功能十分简单,也有很多经典例子可以实现,在C#中确有很多问题会出现。

对于钩子知识不太熟悉可以参考我转载的另一篇文章:http://www.cnblogs.com/hocylan/articles/1033895.html[微软HOOK技术专题]

大概步骤

其实主要就是调用windows API
第一步
:安装钩子:SetWindowsHookEx(WH_Codes idHook, HookProc lpfn,IntPtr pInstance, int threadId);

第二步:回调和处理 CallNextHookEx(IntPtr pHookHandle, int nCode,Int32 wParam, IntPtr lParam);

第三步:完成普通的业务处理其它流程

        将封装的钩子应用到系统中…….

        private void start_Click(object sender, EventArgs e)

        { hook_Main.InstallHook("1");}

        private void stop_Click(object sender, EventArgs e)

        {this.hook_Main.UnInstallHook();}

        private void stopkeyboard_Click(object sender, EventArgs e)

        { hook_Main.InstallHook("2"); }

第四步:拆卸钩子UnhookWindowsHookEx(IntPtr pHookHandle);

 

四 重要代码和解释:

*封装的hook类:

using System;

using System.Windows.Forms;

using System.Runtime.InteropServices; //必须引用

using System.Reflection; //必须引用

namespace KeyboardHook

{

    class Hocy_Hook

    {

        #region私有常量

         ///<summary>

         ///按键状态数组

         ///</summary>

         private readonly byte[] m_KeyState = new byte[ 256 ];

        private string flags;

        //flag=0 正常 flag=1 监控状态 flag=2 屏蔽键盘//

         #endregion私有常量

         #region私有变量

         ///<summary>

         ///鼠标钩子句柄

         ///</summary>

         private IntPtr m_pMouseHook = IntPtr.Zero;

         ///<summary>

         ///键盘钩子句柄

         ///</summary>

         private IntPtr m_pKeyboardHook = IntPtr.Zero;

         ///<summary>

         ///鼠标钩子委托实例

         ///</summary>

         ///<remarks>

         ///不要试图省略此变量,否则将会导致

         ///激活CallbackOnCollectedDelegate 托管调试助手(MDA)。

         ///详细请参见MSDN中关于CallbackOnCollectedDelegate 的描述

         ///</remarks>

         private HookProc m_MouseHookProcedure;

         ///<summary>

         ///键盘钩子委托实例

         ///</summary>

         ///<remarks>

         ///不要试图省略此变量,否则将会导致

         ///激活CallbackOnCollectedDelegate 托管调试助手(MDA)。

         ///详细请参见MSDN中关于CallbackOnCollectedDelegate 的描述

         ///</remarks>

         private HookProc m_KeyboardHookProcedure;

        // 添加

        public event MouseEventHandler OnMouseActivity;

        private const byte VK_SHIFT = 0x10 ;

        private const byte VK_CAPITAL = 0x14;

        private const byte VK_NUMLOCK = 0x90;

         #endregion私有变量

         #region事件定义

         ///<summary>

         ///鼠标更新事件

         ///</summary>

         ///<remarks>当鼠标移动或者滚轮滚动时触发</remarks>

         public event MouseUpdateEventHandler OnMouseUpdate;

         ///<summary>

         ///按键按下事件

         ///</summary>

         public event KeyEventHandler OnKeyDown;

         ///<summary>

         ///按键按下并释放事件

         ///</summary>

         public event KeyPressEventHandler OnKeyPress;

         ///<summary>

         ///按键释放事件

         ///</summary>

         public event KeyEventHandler OnKeyUp;

         #endregion事件定义

         #region私有方法

         ///<summary>

         ///鼠标钩子处理函数

         ///</summary>

         ///<param name="nCode"></param>

         ///<param name="wParam"></param>

         ///<param name="lParam"></param>

         ///<returns>鼠标钩子处理函数</returns>

         private int MouseHookProc( int nCode, Int32 wParam, IntPtr lParam )

         {

 if ((nCode >= 0) && (OnMouseActivity != null))

            {

                //Marshall the data from callback.

                MouseHookStruct mouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

                //detect button clicked

                MouseButtons button = MouseButtons.None;

                short mouseDelta = 0;

                switch (wParam)

                {

                    case (int)WM_MOUSE.WM_LBUTTONDOWN:

                        //case WM_LBUTTONUP:

                        //case WM_LBUTTONDBLCLK:

                        button = MouseButtons.Left;

                        break;

                    case (int)WM_MOUSE.WM_RBUTTONDOWN:

                        //case WM_RBUTTONUP:

                        //case WM_RBUTTONDBLCLK:

                        button = MouseButtons.Right;

                        break;

                    case (int)WM_MOUSE.WM_MOUSEWHEEL:

                        //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta.

                        //One wheel click is defined as WHEEL_DELTA, which is 120.

                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value

                        mouseDelta = (short)((mouseHookStruct.MouseData>> 16) & 0xffff);

                        //TODO: X BUTTONS (I havent them so was unable to test)

                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,

                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released,

                        //and the low-order word is reserved. This value can be one or more of the following values.

                        //Otherwise, mouseData is not used.

                        break;

                }

                //double clicks

                int clickCount = 0;

                if (button != MouseButtons.None)

                    if (wParam == (int)WM_MOUSE.WM_LBUTTONDBLCLK || wParam == (int)WM_MOUSE.WM_RBUTTONDBLCLK) clickCount = 2;

                    else clickCount = 1;

                //generate event

                MouseEventArgs e = new MouseEventArgs(

                                                   button,

                                                   clickCount,

                                                   mouseHookStruct.Point.X,

                                                   mouseHookStruct.Point.Y,

                                                   mouseDelta);

                //raise it

                OnMouseActivity(this, e);

            } 

           

            //*

              return Win32API.CallNextHookEx( this.m_pMouseHook, nCode, wParam, lParam );

         }

         ///<summary>

         ///键盘钩子处理函数

         ///</summary>

         ///<param name="nCode"></param>

         ///<param name="wParam"></param>

         ///<param name="lParam"></param>

         ///<returns></returns>

         ///<remarks></remarks>

         private int KeyboardHookProc( int nCode, Int32 wParam, IntPtr lParam )

         {

          

            switch (flags)

            {

                case "2":

                    return 1;

                    break;

                case "1":

                    break;

            }

            bool handled = false;

            //it was ok and someone listens to events

            if ((nCode >= 0) && (this.OnKeyDown != null || this.OnKeyUp!= null || this.OnKeyPress!= null))

            {

                //read structure KeyboardHookStruct at lParam

                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));

                //raise KeyDown

                if (this.OnKeyDown != null && (wParam == (int)WM_KEYBOARD.WM_KEYDOWN || wParam == (int)WM_KEYBOARD.WM_SYSKEYDOWN))

                {

                    Keys keyData = (Keys)MyKeyboardHookStruct.VKCode;

                    KeyEventArgs e = new KeyEventArgs(keyData);

                   this.OnKeyDown(this, e);

                    handled = handled || e.Handled;

                }

                // raise KeyPress

                    if (this.OnKeyPress != null && wParam == (int)WM_KEYBOARD.WM_KEYDOWN)

                    {

                        bool isDownShift, isDownCapslock;

                        try

                        {

                             isDownShift = ((Win32API.GetKeyStates(VK_SHIFT) & 0x80) == 0x80 ? true : false);

                            isDownCapslock = (Win32API.GetKeyStates(VK_CAPITAL) != 0 ? true : false);

                        }

                        catch

                        {

                            isDownCapslock = false;

                            isDownShift= false;

                        }

                        byte[] keyState = new byte[256];

                       Win32API.GetKeyboardState(keyState);

                        byte[] inBuffer = new byte[2];

                        if (Win32API.ToAscii(MyKeyboardHookStruct.VKCode,

                                  MyKeyboardHookStruct.ScanCode,

                                  keyState,

                                  inBuffer,

                                  MyKeyboardHookStruct.Flags) == 1)

                        {

                            char key = (char)inBuffer[0];

                            if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);

                            KeyPressEventArgs e = new KeyPressEventArgs(key);

                            this.OnKeyPress(this, e);

                            handled = handled || e.Handled;

                        }

                    }

                // raise KeyUp

                if (this.OnKeyUp != null && (wParam == (int)WM_KEYBOARD.WM_KEYUP || wParam == (int)WM_KEYBOARD.WM_SYSKEYUP))

                {

                    Keys keyData = (Keys)MyKeyboardHookStruct.VKCode;

                    KeyEventArgs e = new KeyEventArgs(keyData);

                    this.OnKeyUp(this, e);

                    handled = handled || e.Handled;

                }

            }

            //if event handled in application do not handoff to other listeners

            if (handled)

                return 1;

            else

                return Win32API.CallNextHookEx(this.m_pKeyboardHook, nCode, wParam, lParam);

        }

            

         #endregion私有方法

         #region公共方法

         ///<summary>

         ///安装钩子

         ///</summary>

         ///<returns></returns>

         public bool InstallHook(string flagsinfo)

         {

            this.flags = flagsinfo;

IntPtr pInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);

//pInstance = (IntPtr)4194304;

          //注意:很多时候得到的pInstanc无法安装钩子,请检查值是否为4194304,在应用程序中可以直接取得pinstance的

           // IntPtr pInstanc2 = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly());

           // Assembly.GetExecutingAssembly().GetModules()[0]

              //安装鼠标钩子

              if ( this.m_pMouseHook == IntPtr.Zero )

              {

                   this.m_MouseHookProcedure = new HookProc( this.MouseHookProc );

                   this.m_pMouseHook = Win32API.SetWindowsHookEx( WH_Codes.WH_MOUSE_LL,this.m_MouseHookProcedure, pInstance, 0 );

// WH_Codes.WH_MOUSE_LL为全局钩子即系统钩子,否则应该为WH_Codes.WH_KEYBOARD,即普通钩子

                   if ( this.m_pMouseHook == IntPtr.Zero )

                   {

                       this.UnInstallHook();

                       return false;

                   }

              }

              if ( this.m_pKeyboardHook == IntPtr.Zero ) //安装键盘钩子

              {

                   this.m_KeyboardHookProcedure = new HookProc( this.KeyboardHookProc );

                  // WH_Codes.WH_KEYBOARD_LL为全局钩子即系统钩子,否则应该为WH_Codes.WH_KEYBOARD,即普通钩子

                   this.m_pKeyboardHook = Win32API.SetWindowsHookEx( WH_Codes.WH_KEYBOARD_LL,this.m_KeyboardHookProcedure, pInstance, 0 );

                   if ( this.m_pKeyboardHook == IntPtr.Zero )

                   {

                       this.UnInstallHook();

                       return false;

                   }

              }

              return true;

         }

         ///<summary>

         ///卸载钩子

         ///</summary>

         ///<returns></returns>

         public bool UnInstallHook()

         {

              bool result = true;

              if ( this.m_pMouseHook != IntPtr.Zero )

              {

                   result = ( Win32API.UnhookWindowsHookEx( this.m_pMouseHook ) && result );

                   this.m_pMouseHook = IntPtr.Zero;

              }

              if ( this.m_pKeyboardHook != IntPtr.Zero )

              {

                   result = ( Win32API.UnhookWindowsHookEx( this.m_pKeyboardHook ) && result );

                   this.m_pKeyboardHook = IntPtr.Zero;

              }

              return result;

         }

         #endregion公共方法

         #region构造函数

         ///<summary>

         ///钩子类

         ///</summary>

         ///<remarks>本类仅仅简单实现了WH_KEYBOARD_LL 以及WH_MOUSE_LL </remarks>

         public Hocy_Hook()

         {

              Win32API.GetKeyboardState( this.m_KeyState );

         }

         #endregion构造函数

    }

}

另外感谢来自GermanyGeorge Mamaladze,看了他的代码,给了我比较好的思路

http://www.codeproject.com/KB/cs/globalhook.aspx


这篇关于C# 在程序焦点之外捕捉按键操作(键盘钩子的使用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1008466

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三