Click here to Skip to main content
Click here to Skip to main content

Using a bar code scanner in .NET

, 6 Jun 2012
Rate this:
Please Sign up or sign in to vote.
Getting input from a bar code scanner using C# and WPF or WinForms.

Introduction

The vast majority of bar code scanners emulate keyboards which allows them to be easily used in any application. The user simply needs to put the focus on any text input control and then scan a bar code.

This same behaviour though also allows the user to scan bar codes into fields not intended for scanning, and does not allow the application to take instant action when a scan is received because the application has no way of distinguishing the bar code scanner input from the keyboard.

Many vendors have their own APIs which can be used to distinguish the bar code scanner from the keyboard, but in the real world, there are thousands of bar code scanners and relying on vendor specific APIs is not practical.

Fortunately, there is an easy yet not well known method for detecting distinct input from the bar code scanner. This allows the user to scan bar codes without needing to put the focus on a special field, or activate buttons or menu items before each scan.

Background

One of my projects requires integration with POS peripherals for sales, receiving, inventory, and other standard retail functions. Recently we needed to integrate bar code readers. Previously we had used them for lookups, serial number entry, etc. But users were required to tell the software first by clicking a button, or selecting a text box first and then scanning the code. The software didn't know the difference between the scanner and the keyboard, and just took the text sent to it.

This approach allows for a lot of user mistakes, and is also inefficient. There are ways to directly integrate with bar code scanners using third party libraries, SDKs, or OPOS. This seemed like a lot of fuss just to be able to get data from the bar code scanner.

Many people suggested OPOS and we already use OPOS for interacting with high speed thermal printers. OPOS however relies on individual setup on each machine, and a separate OPOS driver for each piece of hardware. Vendor support for OPOS is varied, and often shoddy. For the printers, we accept this because it provides significant benefits over interacting with the raw printer interface and thermal printers tend to be higher end devices with well established OPOS drivers. Bar code scanners however are lower cost items and we may have many different brands.

I did more searching and found that many users resorted to use the WinAPI and keyboard hooks. Most of these solutions required a lot of external calls and many relied on Windows messages which did not work as well with WPF. They also required the developer to uniquely identify they device specifically on each machine.

My First Try

Bar code scanners can be programmed to send a prefix and suffix for each scan, typically STX (start of text) and ETX (end of text). They are 0x02 and 0x03 in ASCII, respectively.

I created a KeyDown event in a WPF app and scanned a bar code. The first key I received was LeftCtrl. LeftCtrl??? Obviously WPF didn't know how to handle low ASCII codes that keyboards were never designed to send. WPF deals with scan codes anyway, and not all ASCII codes can map to scan codes.

