项目需要在Web项目中获取扫描枪扫描的内容,项目是Java Web项目。
拿到扫描枪后,连接在自己的Windows系统上试了下,插上后,不需要装任何驱动,只要有个文本框,就能将扫描到的内容输入到文本框里。反复测试后发现,当前窗口的焦点在哪里,扫描到的内容就显示在哪里。
先按照盒子上的厂家名称找到官网,在官网上查到了技术支持电话,说他们有串口类型的扫描枪,可支持软件编程。挂完电话看了下我们的上位机,是没有串口的,只有USB接口。但是网上搜了一下,有用Java扫描系统的串口,然后根据串口号获得串口输入进来的东西。
然后就以Java 扫描枪为关键字搜索相关资料,以前还真有人做过这个,在开源中国找到一个前辈做的项目,是一个条形码扫描枪,人家实现了。代码那过来研究了一番,大致明白了。
扫描仪其实说白了对电脑来说就是个键盘, 扫描枪将扫描得到的内容解析,然后模拟键盘,一个一个敲入到电脑中,最后按一下回车键!怪不得焦点在哪个窗口就输入到哪个窗口呢。
那就又遇到一个问题,Java代码运行在Jvm虚拟机内,扫描枪或键盘输入的东西,只有操作系统知道,Jvm虚拟机如何知道呢?那就是JNI编程,通过写C/C++代码,监听操作系统的的输入流,然后通过JNI调用。虽然我不会JNI,也不会C/C++,
但幸运的是,SUN公司已经实现了这个代码,弄出一个叫JNA的东西(Java Native Access),给Java提供了访问操作系统键盘鼠标的能力。
然后将人家的代码完整拷贝,想跑一下,结果没jar包,一直报错,根据包名百度,在maven仓库中找相关jar包,(想找官方的jar包和一些文档,无奈,因为被收购的原因,有些链接已经挂了,找不到哇)找到几个,放进去,编译不报错了,运行一直报错,换了好几个jar包,还是不行,真是可郁闷了。
最后在一个国内的仓库网站找到一个清晰的分类,下载里面的大分类下面的一组jar包,运行成功了。网址是
当自己要实现字母键的时候,才发现,字母不是那么好实现的,因为有大小写区分,还有!@#$%^这些字符需要按住shift键输入。JNA提供的钩子函数,我们能拿到的只有键盘的键控代码,当时感觉很麻烦,想想头都大了。
注意,因为二维码扫描枪只能输入大小写字母、数字、特殊字符,所以其他的键我没管,类似于Ctrl、FN、Alt、F快捷键等。
代码如下
运行需要的jar包在仓库下,网址是://,下载jna-5.2.和jna-platform-5.2.这两个就可以。
import ;
import ;
import ;
import .win32.Kernel32;
import .win32.User32;
import .;
import .;
import .;
import .;
import .;
import .;
import .;
import .;
import .;
public class WindowsKeybordListener {
private static HHOOK hhk;
private static LowLevelKeyboardProc keyboardHook;
static List<Character> singleInput = new ArrayList<Character>();
private static String caseCode() {
StringBuffer buffer = new StringBuffer();
for (Character i : singleInput) {
(i);
}
return ();
}
public static void main(String[] args) {
final User32 lib = ;
HMODULE hMod = (null);
keyboardHook = new LowLevelKeyboardProc() {
boolean isShiftUp = false;
@Override
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
if (nCode >= 0) {
switch (()) {
case WinUser.WM_KEYDOWN:// 只监听键盘按下
//按下回车键,生成完整的字符串,并清空list
if(==13) {
String text = caseCode();
(text);
();
break;
}
//按下的是shift键时,标记一下
if ( == 160) {
isShiftUp = true;
}
if (!isShiftUp) {
if ( >= 65 && <= 90) {//字母键
((char) ( + 32));
} else if ( >= 219 && <= 221) {//[\]
((char) ( - 128));
} else if ( >= 188 && <= 191) {//,-./
((char) ( - 144));
} else if ( >= 48 && <= 57) {//数字键
((char) );
}
if ( == 186) {
(';');
}
if ( == 187) {
('=');
}
if ( == 192) {
('`');
}
if ( == 222) {
('\'');
}
} else {
//大写字母
if ( >= 65 && <= 90) {
((char) );
}
switch () {
case 186:
(':');
break;
case 187:
('+');
break;
case 188:
('<');
break;
case 189:
('_');
break;
case 190:
('>');
break;
case 191:
('?');
break;
case 192:
('~');
break;
case 219:
('{');
break;
case 220:
('|');
break;
case 221:
('}');
break;
case 222:
('\"');
break;
case 48:
('!');
break;
case 49:
('@');
break;
case 50:
('#');
break;
case 51:
('$');
break;
case 52:
('%');
break;
case 53:
('^');
break;
case 54:
('&');
break;
case 55:
('*');
break;
case 56:
('(');
break;
case 57:
(')');
break;
}
}
break;
case WinUser.WM_KEYUP:// 按键起来
if ( == 160) {
isShiftUp = false;
}
break;
}
}
Pointer ptr = ();
long peer = (ptr);
return (hhk, nCode, wParam, new LPARAM(peer));
}
};hhk=(WinUser.WH_KEYBOARD_LL,keyboardHook,hMod,0);
// This bit never returns from GetMessage
int result;
MSG msg = new MSG();while((result=(msg,null,0,0))!=0)
{
if (result == -1) {
// ("error in get message");
break;
} else {
// ("got message");
(msg);
(msg);
}
}(hhk);
}
}