29

好先生,我有一个问题。我目前正在从事的学校 Java 项目要求我将 USB 条形码扫描仪作为外部输入连接到我的笔记本电脑。我实际上并没有购买 USB 扫描仪,因为它对学生来说相当昂贵。所以我必须收集证据证明这个扫描仪可以和我的程序一起工作。

扫描仪是否能够读取条形码(可能是在线打印的)并将其存储到变量中?如果是这样,按下扫描仪的动作事件是否会像键盘按键一样被读取?如果是这样,代码行会是什么样子?

此外,如果您可以发布您对条码扫描仪的体验,或提供任何建议,例如购买哪种扫描仪,那将有很大帮助。干杯!

4

4 回答 4

34

我最近不得不实现一个扫描系统来与 java 交互。

我使用的是Honeywell Voyager MS9540 USB 条码扫描仪。

默认情况下,扫描仪直接将数据作为键盘输入发送 - 无需驱动程序。

但是很容易让这个模型直接与 java 交互,而不是使用键盘钩子(使用条形码作为 java 中的变量,正如你所提到的)。

该模型具有模拟串行端口的设置,然后您可以使用 javax.comm 包读取扫描的数据。对我来说,这比获取条形码数据的键盘挂钩好得多,因为程序在能够解释扫描之前不需要焦点(我不想创建全局键盘挂钩)。

我的 java 程序从指定的串口读取所有输入并将条形码写入数据库。我还设置了程序以将任何无法识别的条形码扫描传递到键盘(我的应用程序未创建的任何条形码 - 我在我的条形码上使用了独特的签名),这样它就可以作为任何其他可能的应用程序的常规条形码扫描仪从键盘读取条形码。

您可能可以通过执行一些密集的 JNI 编码直接从任何 USB 扫描仪读取数据(没有此模型具有的串行端口仿真),但我不准备花时间编写本机代码。

要为串行端口仿真配置此特定型号,您只需使用要配置的扫描仪扫描文档中的特定条形码。它是标题为“串行仿真模式”的条形码。

此扫描仪确实需要用于串行端口仿真的驱动程序。我在这里找到了实施说明和所需的驱动程序(在“软件”选项卡下)。下载标题为“Honeywell Scanning and Mobility (HSM) USB Serial Driver”的软件包。标题为“HSM USB 串行驱动程序入门指南”的 PDF 包含说明。

如果您不熟悉 javax.comm API。请阅读 Rick Proctor 在示例中的介绍 - 它告诉您从哪里获取 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);
        }
    };    
}
于 2011-12-23T22:42:05.767 回答
11

我使用的条形码扫描仪就像一个键盘设备(它在操作系统中显示为 HID 键盘 USB 设备)。当条形码被扫描时,它会像输入一样发送代码。无需特殊的 API 即可与之交互。

于 2011-11-16T04:51:15.320 回答
8

I know it's quite old thread but search can get you there.

This can be treated as an addition to Geronimo's answer:

For Linux OS there is no need to install drivers for barcode scanners in serial emulation mode as there is native support for USB serial ports. We use several types of Honeywell scanners and all of them work out of the box, those scanners in serial emulation shows in our systems as /dev/ttyACM0, /dev/ttyACM1 etc.

Recently we have switched from javax.comm to jssc as a java library to interface serial ports. If I remember well, under Windows 7 64bit system javax.comm library cannot read or write from/to serial port and jssc has very similar api.

于 2015-01-21T06:51:57.440 回答
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]为您预期的扫描仪输入。

于 2015-08-19T20:46:38.753 回答