背景:

最近要做一个抓取扫描枪扫描条形码获取条形码数据的功能,以前没有玩过扫描枪,但是因为做过很多其他方面的外设获取数据的项目,所以原理也明白,都是相当于键盘输入,所以相当的是通过获取键盘输入的方案实现,因为这个功能点是用于整个pc上所有扫描枪程序的数据的抓取,就是其他程序用扫描枪,我做的这个程序也能抓取到数据,并对数据进行相应的处理,至于数据处理那是后面自己所做的业务需求的处理了,和抓取扫描枪扫描数据无关了,所以可以通过全局键盘钩子抓取键盘的输入去实现,这样能够去获取每个键盘输入的值,想法有了,那就是实现功能了,至于代码方面吗!由于鄙人做的是Windows客户端的功能,熟悉C#,所以下面的演示是通过WPF展示。

Solution:

有了想法肯定要实际去操作了,首先知道通过全局键盘钩子去抓取键盘输入的数据,那就调用Win32Api创建键盘钩子Hook去实现,这个功能实现代码在网上一搜,那是太容易找到了,博客园里面也有,但是一个完整的功能自己还是自己Copy一下吧!里面注释很全面,都能看懂!

view sourceprint?

001.1 using System;

002.2 using System.Collections.Generic;

003.3 using System.Linq;

004.4 using System.Runtime.InteropServices;

005.5 using System.Text;

006.6 using System.Threading.Tasks;

007.7 using System.Windows.Forms;

008.8

009.9 namespace MedicalMain