I gave up this approach and tried many of the fairly complex WinAPI approaches to try to access the raw input from the bar code scanner. Most had problems with WPF and required a lot of adaptation because they were written for WinForms and relied on Windows messages. I got one to work relatively easily and became excited. But then I ran my first test and got a code of 162. 162 is the scan code for LeftCtrl. :(

Retry

Back to WPF and a simple PreviewKeyUp. I decided to dig a bit deeper past the first character and realized that there was a bit of a pattern. I hoped that I could detect this pattern reliably and intercept the keystrokes. I made a program to log key ups and downs and realized quickly that STX (0x02) was being translated to:

  • LeftCtrl Down
  • B Down
  • B Up
  • LeftCtrl Up

Then it hit me. My previous assumptions were wrong. Windows was seeing the 0x02. I previously had assumed Windows was getting confused, but in fact it was doing a bit of translation. In the very old days of ASCII, Ctrl + a letter was mapped to 1-26 in ASCII. That is Ctrl-A was equivalent to 0x01. On many pre PC machines, you could press Ctrl-M and the computer would see it the same as Enter (0x0D). So Windows was seeing the 0x02 from the bar code scanner and translating it to a series of key code scans that represented Ctrl-B.

Now I had something I could work with.

The Code

I added two events to my main window: PreviewKeyUp and PreviewKeyDown. I kept track of the Ctrl key state and then looked for a B to detect Ctrl-B. From there I collected all input until I found a Ctrl-C (ETX, 0x03) sequence. Note that most bar code readers do not send these sequences by default, but nearly all can be easily reconfigured to do so.

From the Ctrl-B to the Ctrl-C, I assumed all input was from the bar code scanner and set the event handled property so other events in my program would not see the data. At the end, I called an event and handed the data off to my program.

Demo

In the demo, the sole purpose of the edit field is to show that normal keyboard input is taken, but bar code scanner input is not. The listbox on the left shows the raw key scan sequences, and each bar code result is added to the listbox on the right.

The demo was built in C#, WPF, and Visual Studio 2010. It can be very easily used with VB.NET, WinForms, and other versions of Visual Studio.

BarCodeScannerReader/Untitled.png

Reuse

This method can be easily encapsulated into a class for easy reuse on any window. In my application, all of our WPF windows descend from a common base class, so I have put the functionality there. For each window, I simply need to add this in the constructor:

ScanReceived = Scan;
void Scan(string aData) {
  MessageBox.Show("Scan received: " + aData);
}

Result

Without the use of WinAPI, invasive code, or complex code, I found a method to reliably interpret bar code scanner input. In fact the actual code fits easily on a screen. With this method, you also do not need to identify to the code which device is the bar code scanner. The code simply looks for patterns in the key presses and separates the data out.

Caveat

There is one small caveat. Ctrl-B cannot be used in your application for menus or other hot key functions. The code relies on this to detect the start of input from the bar code scanner. The code also looks for Ctrl-C, but only after a Ctrl-B. At other times, it ignores Ctrl-C, so the commonly used shortcut for copy to clipboard does not conflict with usage of this code.

Known Issues

There are a few issues when other keypress handlers exist on the window. I have addressed these in my production code and will update the demo as time permits.

Alternate Method - Keyboard Detection 

Recently I have been thinking of changing the detection to look at which keyboard instance the keys come from. Since the bar code readers register as a keyboard, instead of looking for a prefix the name of the keyboard instance could be used instead. This method will also work with magnetic stripe readers and allow use of bar code scanners without the need to program them to use a prefix or suffix. 

Future Expansion

Bar code scanners can also be programmed to issue other prefixes to identify the type of code scanned, i.e., UPC vs. Code39. With the products we deal with, this is useful because if a UPC is scanned we know it identifies the product, while Code39 and other non UPC/EAN codes typically represent serial numbers of the item. This allows users to receive items very quickly without the need to identify first what they want to do to the software, and instead the software can infer the user intended actions based on the active window. I have expanded my code to recognize other prefixes and respond with other available events. At some point I will merge my updated code back into this example. 

License

This article, along with any associated source code and files, is licensed under The BSD License

About the Author

Chad Z. Hower, a.k.a. Kudzu
"Programming is an art form that fights back"
www.KudzuWorld.com
 
Formerly the Regional Developer Adviser (DPE) for Microsoft Middle East and Africa, he was responsible for 85 countries spanning 4 continents and 10 time zones. Now Chad is a Microsoft MVP.
 
Chad is the chair of several popular open source projects including Indy and Cosmos (C# Open Source Managed Operating System).
 
Chad is the author of the book Indy in Depth and has contributed to several other books on network communications and general programming.
 
Chad has lived in Canada, Cyprus, Switzerland, France, Jordan, Russia, Turkey, and the United States. Chad has visited more than 60 countries, visiting most of them several times.

Comments and Discussions

 
QuestionSerial or USB-Serial is a much better way to go. PinmemberByron Jones7-Jun-12 14:47 
AnswerRe: Serial or USB-Serial is a much better way to go. PinmemberChad Z. Hower aka Kudzu8-Jun-12 0:39 
GeneralRe: Serial or USB-Serial is a much better way to go. PinmemberEtherealMonkey11-Jun-12 8:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140718.1 | Last Updated 6 Jun 2012
Article Copyright 2011 by Chad Z. Hower aka Kudzu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid