读取USB HID吧code扫描仪输入不知道VID和放大器; PID放大器、扫描仪、HID、USB

2023-09-08 00:42:25 作者:放假过得像放屁一样快

我想开发与设备无关的库吧code扫描仪,它已在Windows环境中工作。

I'm trying to develop device independent library for barcode scanners, it has to be working in windows environment.

我已经做了一些这方面的研究,AFAIK最该问题的解决方案都是根据具体设备的VID和放大器; PID(RawInput @滤镜通过VID和放大器; PID字符串),在我的情况,这是不能接受的,因为我中号试图建立一个独立于设备的解决方案,这将与任何USB棒code扫描仪工作。

I've done some research in this field, afaik most of the solutions of this problem are depending on specific device VID&PID (RawInput @ filter by vid&pid string), in my situation this is inacceptable, because i'm trying to develop a device independent solution, which will be working with any USB-barcode scanner.

其实这个东西是相当具有挑战性的,对我来说ATLEAST,这里有确切的requiriments。我也不能要求用户热插拔设备(在这种情况下,我可能已经只是检测插入设备并提取其VID / PID)。我也不能使用VID和放大器;设备的PID数据库。总的来说,我不能用VID和放大器; PID在所有实际。

Actually this thing is quite challenging, for me atleast, here are exact requiriments. Also i can't ask user to hot-plug device (in that case i could've just detect plugged device and extract it vid/pid). Also i can't use VID&PID database of devices. In general i can't use vid&pid at all actually.

此外,我不能以任何方式reprogramm吧code扫描仪,除非它是从我的PROGRAMM做(也许我可以给些吧codescanner特定的IOCTL这将使回答我?)。

Also i can't in any way reprogramm barcode scanner, unless it's done from my programm (maybe i can send some barcodescanner-specific IOCTLs which will make it answer to me?).

目前我要去使用这一问题提出的解决方案: Reading使用USB棒code扫描仪以及忽略键盘输入数据,而扫描仪产品ID和供应商ID是不知道酒吧code

Currently i'm going to use solution proposed in this question: Reading a barcode using a USB barcode scanner along with ignoring keyboard data input while scanner product id and vendor id are not known