010.10 {

011.11     public class KeyboardHook

012.12     {

013.13         public event KeyEventHandler KeyDownEvent;

014.14         public event KeyPressEventHandler KeyPressEvent;

015.15         public event KeyEventHandler KeyUpEvent;

016.16

017.17         public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

018.18         static int hKeyboardHook = 0; //声明键盘钩子处理的初始值

019.19         //值在Microsoft SDK的Winuser.h里查询

020.20         public const int WH_KEYBOARD_LL = 13;   //线程键盘钩子监听键盘消息设为2,全局键盘监听鼠标消息设为13

021.21         HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型

022.22         //键盘结构

023.23         [StructLayout(LayoutKind.Sequential)]

024.24         public class KeyboardHookStruct

025.25         {

026.26             public int vkCode;  //定一个虚拟键码。该代码必须有一个价值的范围1至254

027.27             public int scanCode; // 指定的硬件扫描码的关键

028.28             public int flags;  // 键标志

029.29             public int time; // 指定的时间戳记的这个讯息

030.30             public int dwExtraInfo; // 指定额外信息相关的信息

031.31         }

032.32         //使用此功能,安装了一个钩子

033.33         [DllImport('user32.dll', CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

034.34         public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

035.35

036.36

037.37         //调用此函数卸载钩子

038.38         [DllImport('user32.dll', CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

039.39         public static extern bool UnhookWindowsHookEx(int idHook);

040.40

041.41

042.42         //使用此功能,通过信息钩子继续下一个钩子

043.43         [DllImport('user32.dll', CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

044.44         public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

045.45

046.46         // 取得当前线程编号(线程钩子需要用到)

047.47         [DllImport('kernel32.dll')]

048.48         static extern int GetCurrentThreadId();

049.49

050.50         //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效

051.51         [DllImport('kernel32.dll')]

052.52         public static extern IntPtr GetModuleHandle(string name);

053.53

054.54         public void Start()

055.55         {

056.56             // 安装键盘钩子

057.57             if (hKeyboardHook == 0)

058.58             {

059.59                 KeyboardHookProcedure = new HookProc(KeyboardHookProc);

060.60                 hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);

061.61                 //hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);

062.62                 //************************************

063.63                 //键盘线程钩子

064.64                 //SetWindowsHookEx( 2,KeyboardHookProcedure, IntPtr.Zero, GetCurrentThreadId());//指定要监听的线程idGetCurrentThreadId(),

065.65                 //键盘全局钩子,需要引用空间(using System.Reflection;)

066.66                 //SetWindowsHookEx( 13,MouseHookProcedure,Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),0);

067.67                 //

068.68                 //关于SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, int threadId)函数将钩子加入到钩子链表中,说明一下四个参数:

069.69                 //idHook 钩子类型,即确定钩子监听何种消息,上面的代码中设为2,即监听键盘消息并且是线程钩子,如果是全局钩子监听键盘消息应设为13,

070.70                 //线程钩子监听鼠标消息设为7,全局钩子监听鼠标消息设为14。lpfn 钩子子程的地址指针。如果dwThreadId参数为0 或是一个由别的进程创建的

071.71                 //线程的标识,lpfn必须指向DLL中的钩子子程。 除此以外,lpfn可以指向当前进程的一段钩子子程代码。钩子函数的入口地址,当钩子钩到任何

072.72                 //消息后便调用这个函数。hInstance应用程序实例的句柄。标识包含lpfn所指的子程的DLL。如果threadId 标识当前进程创建的一个线程,而且子

073.73                 //程代码位于当前进程,hInstance必须为NULL。可以很简单的设定其为本应用程序的实例句柄。threaded 与安装的钩子子程相关联的线程的标识符

074.74                 //如果为0,钩子子程与所有的线程关联,即为全局钩子

075.75                 //************************************

076.76                 //如果SetWindowsHookEx失败

077.77                 if (hKeyboardHook == 0)

078.78                 {

079.79                     Stop();

080.80                     throw new Exception('安装键盘钩子失败');

081.81                 }

082.82             }

083.83         }

084.84         public void Stop()

085.85         {

086.86             bool retKeyboard = true;

087.87

088.88

089.89             if (hKeyboardHook != 0)

090.90             {

091.91                 retKeyboard = UnhookWindowsHookEx(hKeyboardHook);

092.92                 hKeyboardHook = 0;

093.93             }

094.94

095.95             if (!(retKeyboard)) throw new Exception('卸载钩子失败!');

096.96         }

097.97         //ToAscii职能的转换指定的虚拟键码和键盘状态的相应字符或字符

098.98         [DllImport('user32')]

099.99         public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。

100.100                                          int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。高阶位的这个值设定的关键,如果是(不压)

101.101                                          byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。如果高阶位的字节是一套,关键是下跌(按下)。在低比特,如果设置表明,关键是对切换。在此功能,只有肘位的CAPS LOCK键是相关的。在切换状态的NUM个锁和滚动锁定键被忽略。

102.102                                          byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。

103.103                                          int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.

104.104

105.105         //获取按键的状态

106.106         [DllImport('user32')]

107.107         public static extern int GetKeyboardState(byte[] pbKeyState);

108.108

109.109

110.110         [DllImport('user32.dll', CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]

111.111         private static extern short GetKeyState(int vKey);

112.112

113.113         private const int WM_KEYDOWN = 0x100;//KEYDOWN

114.114         private const int WM_KEYUP = 0x101;//KEYUP

115.115         private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN

116.116         private const int WM_SYSKEYUP = 0x105;//SYSKEYUP

117.117

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

119.119         {

120.120             // 侦听键盘事件

121.121             if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null || KeyPressEvent != null))

122.122             {

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

124.124                 // raise KeyDown

125.125                 if (KeyDownEvent != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))

126.126                 {

127.127                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;

128.128                     KeyEventArgs e = new KeyEventArgs(keyData);

129.129                     KeyDownEvent(this, e);

130.130                 }

131.131

132.132                 //键盘按下

133.133                 if (KeyPressEvent != null && wParam == WM_KEYDOWN)

134.134                 {

135.135                     byte[] keyState = new byte[256];

136.136                     GetKeyboardState(keyState);

137.137

138.138                     byte[] inBuffer = new byte[2];

139.139                     if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1)

140.140                     {

141.141                         KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);

142.142                         KeyPressEvent(this, e);

143.143                     }

144.144                 }

145.145

146.146                 // 键盘抬起

147.147                 if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))

148.148                 {

149.149                     Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;

150.150                     KeyEventArgs e = new KeyEventArgs(keyData);

151.151                     KeyUpEvent(this, e);

152.152                 }

153.153

154.154             }

155.155             //如果返回1,则结束消息,这个消息到此为止,不再传递。

156.156             //如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递,也就是传给消息真正的接受者

157.157             return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);

158.158         }

159.159

160.160         ~KeyboardHook()

