C#使用钩子获得按键信息的方法

 更新时间:2015年05月14日 10:32:13   作者:两把刷子  
这篇文章主要介绍了C#使用钩子获得按键信息的方法,实例分析了C#中钩子的相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了C#使用钩子获得按键信息的方法。分享给大家供大家参考。具体如下:

窗体相关代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Threading;
using ReadBadCode;
namespace gouzi
{
 public partial class Form2 : Form
 {
  BarCodeHook BarCode = new BarCodeHook();
  public Form2()
  {
   InitializeComponent();
   BarCode.BarCodeEvent += new BarCodeHook.BarCodeDelegate(BarCode_BarCodeEvent);
  }
  private delegate void ShowInfoDelegate(BarCodeHook.BarCodes barCode);
  private void ShowInfo(BarCodeHook.BarCodes barCode)
  {
   if (this.InvokeRequired)
   {
    this.BeginInvoke(new ShowInfoDelegate(ShowInfo), new object[] { barCode });
   }
   else
   {
    textBox1.Text = barCode.KeyName;//键名
    textBox2.Text = barCode.VirtKey.ToString();//虚拟码
    textBox3.Text = barCode.ScanCode.ToString();//扫描码
    textBox4.Text = barCode.AscII.ToString();//AscII
    textBox5.Text = barCode.Chr.ToString();//字符
    textBox6.Text = barCode.IsValid ? barCode.BarCode : "";
    //在这里进行键入值
   }
  }
  void BarCode_BarCodeEvent(BarCodeHook.BarCodes barCode)
  {
   ShowInfo(barCode);
  }
  private void Form2_Load(object sender, EventArgs e)
  {
   BarCode.Start();
  }
  private void Form2_StyleChanged(object sender, EventArgs e)
  {
   BarCode.Stop();
  }
 }
}

后台类代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
namespace ReadBadCode
{
 class BarCodeHook
 {
  public delegate void BarCodeDelegate(BarCodes barCode);
  public event BarCodeDelegate BarCodeEvent;
  public struct BarCodes
  {
   public int VirtKey;  //虚拟码 
   public int ScanCode;  //扫描码 
   public string KeyName; //键名 
   public uint AscII;  //AscII 
   public char Chr;   //字符
   public string BarCode; //条码信息 
   public bool IsValid;  //条码是否有效 
   public DateTime Time; //扫描时间 
  }
  private struct EventMsg
  {
   public int message;
   public int paramL;
   public int paramH;
   public int Time;
   public int hwnd;
  }
  // 安装钩子 
  [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
  // 卸载钩子
  [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  private static extern bool UnhookWindowsHookEx(int idHook);
  // 继续下一个钩子
  [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
  private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
  //获取键名的字符串
  [DllImport("user32", EntryPoint = "GetKeyNameText")]
  private static extern int GetKeyNameText(int lParam, StringBuilder lpBuffer, int nSize);
  //将256个虚拟键复制到指定的缓冲区中
  [DllImport("user32", EntryPoint = "GetKeyboardState")]
  private static extern int GetKeyboardState(byte[] pbKeyState);
  //将指定的虚拟键码和键盘状态为相应的字符串
  [DllImport("user32", EntryPoint = "ToAscii")]
  private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeyState, ref uint lpChar, int uFlags);
  //声明定义回调函数
  delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
  BarCodes barCode = new BarCodes();
  int hKeyboardHook = 0;
  string strBarCode = "";
  private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
  {
   if (nCode == 0)
   {
    EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
    if (wParam == 0x100) //WM_KEYDOWN = 0x100
    {
     barCode.VirtKey = msg.message & 0xff; //虚拟码 
     barCode.ScanCode = msg.paramL & 0xff; //扫描码
     StringBuilder strKeyName = new StringBuilder(255);
     if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0)
     {
      barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '\0' });
     }
     else
     {
      barCode.KeyName = "";
     }
     byte[] kbArray = new byte[256];
     uint uKey = 0;
     GetKeyboardState(kbArray);
     if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0))
     {
      barCode.AscII = uKey;
      barCode.Chr = Convert.ToChar(uKey);
     }
     if (DateTime.Now.Subtract(barCode.Time).TotalMilliseconds > 50)
     {
      strBarCode = barCode.Chr.ToString();
     }
     else
     {
      if ((msg.message & 0xff) == 13 && strBarCode.Length > 3)
      //回车
      {
       barCode.BarCode = strBarCode;
       barCode.IsValid = true;
      }
      strBarCode += barCode.Chr.ToString();
     }
     barCode.Time = DateTime.Now;
     if (BarCodeEvent != null) BarCodeEvent(barCode);
     //触发事件 
     barCode.IsValid = false;
    }
   }
   return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
  }
  // 安装钩子 
  public bool Start()
  {
   if (hKeyboardHook == 0)
   {
    //WH_KEYBOARD_LL = 13 
    hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
   }
   return (hKeyboardHook != 0);
  }
  // 卸载钩子 
  public bool Stop()
  {
   if (hKeyboardHook != 0)
   {
    return UnhookWindowsHookEx(hKeyboardHook);
   }
   return true;
  }
 }
}

