26

我有一个条形码扫描仪(它就像一个键盘),当然我的键盘也连接到了电脑上。该软件正在接受来自扫描仪和键盘的输入。我只需要接受扫描仪的输入。代码是用 C# 编写的。有没有办法“禁用”键盘输入并且只接受来自扫描仪的输入?

注意:键盘是笔记本电脑的一部分……因此无法拔下。另外,我尝试将以下代码保护覆盖 Boolean ProcessDialogKey(System.Windows.Forms.Keys keyData) { return true; 但是随着忽略键盘的击键,条形码扫描仪的输入也被忽略了。

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

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

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

我正在尝试阅读文章:在 WinForms 中将条码扫描仪与键盘区分开来。但是我有以下问题:

  1. 我收到一个错误 NativeMethods 由于其保护级别而无法访问。好像我需要导入一个dll;它是否正确?如果是这样,我该怎么做?
  2. 我应该使用哪个受保护的覆盖 void WndProc(ref Message m) 定义,文章中有两种实现?
  3. 收到与 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] 相关的错误错误 CS0246:找不到类型或命名空间名称“SecurityPermission”(您是否缺少 using 指令或程序集引用?)。如何解决此错误?
  4. 包含以下内容的行上还有一个错误:if ((from hardwareIds in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0) Error is error CS1026: ) 预期。
  5. 我应该将文章中的所有代码放在一个名为 BarcodeScannerListener.cs 的 .cs 文件中吗?

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 方法中设置了一个断点,但它从未被击中。我确实使用设备管理器获得的条形码扫描仪的 ID 更改了 App.config。似乎有 2 个带有 HID#Vid_0536&Pid_01c1 的设备名称(连接扫描仪时从设备管理器中获得)。我不知道这是否导致扫描不起作用。遍历 deviceNames 时,这里是我找到的设备列表(使用调试器):

“\??\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}"
"\??\Root#RDP_KBD#0000#{884b96c3-56ef-11d1-bc8c-00a?0c914dd50? \ACPI#PNP0303#4&2f94427b&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}" "\??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}" "\??\ACPI#PNP0F #4&2f94427b&0#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"

所以 HID#Vid_0536&Pid_01c1 有 2 个条目;这会导致扫描不起作用吗?

好的,看来我必须想办法不依赖扫描仪发送的 ASCII 0x04 字符……因为我的扫描仪不发送该字符。之后,触发条形码扫描事件并显示带有条形码的弹出窗口。所以感谢尼古拉斯的帮助。

4

7 回答 7

20

您可以像我最近所做的那样使用原始输入 API 来区分键盘和扫描仪。您连接了多少键盘或类似键盘的设备并不重要。WM_INPUT在击键映射到通常在KeyDown事件中看到的与设备无关的虚拟键之前,您会看到一个。

更容易的是按照其他人的建议进行操作,并将扫描仪配置为在条形码之前和之后发送标记字符。(您通常通过扫描扫描仪用户手册背面的特殊条形码来做到这一点。)然后,您的主窗体的KeyPreview事件可以观察那些滚动结束并吞下任何子控件的关键事件(如果它处于条形码读取的中间)。或者,如果你想变得更漂亮,你可以使用一个低级的键盘钩子SetWindowsHookEx()来监视那些哨兵并将它们吞下(这样做的好处是即使你的应用程序没有焦点,你仍然可以获得事件)。

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

--

七年后您的更新:如果您的用例是从 USB 条形码扫描仪读取,Windows 10 有一个很好、友好的 API 用于这个内置的Windows.Devices.PointOfService.BarcodeScanner. 它是一个 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 上以 25 美元的价格购买二手霍尼韦尔 4600G 之类的东西。相信我,你的理智是值得的。

于 2009-02-26T06:13:54.820 回答
3

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

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

我不确切知道您的要求,所以也许这对您不起作用,但这是我所拥有的最好的:)

于 2009-02-25T21:21:51.197 回答
1

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

于 2009-02-25T21:10:37.513 回答
1

看看这个:http : //nate.dynalias.net/dev/keyboardredirector.rails(不再可用)效果很好!

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

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

于 2013-05-15T12:01:17.097 回答
1

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

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

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

较新的模型在这方面表现相同。如果你想现场观看,试试我的终端程序 yat3(在我的网站上免费)。它可以打开上面提到的所有接口,并且是为此类设备量身定制的。

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

于 2015-10-29T18:30:54.353 回答
0

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

于 2009-02-25T23:24:38.593 回答
0

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

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

键盘钩子函数必须放在一个 dll 中,因为您想拦截所有系统键盘消息。此外,内存映射文件必须用于 wm_input 处理代码与 dll 通信。

于 2011-09-01T18:47:46.060 回答