I am in the process of integrating support for USB barcode scanners into a WPF application, but I have hit a snag.
Currently I am successfully identifying and capturing input with the help of this article.
The issue that I am facing is that although I am successfully identifying and routing input from the scanner device, I am unable to block the input events for further processing (e.g. if a textbox control on my application has input focus, the input from the scanner will be written to it).
I have tried two methods of capturing input:
var wndSourceHandle = HwndSource.FromHwnd(new WindowInteropHelper(
_wndEventSource = value).Handle);
wndSourceHandle.AddHook(this.WndProc);
WndProc definition:
private IntPtr WndProc(IntPtr hwnd, int iMessage, IntPtr wParam, IntPtr lParam, ref bool bisHandled)
{
if (iMessage == Win32.WM_INPUT)
{
var result = ProcessRawInput(lParam);
bisHandled = result != null && result.Value;
return IntPtr.Zero;
}
return IntPtr.Zero;
}
As well as:
ComponentDispatcher.ThreadFilterMessage += (ref MSG msg, ref bool handled) =>
{
if (msg.message == Win32.WM_INPUT)
{
var result = ProcessRawInput(msg.lParam);
handled = result != null && result.Value;
return;
}
handled = false;
};
The ProcessRawInput method returns true if the source of the input is the barcode scanner, false otherwise.
After a bit more research I found a solution applicable to WinForms here. I was able to modify it for WPF as follows:
ComponentDispatcher.ThreadFilterMessage += (ref MSG msg, ref bool handled) =>
{
if (msg.message == Win32.WM_INPUT)
{
var result = ProcessRawInput(msg.lParam);
this.m_bIgnoreNextKeyDownMessage = result != null && result.Value;
return;
}
if (msg.message == Win32.WM_KEYDOWN && this.m_bIgnoreNextKeyDownMessage)
{
handled = true;
}
this.m_bIgnoreNextKeyDownMessage = false;
};
This solution basically marks the first WM_KEYDOWN message after a barcode WM_INPUT message as "handled". I am not sure if this is the only/best/safest solution, but it looks like it does the trick.
Update:
With the above solution I still found that every now and again one random character from the scanned barcode would slip through to a focussed textbox - I am not sure why this is the case - could be a timing issue with the keyboard events as they are passed through the message handler. Another solution for checking whether the WM_KEYDOWN message should be ignored:
if (msg.message == Win32.WM_KEYDOWN && !String.IsNullOrEmpty(this.m_strKeyInput))
{
handled = true;
}
The buffer m_strKeyInput contains the current scanned barcode value - this buffer is empty when no barcode is available, built up one character at a time as the barcode scanner pushes down the barcode - and then emptied once a custom BarcodeScanned event is generated. The only drawback of this solution that I can think of is that all keyboards will stop functioning for the few milliseconds the barcode is being pushed from the scanner - which is acceptable for my scenario.