HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Differentiate a Keyboard-Scanner from Keyboard: TimeoutBuffer

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
differentiatekeyboardtimeoutbufferscannerfrom

Problem

The need is to get the possibility to differentiate between a Barcode-Scanner (which behaves like a keyboard) from a human pressing keys in a...let's say a Textbox (the use case would be all over everything, wherever I expect a barcode scanner).

The basic idea was to create a buffer which holds the typed string (converted from the Keys-Enum, which I already have a function for) and "releases" it to a callback which then handles it. The problem with those scanners is that they behave like normal keyboards, there's no way to differentiate between them and the user except for the amount of time spend between keypresses. To minimize on-screen flickering, it is shoveled into a buffer instead of the control.

Despite that I mostly need it to hold Strings, I wrote it as a generic method because I can imagine to stuff pretty much everything in there when I need it in a certain amount of time back.

So, let's cut to the case:

```
public class TimeoutBuffer
{
private Thread backgroundThread;
private T buffer;
private DateTime lastChange = DateTime.MaxValue;
private Object syncObject = new Object();

public Action Callback { get; set; }
public int Timeout { get; set; }

public TimeoutBuffer(int timeout)
{
this.Timeout = timeout;
}

///
/// Retrieves the value from the buffer (and clears the buffer). Resets the timer.
///
///
public T Get()
{
lock (syncObject)
{
T temp = buffer;
buffer = default(T);
lastChange = DateTime.MaxValue;
return temp;
}
}

///
/// Stores the value into the buffer. Resets the timer.
///
///
public void Store(T buffer)
{
lock (syncObject)
{
this.buffer = buffer;
lastChange = DateTime.Now;
if (backgroundThread == null || backgroundThread.ThreadState == ThreadState.Stopped)
{
backgroundThread = new Thread

Solution

Using DateTime to check the timespan is not as accurate or as good as just using the System.Diagnostic.Stopwatch class. Plus the stopwatch class has a ElapsedMilliseconds already. So you can switch out LastChange with a stopwatch, and everytime you set it to DateTime.MaxValue instead call stopwatch.Reset()

There are places when you use the Object version of an object instead of its primitive counterpart. I haven't seen much discussion on it lately, but most people would prefer to use the primitive counterpart unless using one of the static methods (such as String.Format and even then some people would argue...meh)

What I don't get about your logic and your description is how this would differentiate between Barcode input and UserInput. I say that because if you follow your logic you check if your buffer is null (and actually since it is generic that isn't a good idea you should check if it is equal to default(T), and even that isn't a great idea because you very well may want to pass in null/default value) after you check if it is null you call the callback. Essentially you are forcing your program to wait 20ms to return the data you want. Overall that isn't so bad, and yes, who has the ability to type 13 characters in 20ms??? but... wouldn't it be better to do a circular average of the time between when the buffer gets filled, and return that as part of your callback? You could then check that the AverageTimeBetweenKeyPresses is ???1ms??? and assume that it is a scanner. Meh.. I even see draw backs to that approach as well.

One other thing I would prefer to see is the use of a Monitor pulse and wait system. You can create a timer that just does Monitor.Pulse on a object. In your background thread you would have your while loop but instead of continuasly looping you'd Lock the object to be Pulsed by Monitor. here is a good article that discuses it in length - MSDN Article

Context

StackExchange Code Review Q#15570, answer score: 2

Revisions (0)

No revisions yet.