如何区分C#中的多个输入设备

时间:2009-02-25 21:04:45

标签: c# barcode-scanner

我有一个条形码扫描仪(就像键盘一样),当然我的键盘也与计算机相连。该软件接受来自扫描仪和键盘的输入。我只需要接受扫描仪的输入。代码是用C#编写的。有没有办法从键盘“禁用”输入并只接受来自扫描仪的输入?

注意: 键盘是笔记本电脑的一部分...所以它不能拔掉。另外,我尝试使用以下代码     protected override Boolean ProcessDialogKey(System.Windows.Forms.Keys keyData)     {       返回true;     } 但随后忽略了键盘上的击键,条码扫描器输入也被忽略了。

我不能让扫描仪发送sentinal字符,因为扫描仪正被其他应用程序使用,添加一个sentinal字符流意味着修改其他代码。

此外,我无法使用计时方法来确定输入是否来自条形码扫描仪(如果它是一堆字符后跟一个暂停),因为扫描的条形码可能是单字符条形码。

是的,我正在从流中读取数据。

我正在尝试跟随文章:在WinForms中区分条形码扫描器和键盘。但是我有以下问题:

  1. 我收到错误由于其保护级别,NativeMethods无法访问。好像我需要输入一个dll;它是否正确?如果是这样,我该怎么办?
  2. 我应该使用哪个受保护的覆盖void WndProc(ref Message m)定义,文章中有两个实现?
  3. 收到与[SecurityPermission(SecurityAction.LinkDemand,Flags = SecurityPermissionFlag.UnmanagedCode)]相关的错误错误CS0246:找不到类型或命名空间名称'SecurityPermission'(您是否缺少using指令或程序集引用? )。如何解决此错误?
  4. 该行还有一个错误:if((来自hardwareId中的hardwareId,其中deviceName.Contains(hardwareId)选择hardwareId).Count()> 0)错误是错误CS1026 :)预期。
  5. 我是否应将文章中的所有代码放在一个名为BarcodeScannerListener.cs的.cs文件中?
  6. Nicholas Piasecki在http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/发布的关于C#解决方案源代码的后续问题:

    1. 我无法在VS 2005中打开解决方案,因此我下载了Visual C#2008 Express Edition,并运行了代码。但是,在连接条形码扫描仪并扫描条形码后,程序无法识别扫描。我在OnBarcodeScanned方法中设置了一个断点,但它从未被击中过。我确实更改了App.config,其中包含使用设备管理器获取的条形码扫描程序的ID。似乎有2个带有HID#Vid_0536& Pid_01c1的设备名称(当扫描仪连接时从设备管理器获得)。我不知道这是否导致扫描无法正常工作。在遍历deviceNames时,这里是我找到的设备列表(使用调试器):
    2. “\ ?? \ HID#Vid_0536&安培; Pid_01c1&安培; MI_01#9和; 25ca5370&安培0安培; 0000#{4d1e55b2-F16F-11CF-88cb-001111000030}”

      “\ ?? \ HID#Vid_0536&安培; Pid_01c1&安培; MI_00#9和; 38e10b9&安培0安培; 0000#{884b96c3-56ef-11D1-bc8c-00a0c91405dd}”

      “\ ?? \ HID#Vid_413c&安培; Pid_2101&安培; MI_00#8和; 1966e83d&安培0安培; 0000#{884b96c3-56ef-11D1-bc8c-00a0c91405dd}”

      “\ ?? \ HID#Vid_413c&安培; Pid_3012#7和; 960fae0&安培0安培; 0000#{378de44c-56ef-11D1-bc8c-00a0c91405dd}”
      “\ ?? \根#RDP_KBD#0000#{884b96c3-56ef-11D1-bc8c-00a0c91405dd}” “\ ?? \ ACPI#PNP0303#4和; 2f94427b&安培; 0#{884b96c3-56ef-11D1-bc8c-00a0c91405dd}” “\ ?? \根#RDP_MOU#0000#{378de44c-56ef-11D1-bc8c-00a0c91405dd}” “\ ?? \ ACPI#PNP0F13#4和; 2f94427b&安培; 0#{378de44c-56ef-11D1-bc8c-00a0c91405dd}”

      因此HID#Vid_0536& Pid_01c1有两个条目;这会导致扫描不起作用吗?

      好的,似乎我不得不想办法不依赖于扫描仪发送的ASCII 0x04字符......因为我的扫描仪不发送该字符。之后,条形码扫描事件被触发,并显示带有条形码的弹出窗口。谢谢尼古拉斯的帮助。

7 个答案:

答案 0 :(得分:16)

You could use the Raw Input API to distinguish between the keyboard and the scanner like I did recently.你连接了多少键盘或类似键盘的设备并不重要;在按键被映射到您通常在WM_INPUT事件中看到的与设备无关的虚拟密钥之前,您会看到KeyDown

