首页 > 编程语言 >c#使用Hook钩子全局监听键盘和鼠标

c#使用Hook钩子全局监听键盘和鼠标

时间:2024-01-22 14:59:17浏览次数:30  
标签:codes 鼠标 c# 钩子 else vkCode Hook int Append

背景:今天接到客户一个需求,就是在收银员在用扫码枪扫顾客会员码或者微信付款码的时候判断用户有没有加企微好友和进企微群,然后根据这个状态进行语音播报,判断顾客能不能享受优惠价。关键难点就是用户用的收银系统是别家的,线上小程序用的是我们家的,两家不互通,所以立即决定采用Hook钩子技术做一工具挂在其他收银系统上。

Hook钩子

Windows是一个不断处理消息的系统,每次的鼠标点击移动键盘输入都是消息。钩子是系统消息处理的一环,可以使用钩子处理函数来监听消息传送,并处理消息。

思路

  1. 用WPF做一个无边框小小的半透明圆形窗体使用TopMost长驻留在桌面上。
  2. 增加一个ContextMenu 菜单,安装钩子和卸载钩子
  3. 接入钩子API
#region 第一步:声明API函数。
// 安装钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
// 卸载钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
// 继续下一个钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
// 取得当前线程编号
[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId();
#endregion

  1. 声明键盘消息结构和鼠标消息结构
public struct KeyMSG
{
    public int vkCode;
    public int scanCode;
    public int flags;
    public int time;
    public int dwExtraInfo;
}
public struct MSG
{
    public Point p;
    public IntPtr HWnd;
    public uint wHitTestCode;
    public int dwExtraInfo;
}
  1. 安装键盘钩子和鼠标钩子
private void install_Click(object sender, RoutedEventArgs e)
{
    HookStart();
}
private void HookStart()
{
    if (hKeyboardHook == 0)//如果hKeyboardHook==0,钩子安装失败
    {
        //创建HookProc实例
        KeyboardHookProcedure = new HookProc(KeyboardHookProc);
        //设置全局钩子
        hKeyboardHook = SetWindowsHookEx(13, KeyboardHookProcedure,
   Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
        if (hKeyboardHook == 0)
        {
            //终止钩子
            throw new Exception("安装钩子失败");
        }
        Trace.WriteLine("键盘钩子安装成功");
    }
    if(hMouseHook == 0)
    {
        mouseHookProcedure = new HookProc(MouseHookProc);
        hMouseHook = SetWindowsHookEx(14, mouseHookProcedure,
   Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0); 
        if(hMouseHook == 0)
        {
            throw new Exception("安装鼠标钩子失败");
        }
        Trace.WriteLine("鼠标钩子安装成功");
    }
}
  1. 增加键盘钩子和鼠标钩子处理函数
private StringBuilder codes = new StringBuilder(); //接收扫码枪输入的数据
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
    if (nCode >= 0)
    {
        if(wParam == 0x100)
        {
            KeyMSG m = (KeyMSG)Marshal.PtrToStructure(lParam, typeof(KeyMSG));
            if (m.vkCode == 0x31)
            {
                codes.Append(1);
            }
            else if (m.vkCode == 0x32)
            {
                codes.Append(2);
            }
            else if (m.vkCode == 0x33)
            {
                codes.Append(3);
            }
            else if (m.vkCode == 0x34)
            {
                codes.Append(4);
            }
            else if (m.vkCode == 0x35)
            {
                codes.Append(5);
            }
            else if (m.vkCode == 0x36)
            {
                codes.Append(6);
            }
            else if (m.vkCode == 0x37)
            {
                codes.Append(7);
            }
            else if (m.vkCode == 0x38)
            {
                codes.Append(8);
            }
            else if (m.vkCode == 0x39)
            {
                codes.Append(9);
            }
            else if (m.vkCode == 0x30)
            {
                codes.Append(0);
            }
            else if (m.vkCode == 0x60)
            {
                codes.Append(0);
            }
            else if (m.vkCode == 0x61)
            {
                codes.Append(1);
            }
            else if (m.vkCode == 0x62)
            {
                codes.Append(2);
            }
            else if (m.vkCode == 0x63)
            {
                codes.Append(3);
            }
            else if (m.vkCode == 0x64)
            {
                codes.Append(4);
            }
            else if (m.vkCode == 0x65)
            {
                codes.Append(5);
            }
            else if (m.vkCode == 0x66)
            {
                codes.Append(6);
            }
            else if (m.vkCode == 0x67)
            {
                codes.Append(7);
            }
            else if (m.vkCode == 0x68)
            {
                codes.Append(8);
            }
            else if (m.vkCode == 0x69)
            {
                codes.Append(9);
            }
            if (m.vkCode == 0x0D)
            {
                // 回车键
                string code = codes.ToString();
                Trace.WriteLine(code);
                if(code.Length == 18)
                {
                    StatausHandle(code);
                    codes.Clear();
                }                        
            }
        }                
    }
    return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
  1. 卸载键盘钩子和鼠标钩子
private void unInstall_Click(object sender, RoutedEventArgs e)
{
    HookStop();
}
private void HookStop()
 {
     bool retKeyboard = true;
     if (hKeyboardHook != 0)
     {
         retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
         hKeyboardHook = 0;
     }
     if (!retKeyboard)
         throw new Exception("钩子卸载失败");

     Trace.WriteLine("键盘钩子卸载成功");
     if (hMouseHook != 0)
     {
         retKeyboard = UnhookWindowsHookEx(hMouseHook);
         hMouseHook = 0;
     }
     if (!retKeyboard)
         throw new Exception("鼠标钩子卸载失败");
     Trace.WriteLine("鼠标钩子卸载成功");
 }
  1. 好了,拿到的code就算扫码枪输入的条码,根据这个条码实现自己的判断逻辑来进行语音播报就行了。

标签:codes,鼠标,c#,钩子,else,vkCode,Hook,int,Append
From: https://www.cnblogs.com/leafroc/p/17980022

相关文章

  • 华企盾DSC的如何管控企业文件外发权限的?
    随着企业运营的数据化,信息已成为决策、优化和竞争的关键。然而,数据资产的价值,也使其成为了各种风险的目标。尤其在员工共享和外发文件时,无论是无意的错误操作还是恶意的信息窃取,都可能导致重要数据的风险暴露。因此,将如何管控企业文件外发权限落到实处,就显得至关重要。一、文件......
  • select count(*) 引发的思考
    1、属性上添加注解:@JsonIgnoreimportcom.fasterxml.jackson.annotation.JsonIgnore;@JsonIgnore@ApiModelProperty("属性")privateLongsqlTotal;privateinttotal;针对Long类型,接口返回时,会转化为字符串,这样做是因为怕前端解析时出现精度问题......
  • vscode本地调试gitbook
    1.windows下载安装git2.安装nodejs下载安装nvmhttps://github.com/coreybutler/nvm-windows/releases/download/1.1.9/nvm-setup.exe安装配置nodejsC:\Users\Administrator>nvminstall10Downloadingnode.jsversion10.24.1(64-bit)...CompleteCreating......
  • rockertmq--linux环境下安装
    在Linux系统上安装RocketMQ涉及到下载RocketMQ的二进制包、配置环境、启动NameServer和Broker等步骤。以下是一个基本的安装指南,请确保你有足够的权限来执行以下操作。安装Java环境:RocketMQ是基于Java开发的,因此你需要在你的Linux系统上安装Java。RocketMQ推荐使用Java8。su......
  • CF1770C
    分析不难发现,由于\(x>0\),所以当出现两个相同数的时候一定是NO。再然后,发现对于一个数\(k\),记\(re_i\)表示\(a\)中模\(k\)余\(i\)的数的个数,若对于所有的\(0\lei<k\),都有\(re_i>1\),那么不管你加多少,必定有至少\(2\)个\(k\)的倍数,不互质,因此也是NO。剩下的就是......
  • C# SerialPort.Open() COM蓝牙串口阻塞问题
    这种问题一般是蓝牙串口的问题,即使设置了SerialPort.TimeOut也是没有用的,需要验证串口名称,跳过该串口SerialPort.Open()步骤这种有问题的蓝牙串口设备名称中会带有BTHENUM那么我们就要取到串口名称,C#提供的SerialPort类只能取到串口编号,所以我们需要借助WMI取串口名称privateb......
  • Python web crawler(2)json异步加载的格式
    异步加载的特点点击“查看更多”等按钮,浏览器“刷新”按钮无反馈效果。查看浏览器点击F12的“DevTools”开发者工具,点选“网络”——“Fetch/XHR”——每点击一次“加载更多”就会出现一次网络请求点击刷新出来的“请求内容”——点击“响应”,可以看到响应的是“字典”点击标......
  • abc等多个系统 每个系统有多个文档 ,每个系统根据不同的文类型获取该文件类型最新上传
    假如有abc等多个系统每个系统有多个文档,每个系统根据不同的文类型获取该文件类型最新上传时间文档(文件类型(文件类型字段为idoctype)分别为设计文档和评审记录文档,最新上传时间字段为duptime)这个思路和Java代码list怎莫处理对于这个问题,可以使用一个嵌套的Map来处理。外层的M......
  • 高铁拉我,马拉车——记高铁路上的manacher
    目录前言问题引入思路一览manacher高效的原因具体情况讨论小问题的讨论code前言不得为什么,总会在奇奇怪怪的时候特定时间看算法比平常看得舒服多了,之前看字符串匹配的时候自然是准备把马拉车一起看了的,但是那时候看不下去,昨天回家的高铁上再次看了看,觉得格外的亲切,emmm问题引入......
  • C语言中的野指针问题
    1、以下这种情况p也是个野指针int*ceFun(){intx=5;return&x;}intmain(){int*p=ceFun();*p=70;printf("%p\n",p);return0;}因为p指向了一个局部变量,指向了一个已经释放内存的变量2、还有哪些现象,开始定义的时候没......