Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.9k views
in Technique[技术] by (71.8m points)

barcode scanner - How to distinguish between multiple input devices in 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?

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.

I am trying to follow along with the article: Distinguishing Barcode Scanners from the Keyboard in WinForms. However I have the following questions:

  1. I get an error NativeMethods is inaccessible due to its protection level. It seems as though I need to import a dll; is this correct? If so, how do I do it?
  2. Which protected override void WndProc(ref Message m) definition should I use, there are two implementations in the article?
  3. Am getting an error related to [SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] error CS0246: The type or namespace name 'SecurityPermission' could not be found (are you missing a using directive or an assembly reference?). How do I resolve this error?
  4. There is also an error on the line containing: if ((from hardwareId in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0) Error is error CS1026: ) expected.
  5. Should I be placing all the code in the article in one .cs file called BarcodeScannerListener.cs?

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/:

  1. I was not able to open the solution in VS 2005, so I downloaded Visual C# 2008 Express Edition, and the code ran. However, after hooking up my barcode scanner and scanning a barcode, the program did not recognize the scan. I put a break point in OnBarcodeScanned method but it never got hit. I did change the App.config with the id of my Barcode scanner obtained using Device Manager. There seems to be 2 deviceNames with HID#Vid_0536&Pid_01c1 (which is obtained from Device Manager when the scanner is hooked up). I don't know if this is causing the scanning not to work. When iterating over the deviceNames, here is the list of devices I found (using the debugger):

"??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-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}"

So there are 2 entries for HID#Vid_0536&Pid_01c1; could that be causing the scanning not to work?

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.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

2 Answers

0 votes
by (71.8m points)

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.

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!

--

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;
            }
        }
    }
}

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
0 votes
by (100 points)

To make a barcode scanner distinguish between multiple input devices in C#, you can use the System.Management namespace to retrieve a list of all connected USB devices and their properties, including the device ID.

Here's an example code snippet that demonstrates how to distinguish between multiple input devices:

using System.Management;

// Retrieve a list of all USB devices

ManagementObjectCollection collection;

using (var searcher = new ManagementObjectSearcher(@"Select * From Win32_USBHub"))

    collection = searcher.Get();


// Loop through each USB device and check if it's a barcode scanner

foreach (var device in collection)

{

    // Get the device ID

    var deviceId = (string)device.GetPropertyValue("DeviceID");


    // Check if the device ID contains the string "VID_xxxx&PID_xxxx",

    // which is a unique identifier for a barcode scanner

    if (deviceId.Contains("VID_xxxx&PID_xxxx"))

    {

        // This is a barcode scanner, do something with it

        // For example, open a serial port and start reading data

    }

}
In the code above, replace "VID_xxxx&PID_xxxx" with the actual Vendor ID (VID) and Product ID (PID) of your barcode scanner. You can find these values by looking up your scanner's specifications or by using a tool like USBDeview to inspect the device properties.
By looping through each USB device and checking its properties, you can identify which input device is a barcode scanner and take appropriate actions.
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...