Reputation: 80
I am currently writing a C# application that will accept input from multiple USB connected input devices. Using the Raw Input library, I am able to identify the input device and then complete an action based on the input device.
Example: Device A input is received as a series of keystrokes, a string is built, a database is queried using the 'built' string as a parameter, Printer A prints the results.
The issue I am having is latency when multiple devices input values at the same time. Device A input is received at the same time as Device B; Printer A prints immediately but Printer B experiences somewhat of a delay in printing. The delay is no longer than a second, but that is one second too long for this projects intended purpose. I am using barcode scanners so I will say that the input of the entire string is lightning fast for lack of a better quantitative measurement.
I don't think my question requires any code on my behalf but if needed to help answer the question then let me know and I can provide a snippet. I am simply looking for an example or a strategy to use to go about multithreading input to output if that makes sense.
Any help is appreciated.
EDIT (Adding current code):
private readonly RawInput _rawinput;
const bool CaptureOnlyInForeground = true;
public InputForm()
{
InitializeComponent();
_rawinput = new RawInput(Handle, CaptureOnlyInForeground);
}
string Scanner1ID;
string Scanner2ID;
string Printer1IP;
string Printer2IP;
int NumberIdentifier;
string ScannedItem;
string ScannedKey;
PLabel NewLabel = New PLabel();
//Various methods are used to identify each scanner and printer, print commands are sent via the TcpClient class in conjunction with a StreamWriter.
void StartScanning(object sender, EventArgs e)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
_rawinput.AddMessageFilter();
Win32.DeviceAudit();
_rawinput.KeyPressed += OnItemScanned;
}
private void OnItemScanned(object sender, RawInputEventArg e)
{
ScannedKey = e.KeyPressEvent.VKeyName.Replace("D", "");
if (int.TryParse(ScannedKey, out NumberIdentifier)
{
ScannedItem += ScannedKey;
if (e.KeyPressEvent.VKey == 13 || ScannedItem.Length == 10)
{
InOutList.Items.Add(ScannedItem); //Adds to list in form
if (e.KeyPressEvent.DeviceHandle.ToString() == Scanner1ID)
{
NewLabel.querySQL(ScannedItem);
Printer1Writer.Write(NewLabel.Results);
Printer1Writer.Flush();
}
else if (e.KeyPressEvent.DeviceHandle.ToString() == Scanner2ID)
{
NewLabel.pingSQL(ScannedHWB);
if (Client2Printer2.Connected)
{
NewLabel.querySQL(ScannedItem);
Printer2Writer.Write(NewLabel.Results);
Printer2Writer.Flush();
}
}
ScannedItem = "";
}
}
}
I may have left something out but hopefully this is enough.
Upvotes: 1
Views: 637
Reputation: 150138
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.
Upvotes: 2