好先生,我有一个问题。我目前正在研究的学校Java项目要求我将USB条形码扫描仪作为外部输入连接到我的笔记本电脑。我还没有真正买过USB扫描仪,因为它对学生而言相当昂贵。因此,我必须收集证据证明此扫描程序可以与我的程序一起使用。
扫描仪是否能够读取条形码(可能是在线打印)并将其存储到变量中?如果是这样,扫描仪按下的动作事件是否真的像键盘按键一样被读取?如果是这样,代码行会是什么样的?
此外,如果您可以发布条形码扫描仪的经验,或提供任何建议,例如购买哪种扫描仪,这将有所帮助。干杯!
答案 0 :(得分:31)
我最近不得不实现一个与java交互的扫描系统。
我使用 Honeywell Voyager MS9540 USB条形码扫描仪。
默认情况下,扫描仪将数据作为键盘输入直接发送 - 无需驱动程序。
但很容易让这个模型与直接与java进行交互,而不是使用键盘钩子(将条形码用作java中的变量,正如您所提到的)。
此模型具有模拟串行端口的设置,然后您可以使用javax.comm包读取扫描数据。对我来说,这比键盘钩子更好很多来获取条形码数据,因为程序在能够解释扫描之前不需要焦点(我不想创建全局键盘钩子)
我的java程序读取指定串行端口的所有输入,并将条形码写入数据库。我还设置程序将任何无法识别的条形码扫描传递到键盘(我的应用程序没有创建的任何条形码 - 我在我的条形码上使用了不同的签名)这样它就可以作为常规条形码扫描仪用于任何其他可能的应用程序从键盘上读取条形码。
您可以直接从任何USB扫描仪读取数据(没有此模型具有的串行端口仿真),通过执行一些密集的JNI编码,但我不准备花时间计算本机代码。
要为串行端口仿真配置此特定模型,您只需使用要配置的扫描仪扫描this文档中的特定条形码。这是标题为“串行仿真模式”的条形码。
此扫描程序 需要驱动程序进行串行端口仿真。我找到了实施说明和所需的驱动程序here(在“软件”选项卡下)。下载标题为“霍尼韦尔扫描与移动(HSM)USB串行驱动程序”的软件包。标题为“HSM USB串行驱动程序入门指南”的PDF有说明。
如果您不熟悉javax.comm API。请阅读Rick Proctor的this示例中的介绍 - 它告诉您从哪里获取jar以及放置文件的位置(javax.comm不是大多数java软件包的标准)。
我确信周围还有其他具有串口仿真的扫描仪型号(我不适用于霍尼韦尔)。
这是我的条形码阅读器类的一个稍微简化的版本:
package scanhandler;
import java.awt.AWTException;
import java.awt.Robot;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Enumeration;
import java.util.Properties;
import java.util.TooManyListenersException;
import javax.comm.CommPortIdentifier;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;
public class ScanHandler implements Runnable, SerialPortEventListener {
private static CommPortIdentifier myCommPortIdentifier;
private static Enumeration portList;
private static String TimeStamp;
private static String driverClass;
private static String connectionString;
private static String comPort;
private Connection myConnection;
private InputStream myInputStream;
private Robot myRobot;
private SerialPort mySerialPort;
private Thread myThread;
public ScanHandler() {
// open serial port
try {
TimeStamp = new java.util.Date().toString();
mySerialPort = (SerialPort) myCommPortIdentifier.open("ComControl", 2000);
//System.out.println(TimeStamp + ": " + myCommPortIdentifier.getName() + " opened for scanner input");
} catch (PortInUseException e) {
e.printStackTrace();
}
// get serial input stream
try {
myInputStream = mySerialPort.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
// add an event listener on the port
try {
mySerialPort.addEventListener(this);
} catch (TooManyListenersException e) {
e.printStackTrace();
}
mySerialPort.notifyOnDataAvailable(true);
// set up the serial port properties
try {
mySerialPort.setSerialPortParams(9600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
mySerialPort.setDTR(false);
mySerialPort.setRTS(false);
} catch (UnsupportedCommOperationException e) {
e.printStackTrace();
}
// make a robot to pass keyboard data
try {
myRobot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
// create the thread
myThread = new Thread(this);
myThread.start();
}
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
// on scan
public void serialEvent(SerialPortEvent event) {
if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
StringBuilder myStringBuilder = new StringBuilder();
int c;
try {
// append the scanned data onto a string builder
while ((c = myInputStream.read()) != 10){
if (c != 13) myStringBuilder.append((char) c);
}
// send to keyboard buffer if it the barcode doesn't start with '5'
if (myStringBuilder.charAt(0) != '5') {
for (int i = 0; i < myStringBuilder.length(); i++) {
myRobot.keyPress((int) myStringBuilder.charAt(i));
myRobot.keyRelease((int) myStringBuilder.charAt(i));
}
// here's the scanned barcode as a variable!
} else {
TimeStamp = new java.util.Date().toString();
System.out.println(TimeStamp + ": scanned input received:" + myStringBuilder.toString());
}
// close the input stream
myInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
// read ScanHandler properties
Properties myProperties = new Properties();
try {
myProperties.load(new FileInputStream("config.properties"));
comPort = myProperties.getProperty("ScanHandler.comPort");
} catch (IOException e) {
e.printStackTrace();
}
try {
// get our pre-defined COM port
myCommPortIdentifier = CommPortIdentifier.getPortIdentifier(comPort);
ScanHandler reader = new ScanHandler();
} catch (Exception e) {
TimeStamp = new java.util.Date().toString();
System.out.println(TimeStamp + ": " + comPort + " " + myCommPortIdentifier);
System.out.println(TimeStamp + ": msg1 - " + e);
}
};
}
答案 1 :(得分:9)
我使用的bardcode扫描仪就像一个键盘设备(它在操作系统中显示为HID键盘USB设备)。扫描条形码时,它会像输入一样发送代码。不需要特殊的API来与它进行交互。
答案 2 :(得分:6)
我知道这是一个很老的帖子,但搜索可以帮助你。
这可以作为Geronimo答案的补充:
对于Linux OS,无需在串行仿真模式下安装条形码扫描仪的驱动程序,因为本机支持USB串行端口。我们使用几种类型的霍尼韦尔扫描仪,所有这些都是开箱即用的,串行仿真中的扫描仪在我们的系统中显示为/ dev / ttyACM0,/ dev / ttyACM1等。
最近我们已经从javax.comm切换到jssc作为java库来连接串口。如果我记得很清楚,在Windows 7 64bit系统下,javax.comm库无法从串口读取或写入,而jssc也有非常相似的api。
答案 3 :(得分:0)
我意识到这是一个老问题,但我想我会为模拟条码扫描器输入添加一个额外的解决方案。此解决方案仅适用于将扫描仪输入模拟为键盘数据。
由于扫描仪通常只使用键盘输入,我们可以使用AutoHotkey脚本来模拟它。下面是一个脚本示例:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
; Barcode 1
; Hotkey = ctrl + alt + 1
^!1::
SendInput [BC200015]
Return
; Barcode 2
; Hotkey = ctrl + alt + 2
^!2::
SendInput [BC300013]
Return
只需将[BC300013]
和[BC200015]
替换为您预期的扫描仪输入。