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

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

C# 中变量未赋值能用吗,各种类型的初始值是什么

对于一个局部变量,如果未赋值,是不能使用的 对于属性,未赋值,也能使用有系统默认值,默认值如下: 对于 int 类型,默认值是 0;对于 int? 类型,默认值是 null;对于 bool 类型,默认值是 false;对于 bool? 类型,默认值是 null;对于 string 类型,默认值是 null;对于 string? 类型,哈哈,没有这种写法,会出错;对于 DateTime 类型,默

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

uniapp接入微信小程序原生代码配置方案(优化版)

uniapp项目需要把微信小程序原生语法的功能代码嵌套过来,无需把原生代码转换为uniapp,可以配置拷贝的方式集成过来 1、拷贝代码包到src目录 2、vue.config.js中配置原生代码包直接拷贝到编译目录中 3、pages.json中配置分包目录,原生入口组件的路径 4、manifest.json中配置分包,使用原生组件 5、需要把原生代码包里的页面修改成组件的方

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

【操作系统】信号Signal超详解|捕捉函数

🔥博客主页: 我要成为C++领域大神🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 ​ 如何触发信号 信号是Linux下的经典技术,一般操作系统利用信号杀死违规进程,典型进程干预手段,信号除了杀死进程外也可以挂起进程 kill -l 查看系统支持的信号