161.161         {

162.162             Stop();

163.163         }

164.164

165.165     }

166.166 }

键盘钩子功能类实现了,下面就是调用该类了,能够抓取到键盘的输入的每个值了

view sourceprint?

1.eyboardHook k_hook = new KeyboardHook();

2.k_hook.KeyDownEvent += new System.Windows.Forms.KeyEventHandler(hook_KeyDown);//钩住键按下

3.private void hook_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)

4.{

5.///

6.}

hook_KeyDown方法在每次按键都会触发,能够通过参数e获取到每次键盘输入的键值,这样键盘钩子虽然实现了,但是我们在正常的使用过程中有的时候是通过真实的键盘按键输入,有的时候通过扫描枪扫描输入,那这个时候该如何区分是通过扫描枪还是通过键盘按键输入呢!后来通过度娘查了一下发现了一种解决方案,但是这个解决方案是有判断不是非常精确的,通过按键的间隔时间去判断去,下面代码的实现:

view sourceprint?

01.1  ///

02.2         ///键盘按下触发的事件

03.3         ///

04.4         ///

05.5         ///

06.6         private void hook_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)

07.7         {

08.8            string temp=string.Empty;

09.9            DateTime nowTime = DateTime.Now;

10.10            if ((e.KeyData >= Keys.D0 && e.KeyData <= Keys.D9) || (e.KeyData >= Keys.NumPad0 && e.KeyData <= Keys.NumPad9))//判断是不是数字的键盘值

11.11                temp = (e.KeyData.ToString()).Last().ToString();

12.12            else

13.13                temp = e.KeyData.ToString();

14.14             if((nowTime-previewTime).Milliseconds<20)//通过判断键盘输入的间隔来确定是扫描枪还是通过键盘输入的

15.15             {

16.16                 if (e.KeyValue == (int)Keys.Return&&inputKey.Length>2)

17.17                 {

18.18                     this.tb_Key.Text = inputKey.ToString();

19.19                     inputKey = new StringBuilder();

20.20                     previewTime = DateTime.Now;

21.21                     return;

22.22                 }

23.23                 inputKey.Append(temp);

24.24

25.25             }

26.26             else

27.27             {

28.28                 inputKey=new StringBuilder(temp);

29.29             }

30.30             previewTime = DateTime.Now;

31.31         }

因为扫描枪最后扫描完成后会返回一个回车键,我们通过回车键和每个按键的时间间隔去判断,为了防止同事按下某一个键和回车键,他们的时间间隔也是很小,所以可能通过最后输入的字符串的长度去判断,毕竟条形码只有一两个字符的很少吧,看个人的需求了!

总结:

抓取扫描枪扫描数据实现很简单,也没深奥的技术,就是对自己实现功能的一个记录,也是想让其他人能够给指点一下,是否有更准确的方案,毕竟一个pc上不一定只接了一个外设,很多其他的外设可能也会刷入数据,这样就无法区分是扫描枪还是其他外设的输入的数据了!如果有更好的建议的希望留言指点,先感谢大家了!

推荐一款适合二次开发的仓库扫描枪:FS01指环式条码扫描枪http://www.posunitech.cn