此外,我所看到的商业库(这是offcourse来没有任何来源和有关它是如何实现的任何信息,但考虑到他们在更新日志have'd一些单词性能比较计数器,我猜他们使用的解决方案在上面的链接),它实现了这一功能,但它不能在x64系统工作。也许可能是因为凌乱code或东阳它可能使用某种过滤器(迷你)驱动程序。它是加密的,我不能再分发。

Also i have seen commercial library (which is offcourse comes without any sources and any info about how it's implemented, but considering they have'd some word "Perfomance counter" in their changelogs, i guess they used solution in the link above), which implements this functionality, but it doesn't work in x64 systems. Probably either because of messy code or beacause it probably uses some kind of filter (mini) driver. It's crypted and i can't redistribute it.

我确切的问题是: 有没有什么办法来确定这HID键盘其实不是键盘,而是一个吧code扫描仪?我已经看到了在Win 7 64位系统,它连接,酒吧code扫描仪,而不是键盘(这是一个系统错误,或排序)。

My exact question is: Is there any way to determine that this HID keyboard is in fact not a keyboard, but a barcode scanner? I've seen on Win 7 x64 that it connects as Barcode scanner, not keyboard (this was a system bug, or sort of).

正是我现在做的:

将RID_INPUTSINK读取输入。 在区分所有输入的VID和放大器;设备的PID 将所有输入到独立的缓冲区和缓冲区收集吧codeS时VK_ENTER显示了缓冲区。

我目前要做的事情:

在读取输入的RID_INPUTSINK 启动计时器特定的设备,如果下一个符号是VK_ENTER - 停止定时器 如果定时器超过50毫秒的限制 - 关闭,并删除所有其它设备的输入。 如果设备将成功读取字符序列从第一符号VK_ENTER - 萃取设备VID和放大器; PID /手柄和更方便的方式使用它(无timering)。

我在C ++ developng它,纯WinAPI的,这将是一个DLL库,并得到了在Windows XP,Vista中,7,对x32-86和x32-64架构8工作。

I'm developng it on C++, pure WinAPI, it will be a DLL library, and got to work in Windows XP, Vista, 7, 8 on x32-86 and x32-64 architectures.

更新0: 刚刚发现吧code扫描仪有自己的usagePage和使用的USB规格: http://www.usb.org/developers/devclass_docs/pos1_02.pdf

UPDATE 0: Just found that barcode scanner have their own usagePage and usage in USB specs: http://www.usb.org/developers/devclass_docs/pos1_02.pdf

根据这份文件的USB吧code扫描仪具有UsagePage 0x8C和使用0X02。不幸的是我已经用它作为RAWINPUTDEVICE.dwUsage和RAWINPUTDEVICE.dwUsagePage失败。可能是因为系统上安装它是在它上面的USB键盘驱动程序,并在用户模式下它是真正的USB键盘没有区别。也许这些值都在内核模式环境中使用(其中一个选项是开发的HID过滤器驱动程序)。

According to this document USB Barcode scanner have UsagePage 0x8C and Usage 0x02. Unfortunately i've failed using it as RAWINPUTDEVICE.dwUsage and RAWINPUTDEVICE.dwUsagePage. Probably because system install it's usb keyboard driver on top of it and in user mode it is indistinguishable from real usb keyboard. Probably those values are usable in kernelmode environment (one of the options is to develop hid filter driver).

推荐答案

这不回答你的具体问题,但无论如何...

This does not answer your specific question, but anyway...

在一年多以前,我实现了在更恶劣的环境下吧code阅读器支持。它是在纯Java的一个报告的一个应用与关联后勤数据(跨平台富客户端,主要是在Windows上)。 我发现你说的话有关键盘的驱动,美元实际USB设备p $ pvents区别在用户模式下,至少在第一眼相同。没有与自己的驱动程序和先进的功能,这将允许某种区别,更昂贵的设备。 所有的酒吧code读者我在那个环境中遇到的是可见的键盘和用于只需填写一个SAP表单字段并按下回车键,这是一种常见的情况。该终端可使用魔棒codeS'或其他制造商特定的方法是可配置的。

More than a year ago, I implemented barcode reader support under even more adverse circumstances. It was for a reporting applicaton with association to logistical data in pure Java (cross platform rich client, primarily on Windows). I found out the same you're saying about the keyboard driver, which prevents distinction of actual USB devices in user mode, at least at the first glance. There are more expensive devices with own drivers and advanced features, which would allow some sort of distinction. All barcode readers I encountered in that environment were visible as keyboards and used to simply fill an SAP form field and hit the enter key, which is a common case. The termination may be configurable using 'magic barcodes' or another manufacturer specific method.

因此​​,决定是反对任何JNI基础,平台的具体实施。 相反,我还实施了拦截式的方法(对你的扩展版),通过在一定的摇摆评估通用keyoard输入/采用这些标准AWT形式:

So the decision was against any JNI based, platform specific implementation. Instead, I implemented also an interception-like approach (extended version of yours) by evaluating generic keyoard input within certain Swing/AWT forms using these criteria:

由前两个字符(开始/暂停后)确定击键次数 抖动(频率/变化率) 设置有效字符的 终止换行符。

输入得到一个缓冲,直到消耗不符合标准的机器生成的输入,或验证已通过,在那里吧code监听器将被通报。在这两种情况下,输入可以转发,如果没有别的事。

The input gets consumed by a buffer until the criteria for machine generated input aren't met, or the validation has been passed, where barcode listeners will be notified. In either situation, the input can be forwarded as if nothing else happened.

这已经被证明是非常准确的,因为一个人的,它是几乎不可能进入酒吧code读者率的有效序列(几乎)零抖动。

This has proven to be very accurate, since for a human, it's all but impossible to enter a valid sequence at the barcode reader's rate with (almost) zero jitter.

编辑:

刚挖出来的Java源代码;我可以给你实施的早期版本的code以上,例如,(没有担保,也可以考虑实施CR):

Just dug out the Java source; I can give you the code of an early revision of the implementation above as an example (no warranty, also consider to implement CR):

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A {@link KeyListener} implementation for barcode readers. This implementation
 * checks for input rate and jitter to distinguish human and scanner
 * input sequences by 'precision'. A barcode input sequence from a scanner is
 * typically terminated with a line break.
 * 
 * @author Me
 */
public abstract class AbstractBarcodeInputListener implements KeyListener {
    public static final int DEFAULT_MIN_PAUSE = 300;// [ms]
    public static final int DEFAULT_MAX_TIME_DELTA = 200;// [ms]
    public static final int DEFAULT_MAX_TIME_JITTER = 50;// [ms]

    public static Integer parseInt(Pattern pattern, int group, String line) {
        final Matcher matcher = pattern.matcher(line);
        if (matcher.matches())
            return Integer.parseInt(matcher.group(group));
        return null;
    }

    private String input;

    private final long minPause;
    private long maxTimeDelta;
    private final long maxTimeJitter;

    private long firstTime;
    private long firstTimeDelta;
    private long lastTimeDelta;
    private long lastTime;

    public AbstractBarcodeInputListener(long maxTimeDelta, long maxTimeJitter) {
        this.input = new String();

        this.minPause = AbstractBarcodeInputListener.DEFAULT_MIN_PAUSE;
        this.maxTimeDelta = maxTimeDelta;
        this.maxTimeJitter = maxTimeJitter;

        this.firstTime = 0;
        this.firstTimeDelta = 0;
        this.lastTimeDelta = 0;
        this.lastTime = 0;
    }

    public AbstractBarcodeInputListener() {
        this(AbstractBarcodeInputListener.DEFAULT_MAX_TIME_DELTA,
                AbstractBarcodeInputListener.DEFAULT_MAX_TIME_JITTER);
    }

    private boolean checkTiming(KeyEvent e) {
        final int inputLength = this.input.length();
        final long time = e.getWhen();
        long timeDelta = time - this.lastTime;
        long absJitter = 0;
        long relJitter = 0;

        boolean inputOK = true;

        switch (inputLength) {
        case 0: // pause check
            inputOK &= (timeDelta > this.minPause);
            this.firstTime = time;
            this.firstTimeDelta = timeDelta = 0;
            break;
        case 1: // delta check
            this.firstTimeDelta = timeDelta;
            inputOK &= (timeDelta < this.maxTimeDelta);
            break;
        default:// jitter check & delta check
            absJitter = Math.abs(timeDelta - this.firstTimeDelta);
            relJitter = Math.abs(timeDelta - this.lastTimeDelta);
            inputOK &= (absJitter < this.maxTimeJitter);
            inputOK &= (relJitter < this.maxTimeJitter);
            inputOK &= (timeDelta < this.maxTimeDelta);
            break;
        }

        this.lastTime = time;
        this.lastTimeDelta = timeDelta;

        return inputOK;
    }

    @Override
    public void keyPressed(KeyEvent e) {
    }

    private void clearInput() {
        this.input = new String();
    }

    private void commitInput(KeyEvent e) {
        final String code = this.input;
        if (!code.isEmpty()) {
            final long avgIntervalTime = e.getWhen() - this.firstTime;
            this.maxTimeDelta = (avgIntervalTime * 15) / 10;
            this.clearInput();
            this.codeRead(code);
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }

    @Override
    public void keyTyped(KeyEvent e) {
        if (this.checkTiming(e)) {
            final char c = e.getKeyChar();
            switch (c) {
            case '\b':
                this.clearInput();
                break;
            case '\n':
                this.commitInput(e);
                break;
            default:
                this.input += c;
                break;
            }
        } else {
            this.clearInput();
        }
    }

    public abstract void codeRead(String line);
}