问题描述
我有一个条形码扫描仪(起着键盘的作用),当然,我的键盘也挂在计算机上了.该软件正在接受来自扫描仪和键盘的输入.我只需要接受扫描仪的输入.该代码是用C#编写的.有没有一种方法可以禁用"来自键盘的输入,而仅接受来自扫描仪的输入?
I have a barcode scanner (which acts like a keyboard) and of course I have a keyboard too hooked up to a computer. The software is accepting input from both the scanner and the keyboard. I need to accept only the scanner's input. The code is written in C#. Is there a way to "disable" input from the keyboard and only accept input from the scanner?
注意:键盘是笔记本电脑的一部分...因此无法拔下电源.另外,我试着把下面的代码 受保护的重写Boolean ProcessDialogKey(System.Windows.Forms.Keys keyData) { 返回true; }但是,除了忽略键盘上的击键之外,条形码扫描仪的输入也将被忽略.
Note:Keyboard is part of a laptop...so it cannot be unplugged. Also, I tried putting the following code protected override Boolean ProcessDialogKey(System.Windows.Forms.Keys keyData) { return true; }But then along with ignoring the keystrokes from the keyboard, the barcode scanner input is also ignored.
我无法让扫描程序发送警句字符,因为该扫描程序正在被其他应用程序使用,并且添加警句字符流将意味着修改其他代码.
I cannot have the scanner send sentinal characters as, the scanner is being used by other applications and adding a sentinal character stream would mean modifying other code.
而且,由于扫描的条形码可能是单字符条形码,因此我无法使用计时方法来确定输入是否来自条形码扫描仪(如果输入的是一堆字符,然后是暂停).
Also, I cannot use the timing method of determining if the input came from a barcode scanner (if its a bunch of characters followed by a pause) since the barcodes scanned could potentially be single character barcodes.
是的,我正在从流中读取数据.
Yes, I am reading data from a stream.
我正在尝试遵循以下文章:从WinForms中的键盘区分条形码扫描仪.但是我有以下问题:
I am trying to follow along with the article: Distinguishing Barcode Scanners from the Keyboard in WinForms. However I have the following questions:
- 我收到一个错误,因为其保护级别,NativeMethods无法访问.好像我需要导入一个dll.这样对吗?如果是这样,我该怎么办?
- 我应该使用哪个受保护的重写void WndProc(ref Message m)定义,本文中有两种实现?
- 正在获取与[SecurityPermission(SecurityAction.LinkDemand,Flags = SecurityPermissionFlag.UnmanagedCode)]相关的错误CS0246:找不到类型或名称空间名称'SecurityPermission'(您是否缺少using指令或程序集引用? ).如何解决此错误?
- 在包含以下内容的行上也存在错误:if((从hardwareIds中的hardwareId,其中deviceName.Contains(hardwareId)选择hardwareId).Count()> 0)错误是错误CS1026:).
- 我应该将文章中的所有代码放在一个名为BarcodeScannerListener.cs的.cs文件中吗?
Nicholas Piasecki在 http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/:
Followup questions about C# solution source code posted by Nicholas Piasecki on http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/:
- 我无法在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_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_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_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-00a0c91405dd}""\ ?? \ ACPI#PNP0303#4& 2f94427b& 0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}""\ ?? \ Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}""\ ?? \ ACPI#PNP0F13#4& 2f94427b& 0#{378de44c-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-00a0c91405dd}""\??\ACPI#PNP0303#4&2f94427b&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}""\??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}""\??\ACPI#PNP0F13#4&2f94427b&0#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
因此,对于HID#Vid_0536& Pid_01c1,有2个条目;会导致扫描无法正常工作吗?
So there are 2 entries for HID#Vid_0536&Pid_01c1; could that be causing the scanning not to work?
好的,所以看来我不得不找出一种不依赖于扫描仪发送的ASCII 0x04字符的方法...因为我的扫描仪不发送该字符.之后,将触发条形码扫描事件,并显示带有条形码的弹出窗口.因此,感谢尼古拉斯(Nicholas)的帮助.
OK so it seems that I had to figure out a way to not depend on the ASCII 0x04 character being sent by the scanner...since my scanner does not send that character. After that, the barcode scanned event is fired and the popup with the barcode is shown. So thanks Nicholas for your help.
推荐答案
您可以像我最近一样使用Raw Input API区分键盘和扫描仪.无论您连接了多少个键盘或类似键盘的设备;在将击键映射到通常在KeyDown
事件中看到的与设备无关的虚拟键之前,您会看到一个WM_INPUT
.
You could use the Raw Input API to distinguish between the keyboard and the scanner like I did recently. It doesn't matter how many keyboard or keyboard-like devices you have hooked up; you will see a WM_INPUT
before the keystroke is mapped to a device-independent virtual key that you typically see in a KeyDown
event.
执行其他人推荐的操作更容易,并且将扫描仪配置为在条形码之前和之后发送哨兵字符. (通常,您可以通过扫描扫描仪用户手册背面的特殊条形码来进行此操作.)然后,主窗体的KeyPreview
事件可以监视那些滚动结束并吞下任何子控件的关键事件(如果该控件位于条形码中间)读.或者,如果您想成为一名发烧友,则可以使用带有SetWindowsHookEx()
的低级键盘挂钩来监视这些哨兵并将其吞入那里(这样做的好处是,即使您的应用程序没有该哨兵,您仍然可以得到该事件焦点).
Far easier is to do what others have recommended and configure the scanner to send sentinel characters before and after the barcode. (You usually do this by scanning special barcodes in the back of the scanner's user manual.) Then, your main form's KeyPreview
event can watch those roll end and swallow the key events for any child control if it's in the middle of a barcode read. Or, if you wanted to be fancier, you could use a low-level keyboard hook with SetWindowsHookEx()
to watch for those sentinels and swallow them there (advantage of this is you could still get the event even if your app didn't have focus).
除其他外,我无法更改条形码扫描器上的哨兵值,因此我不得不走复杂的路线.绝对是痛苦的.如果可以的话,请保持简单!
I couldn't change the sentinel values on our barcode scanners among other things so I had to go the complicated route. Was definitely painful. Keep it simple if you can!
-
七年后的更新::如果您的用例是从USB条码扫描仪读取的,则Windows 10在Windows.Devices.PointOfService.BarcodeScanner
中内置了一个很好的友好API.它是UWP/WinRT API,但您也可以从常规桌面应用程序中使用它.那就是我现在正在做的.这是一些示例代码,直接从我的应用程序中获取要点:
Your update, seven years later: If your use case is reading from a USB barcode scanner, Windows 10 has a nice, friendly API for this built-in in Windows.Devices.PointOfService.BarcodeScanner
. It's a UWP/WinRT API, but you can use it from a regular desktop app as well; that's what I'm doing now. Here's some example code for it, straight from my app, to give you the gist:
{
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且不仅仅是键盘楔的条形码扫描仪.如果您的扫描仪只是一个键盘楔子,我建议您以25美元的价格在eBay上购买二手Honeywell 4600G.相信我,您的理智是值得的.
Granted, you'll need a barcode scanner that supports the USB HID POS and isn't just a keyboard wedge. If your scanner is just a keyboard wedge, I recommend picking up something like a used Honeywell 4600G off eBay for like $25. Trust me, your sanity will be worth it.
这篇关于如何在C#中区分多个输入设备的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!