linux添加usb扫描枪,抓取扫描枪扫描数据的案例相关推荐

  1. linux原始套接字抓取网络数据包

    基于linux的抓包 一.获取数据     当我们在做网络安全或者数据探测等工作经常会用到抓包.熟悉的工具有tcpdump.wireshark等,这里我们介绍如何使用C程序原始套接字在linux系统上 ...

  2. Python 3.6 抓取微博m站数据

    Python 3.6 抓取微博m站数据 2019.05.01 更新内容 containerid 可以通过 "107603" + user_id 组装得到,无需请求个人信息获取: 优 ...

  3. 小猪的Python学习之旅 —— 20.抓取Gank.io所有数据存储到MySQL中

    小猪的Python学习之旅 -- 20.抓取Gank.io所有数据存储到MySQL中 标签:Python 一句话概括本文: 内容较多,建议先mark后看,讲解了一波MySQL安装,基本操作,语法速成, ...

  4. python代码案例详解-我用Python抓取了7000 多本电子书案例详解

    安装 安装很简单,只要执行: pip install requests-html 就可以了. 分析页面结构 通过浏览器审查元素可以发现这个电子书网站是用 WordPress 搭建的,首页列表元素很简单 ...

  5. 绕过SSL双向校验抓取Soul App的数据包

    参考了这篇文章:Android抓包总结 - 先知社区 https://xz.aliyun.com/t/6551#toc-10 毫无反编译经验的我,硬着头皮参考这篇文章抓到数据,记录一下抓包过程,全部是 ...

  6. Burpsuite 抓取微信小程序数据包

    Burpsuite 抓取微信小程序数据包 一.网上的方法 ① 手机导入CA证书,设置指定DNS,亲测无效 备注:此方法可抓取微信公众号的数据,但是无法抓取微信小程序的数据 ② 使用安卓模拟器,我下载的 ...

  7. 抓取微信小程序数据包的三种方法

    前言 做安全测试的都会遇到测试某微信小程序,而微信小程序基本都是基于HTTPS的,所以抓取HTTPS数据包就是最关键的一步.最近几天折腾了一下,整理了比较简单.方便的三种方法. 条件 抓取微信小程序数 ...

  8. Python 抓取中国银行外汇牌价首页数据

    利用requests.BeautifulSoup.xlwings库抓取中国银行外汇牌价首页数据 (1)中国银行外汇牌价网址 import requests from bs4 import Beauti ...

  9. charles抓取微信小程序数据(抓取http和https数据)

    本文中使用的是mac上的抓包工具charles进行抓包,手机是华为荣耀8,安卓版本7.0(其实跟版本没啥关系) 要想抓取到微信小程序的数据首先要解决的第一个问题件就是如何 通过charles抓取手机上 ...

  10. 结束 txt进程_Python多进程抓取拉钩网十万数据

    转载:Python多进程抓取拉钩网十万数据 准备 安装Mongodb数据库 其实不是一定要使用MongoDB,大家完全可以使用MySQL或者Redis,全看大家喜好.这篇文章我们的例子是Mongodb ...

最新文章

  1. GeoQuiz项目的开发与总结2
  2. 会说话的狗狗本电脑版_会说话的电脑有点酷!惠普星14帮你解锁“偷懒”新姿势_惠普 星 14 2020(i5 1135G7/16GB/512GB/MX450)_笔记本新闻...
  3. 查看历史操作记录_燕麦课堂丨操作日志管理,为企业数据安全保驾护航
  4. 20应用统计考研复试要点(part14)--应用多元分析
  5. SpringCloud常见问题总结(二)
  6. python初学者用什么开发环境_python初学者用什么开发环境
  7. Realme XT发布会PPT曝光:后置6400万四摄+骁龙712
  8. 计算机基础知识PDF文档,计算机基础知识(范文).pdf
  9. Vue_eslint编码规范检查---vue工作笔记0021
  10. sql创建表主键gui_在SQL Server中使用主数据服务快速创建最终用户可以维护的GUI
  11. LeetCode 77. Combinations
  12. TagSupport标签的应用
  13. mysql分组求和_mysql 行转列,对列的分组求和,对行求和
  14. 手机APP项目测试点总结
  15. Kali Linux 安装网易云音乐打不开的解决方法
  16. 【机器视觉硬件】机器视觉硬件学习笔记2——工业相机
  17. 2011年中国程序员薪水,蛋疼。
  18. Java实现家谱家族管理系统,图形化家谱家族树,单机应用程序
  19. Java知识点的总结(一)
  20. 企业信用代码等常用的正则验证

热门文章

  1. PDF有口令密码怎么移除?
  2. js实现直接打印pdf文件内容解决方案
  3. 怎么用PS为一寸证件照更换底色背景色
  4. Gamma 分布函数可加性证明
  5. 正弦交流电的最大值、有效值、和瞬间值概念解析和计算
  6. Python零基础爬虫速成②:批量爬取微信公众号图片(基于beautifulsoup爬取吉他谱)
  7. 线程启动、结束,创建线程多法、join,detach
  8. png格式图像转成jpg图像时出现异常颜色值
  9. 强大的网页数据库管理工具Adminer
  10. UE4-蓝图-角色的移动,视角控制(五)人物走动到停下过度动画