更容易做其他人推荐的事情并配置扫描仪在条形码之前和之后发送哨兵字符。 (您通常通过扫描扫描仪用户手册背面的特殊条形码来完成此操作。)然后,您的主表单的KeyPreview事件可以观看那些滚动结束并吞下任何子控件的关键事件(如果它在中间)条形码阅读。或者,如果你想成为发烧友,你可以使用SetWindowsHookEx()的低级键盘钩来观察那些哨兵并将它们吞在那里(这样做的好处是,即使你的应用没有,你仍然可以获得该事件'有焦点)。

我无法改变条形码扫描仪上的哨兵值,所以我不得不走复杂的路线。绝对是痛苦的。如果可以,请保持简单!

-

7年后的更新:如果您的用例是从USB条形码扫描仪读取,则Windows 10在Windows.Devices.PointOfService.BarcodeScanner中为此内置版提供了一个友好的友好API。它是一个UWP / WinRT API,但您也可以从常规桌面应用程序中使用它;这就是我现在正在做的事情。以下是一些示例代码,直接来自我的应用程序,为您提供要点:

{
    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Windows;
    using Windows.Devices.Enumeration;
    using Windows.Devices.PointOfService;
    using Windows.Storage.Streams;
    using PosBarcodeScanner = Windows.Devices.PointOfService.BarcodeScanner;

    public class BarcodeScanner : IBarcodeScanner, IDisposable
    {
        private ClaimedBarcodeScanner scanner;

        public event EventHandler<BarcodeScannedEventArgs> BarcodeScanned;

        ~BarcodeScanner()
        {
            this.Dispose(false);
        }

        public bool Exists
        {
            get
            {
                return this.scanner != null;
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        public async Task StartAsync()
        {
            if (this.scanner == null)
            {
                var collection = await DeviceInformation.FindAllAsync(PosBarcodeScanner.GetDeviceSelector());
                if (collection != null && collection.Count > 0)
                {
                    var identity = collection.First().Id;
                    var device = await PosBarcodeScanner.FromIdAsync(identity);
                    if (device != null)
                    {
                        this.scanner = await device.ClaimScannerAsync();
                        if (this.scanner != null)
                        {
                            this.scanner.IsDecodeDataEnabled = true;
                            this.scanner.ReleaseDeviceRequested += WhenScannerReleaseDeviceRequested;
                            this.scanner.DataReceived += WhenScannerDataReceived;

                            await this.scanner.EnableAsync();
                        }
                    }
                }
            }
        }

        private void WhenScannerDataReceived(object sender, BarcodeScannerDataReceivedEventArgs args)
        {
            var data = args.Report.ScanDataLabel;

            using (var reader = DataReader.FromBuffer(data))
            {
                var text = reader.ReadString(data.Length);
                var bsea = new BarcodeScannedEventArgs(text);
                this.BarcodeScanned?.Invoke(this, bsea);
            }
        }

        private void WhenScannerReleaseDeviceRequested(object sender, ClaimedBarcodeScanner args)
        {
            args.RetainDevice();
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                this.scanner = null;
            }
        }
    }
}

当然,您需要一个支持USB HID POS的条形码扫描仪,而不仅仅是键盘楔形。如果你的扫描仪只是一个键盘楔子,我建议在eBay上买一个像二手Honeywell 4600G一样的东西,价格只要25美元。相信我,你的理智是值得的。

答案 1 :(得分:3)

我在类似情况下所做的是通过查看输入的速度来区分扫描和用户打字。

很多字符非常靠近,然后暂停是扫描。其他任何东西都是键盘输入。

我不确切地知道你的要求,所以也许这对你不起作用,但它是我得到的最好的:)

答案 2 :(得分:1)

这取决于您与设备交互的方式。无论如何,它不会是一个C#解决方案,它将是一些其他库。你在从流中读取数据吗?如果你只是按键,你可能无能为力。

答案 3 :(得分:1)

看看这个: http://nate.dynalias.net/dev/keyboardredirector.rails 不可用任何东西)效果很好!

指定要阻止的键盘和键,它就像一个魅力!

另请看一下:http://www.oblita.com/interception.html 你可以为它创建一个C#包装器 - 它也像魅力一样......

答案 4 :(得分:1)

我知道这是一个老线程,通过搜索WIN10中的条形码扫描找到它。 只需几个笔记,以防有人需要它。

霍尼韦尔的这些扫描仪有几个USB接口。 一个是键盘+ Hid销售点(复合设备)。 还有CDC-ACM(ComPort仿真)和Hid销售点(单独)+更多。

默认情况下,扫描仪会显示一个序列号,因此主机可以区分许多设备(我曾经连接过+20)。有一个命令可以禁用序列号!

新型号在这方面表现相同。 如果你想看到它,请尝试我的终端程序yat3(免费my site)。 它可以打开上面提到的所有接口,并为这些设备量身定制。

使用键盘界面的一句话:
只能将它们作为最后的手段。当涉及到异国情调的角色时,它们很慢,不太可靠。唯一的好处是,如果要将数据输入现有应用程序。如果您仍然编码,那么从ComPort / HidPos-Device读取更容易。

答案 5 :(得分:0)

我认为您可以通过DirectX API区分多个键盘,或者如果不起作用,可以通过原始输入API区分。

答案 6 :(得分:0)

我已经成功完成了你们在这里寻找的东西。我有一个应用程序从Honeywell / Metrologic条形码扫描仪接收所有条形码字符数据。系统上没有其他应用程序从扫描仪接收数据,键盘继续正常运行。

我的应用程序使用原始输入和可怕的低级键盘挂钩系统的组合。与此处写的相反,我发现在调用键盘钩子函数之前接收到wm_input消息。我处理wm_input消息的代码基本上设置了一个布尔变量来指定接收到的字符是否来自扫描器。在处理wm_input之后立即调用的键盘钩子函数会吞下扫描器的伪键盘数据,从而阻止其他应用程序接收数据。

键盘挂钩功能必须放在dll中,因为您要拦截所有系统键盘消息。此外,必须使用内存映射文件来使wm_input处理代码与dll通信。