How to Distinguish Between Multiple Input Devices in C#

How to distinguish between multiple input devices in C#

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.

How to distinguish Multiple Keyboards in Delphi?

@Dian, you can use the RegisterRawInputDevices function to register the keyboards and monitor the WM_INPUT message to determine the device (keyboard) where the input came from.

check theses links for more info

  • Using Raw Input from C# to handle multiple keyboards
  • WM_INPUT Message

distinguish connected keyboards on windows?

It's possible but pretty difficult - you'd have to have a device driver whose INF file specifically targets one of the keyboards (the driver chosen by PNP will always be the most specific match to the hardware), then write a HID driver that essentially replicates kbdhid.sys but instead of directly relaying the keys pressed, relays your programmed keys (or an easier solution would to have it always relay "weird" key combinations like Win+π, which you could then have a user-mode app watch for it via RegisterHotkey)

Check out this page on WDF to get started.

Differentiate between two keyboards in a KeyboardHook

To distinguish between input devices, you may probably need to use Raw Input API

Here is a detailed example

UPDATE: The above link seems to be down. But here is a similar question answered by the blogger who provided above example.

C# - Multithreading using Multiple Input Devices

According to the article you link

Each window whose handle is associated with a registered device as described in the previous section must therefore check the messages it receives and take appropriate action when a WM_INPUT one is detected.

Windows message processing is a form of cooperative multi-tasking. A new message cannot be processed from the message queue until the current one returns from processing.

If your code is responding to WM_INPUT by doing whatever it needs to in the database, no other events can process until that is done.

You can solve this by using a producer/consumer pattern. Have your code that handles WM_INPUT put information necessary for processing into a structure such as a BlockingCollection, and have a separate thread read from the BlockingCollection and do the work.

Depending on your needs, you might have one BlockingCollection per raw input device, or just a single one. If the latter, part of the information put into the BlockingCollection would probably be an identifier of the raw device that generated the input.



Related Topics



Leave a reply



Submit