【注意】要想测试实际的效果,必须执行编译后的Exe文件,在开发环境直接运行会没有效果的。

希望本文所述对大家的C#程序设计有所帮助。

相关文章

  • CefSharp过滤图片RequestHandler问题

    CefSharp过滤图片RequestHandler问题

    这篇文章主要介绍了CefSharp过滤图片RequestHandler问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • C#实现计算器精简版

    C#实现计算器精简版

    这篇文章主要为大家详细介绍了C#实现计算器精简版,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 亲自教你实现栈及C#中Stack源码分析

    亲自教你实现栈及C#中Stack源码分析

    大家都知道栈的实现方式有两种,一种是基于数组实现的顺序栈,另一种是基于链表实现的链式栈。这篇文章主要介绍了手把手教你实现栈以及C#中Stack源码分析,需要的朋友可以参考下
    2021-09-09
  • C#字符串内存驻留机制分析

    C#字符串内存驻留机制分析

    这篇文章介绍了C#字符串内存驻留机制,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-01-01
  • c#中WinForm使用OpencvSharp4实现简易抓边

    c#中WinForm使用OpencvSharp4实现简易抓边

    本文主要介绍了c#中WinForm使用OpencvSharp4实现简易抓边,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • .Net WInform开发笔记(二)Winform程序运行结构图及TCP协议在Winform中的应用

    .Net WInform开发笔记(二)Winform程序运行结构图及TCP协议在Winform中的应用

    中午没事,把去年刚毕业那会画的几张图翻出来了,大概介绍Winform应用程序运行的过程,以及TCP协议在Winform中的应用。感兴趣的朋友可以了解下;如果有Windows消息机制等基础,很好理解这两张
    2013-01-01
  • C# 键盘Enter键取代Tab键实现代码

    C# 键盘Enter键取代Tab键实现代码

    这篇文章主要介绍了C# 键盘Enter键取代Tab键实现代码,有需要的朋友可以参考一下
    2013-11-11
  • 在.NET中读取嵌入和使用资源文件的方法

    在.NET中读取嵌入和使用资源文件的方法

    本文分别介绍了使用GetManifestResourceStream读取嵌入资源,和使用. resx资源文件嵌入资源,希望对大家有所帮助。
    2016-05-05
  • C#并查集(union-find)算法详解

    C#并查集(union-find)算法详解

    本文详细讲解了C#并查集(union-find)算法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04
  • C#解析json字符串总是多出双引号的原因分析及解决办法

    C#解析json字符串总是多出双引号的原因分析及解决办法

    json好久没用了,今天在用到json的时候,发现对字符串做解析的时候总是多出双引号,下面给大家介绍C#解析json字符串总是多出双引号的原因分析及解决办法,需要的朋友参考下吧
    2016-03-03

最新评论