I have a win forms app that i am trying to add a bar code scan too.
The window has multi able text boxes which the user fills in. When user clicks on a box and scans bar code it goes into the selected text box.
Is it possible to write an event to put the text into a particular textbox when scanned even if a different text box is highlighted?
If so how would i do this.
Thanks
There are different types of barcode scanners: keyboard wedge, and serial ones.
Keyboard wedge will send 'messages' as if they were input from the keyboard. So normally they only appear when some kind of edit box has focus.
To put that scanned data in a textbox without having focus, the best and safest way would be to capture the messages in a seperate background thread (this could work for KB wedge as wel as for serial). With KB wedge, your thread would have to check the (prefix)codes to see if they are coming from the barcode scanner - if not, forward then to the normal windows message processing.
Some barcode scanners might have libraries available that already do that for you.
On the other hand, if the app has only one window, and a KB wedge scanner is used, a seperate thread could be avoided, and the messages can be captured inside that window, analysed, and if a barcode is detected the data can be put in the right text box. But I would never trust the user to be in the right text box when scanning the barcode - in fact, that text box should better be read-only.
But, in general, when the application has multiple windows, a background thread may be the only option. Some examples:
A user scans a barcode on a document (invoice for example), and that document needs to be opened automatically. The thread could capture the code, and open that document.
A user scans an EAN code, and wants to see the details of the product. Same as above.
Here's some example code that handles scan events. The scnner has to be configured as a serial scanner, they usually come with barcodes that configure the scanner.
private SerialPort InitializeScanner()
{
SerialPort port = null;
bool result;
int iPort = 2;
do
{
try
{
result = true;
port = new SerialPort("COM" + iPort, 9600, Parity.None, 8, StopBits.One);
port.Close();
if (!port.IsOpen)
port.Open();
port.DiscardOutBuffer();
port.DiscardInBuffer();
port.DataReceived += OnScan;
}
catch (IOException)
{
iPort++;
result = false;
}
} while (result == false && iPort <= 20);
return port;
}
It's all about this line:
port.DataReceived += OnScan;
Here's an example of OnScan. You can set any textbox in that function, although note that you have to use Invoke to set the GUI components, the serial port thread is a different thread from the GUI one.
private void OnScan(object sender, SerialDataReceivedEventArgs args)
{
SerialPort port = sender as SerialPort;
string line = port.ReadExisting();
int idx = line.IndexOf('\r');
if (idx != -1)
{
line = line.Substring(0, idx);
_scanBuffer += line;
Invoke((MethodInvoker)delegate { OnScan(_scanBuffer); });
_scanBuffer = "";
}
else
{
_scanBuffer += line;
}
}
Related
I am working on a barcode reader project in Visual Studio using C#. I have created a WinForm Application and have added a RichTextBox to it. I want the user to be able to start scanning when they open the program without having to click on the textbox.
Thanks in advance!
(I'm assuming you have an application with a multitude of stuff in it. However there is one field that needs to be filled in with a scanned barcode.)
I faced a simular issue a while ago. I needed to capture a barcode in WPF. Setting the focus property in load seemed a good idea but because there were a multitude of other controls on the page that the user could click etc. focus jumped from one control to the other, making the barcode go in the wrong fields or vanish in a grid that has focus for example.
We were not able to use any other way of reading the barcode from the scanner because it was used for other applications too. It had to be configured as input.
We came up with a solution of capturing the keypresses instead.
By using the keydown events we could track the scanner input and stated that if more than 5 keys came in within a limited time + with our prefix and suffix it had to be a barcode.
EDIT: here is a simplified version of the class.
public delegate void BarcodeRead(string barcode);
public class ManualReader
{
private string barcode = "no barcode detected";
private string possible = "";
private DateTime timestarted = DateTime.MinValue;
private Timer InputTimeout;
public BarcodeRead OnBarcodeRead;
public void OnKeyDown(object sender, KeyEventArgs.KeyEventArgs e)
{
//create timer if it does not exist
if (InputTimeout == null)
{
InputTimeout = new Timer(100);
InputTimeout.Enabled = true;
InputTimeout.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
//reset timer
InputTimeout.Stop();
InputTimeout.Start();
//possible barcode
possible += CharToKey.GetCharFromKey(e);
if (timestarted == DateTime.MinValue)
{
timestarted = DateTime.Now;
}
}
//Timer elapses
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
//Is it a barcode?
if ((timestarted.AddMilliseconds(600) > DateTime.Now) && (possible.Length > 5)
&& (timestarted != DateTime.MinValue) && possible.Contains("\r"))
{
barcode = possible;
barcode = barcode.Remove(0, 1);
barcode = barcode.Replace("\r", "");
//launch delegate
if (OnBarcodeRead != null)
{
OnBarcodeRead.Invoke(barcode);
}
}
//delete timers
timestarted = DateTime.MinValue;
InputTimeout.Dispose();
InputTimeout = null;
possible = null;
}
}
}
I'm aware that for really short timeouts datetime functions aren't precise but still this little 'hack' worked perfectly for our application.
You can add directly in the element. This works for textbox but not sure with RichTexBox
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
Is it possible to suppress the windows global shortcuts while recording keypresses ?
I have a Windows Form application written in c#, and using this library to record keypresses to use later in macros. Now when I record the key combinations that are used by Windows (i.e. L Control + Win + Right Arrow to change virtual desktop on Win 10), I'd like my app to record it but avoid windows actually using it while I record which is quite annoying.
I have a checkbox to enable key capturing, on click event
m_KeyboardHookManager.KeyDown += HookManager_KeyDown;
the HookManager_KeyDown is simply like this
private void HookManager_KeyDown(object sender, KeyEventArgs e)
{
Log(string.Format("KeyDown \t\t {0}\n", e.KeyCode));
string [] sArr = new string [2];
if (keyBindingArea1.Text != "")
{
sArr[0] = keyBindingArea1.Text;
sArr[1] = string.Format("{0}", e.KeyCode);
keyBindingArea1.Text = string.Join("+", sArr);
}
else
{
keyBindingArea1.Text = string.Format("{0}", e.KeyCode);
}
}
which display the key combination in a comboText control. (This code is taken directly from the demo attached to the package.
Now the recording work well if for instance I press L Control + Win, then I release the keys and press the third one (i.e. Right Arrow), this will not trigger Windows shortcuts but it is quite annoying to have it work like that.
Appreciate any help. Thanks
Try to use e.Handled property of the event. If you set it to true it will terminate key procesing chain. As a rule oher applications in the processing chain will not get it. I am not sure it is going to work for such a low level windows staff as virtual desktop switch.
private void OnKeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
bool isThirdKey = //Some state evaluation to detect the third key was pressed
if (isThirdKey) e.Handled = true;
}
I have a program that is similar to an ATM application. I use my android device a the Keypad. No problem with transmitting data from phone to my C# program. I use threading. I have a problem on how to really "start" the ATM application.
The only input device is the android device. I will not use computer keyboard or anything. So once the program is shown, the first thing is that the program will ask what kind of transaction is it.
private void FrontPage_Shown(object sender, EventArgs e)
{
Ask_Transaction();
}
and inside that... (Edited part)
public void Ask_Transaction()
{
string decoded_input = "";
decoded_input = KT.CheckPress(input); //"input" is the data from the arduino. the checkpress will decode it.
do
{
try
{
//input = serialPort.ReadLine();
switch (KT.CheckPress(input))
{
case "S5": //Card;
break;
case "S6": //Cardless
{
PF.Format_Cardless();
AskLanguage(); //if cardless, it will now ask the language. Once again, another input from serial is needed
}
break;
case "Cancel": PF.Format_TransactionCancelled();
break;
default:
break;
}
}
catch
{
//To catch ReadTimeout after 6 seconds
//"You do not respond to the alloted time.."
}
}
while (decoded_input != "S5"
|| decoded_input != "S6"
|| decoded_input != "Cancel");
}
my problem is that when I try to loop Ask_Transaction until I get the correct inputs (S5 or S6 or cancel) using a do-while loop, my program is lagging and eventually crashing. No errors displaying.
EDIT:
Of course we cannot assure that the user will input the correct key. And usually when you click just numbers on the keypad, ATM program will not notify you at first. It will just wait for possible correct inputs. Also, if the user enters S6, the program will now ask another input using those keypad numbers s5 and s6. the problem is that the program is not "continuous". Any kind of help will be appreciated.
I have a application that reads data from health cards and parse them for basic info like D.O.B., Health Card #, and names. Right now, I have a textbox that takes input from the card swiper and it works great, but I feel there could be a better approach for this.
I want to have a keyboard listener in the background of the application that captures input from the card swiper and parse the data without the need of a textbox. I figure I'll need a loop function in the Form1_Load that actively listens for keyboard inputs, prepare a buffer for the input, and then when a carriage return is detected, go ahead and parse the buffered data. When the parsing is done, clear the buffer.
My problem is I'm relatively new to C# and I don't know what I should use for listening to keyboard inputs without a textbox. Could someone point me in the right direction?
Here's my code in case if anyone's interested: http://pastebin.com/q6AkghvN
Just a note, I followed the credit card swipe guide from
http://www.markhagan.me/Samples/CreditCardSwipeMagneticStripProcessing and modified it slightly for my usecase.
--- EDITED ---
Thanks Paul and everyone else for their help!
Here is my solution if anyone is interested:
private void frmMain_KeyPress(object sender, KeyPressEventArgs e)
{
lblStatus.Text = "Reading Card...";
lblStatus.ForeColor = Color.Blue;
if (e.KeyChar != (char)Keys.Enter)
{
buffer += e.KeyChar;
}
else
{
lblStatus.Text = "Parsing Card...";
if (buffer.Contains('^') && buffer.Contains(';') && buffer.Contains('='))
{
try
{
string[] cardData = buffer.Split(';');
string[] caretData = cardData[0].Split('^');
string[] nameData = caretData[1].Split('/');
string[] equalData = cardData[1].Split('=');
tBoxHealthCardNumber.Text = equalData[0];
tBoxDateOfBirth.Text = FormatBirthday(equalData[1]);
tBoxFirstName.Text = TrimName(nameData[1]);
tBoxLastName.Text = TrimName(nameData[0]);
tBoxDateTimeScanned.Text = DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm");
e.Handled = true;
}
catch (Exception)
{
throw;
}
}
else
{
lblStatus.Text = "Error Reading Card";
}
buffer = "";
lblStatus.Text = "Ready";
lblStatus.ForeColor = Color.Green;
}
}
If you add a key handler to the form you will not see the key presses when focus is on a control, e.g. a textbox. For the form to see the key presses even when there is a focused control, you must also enable the KeyPreview property.
You can then add a handler for KeyDown, KeyPress and/or KeyUp on the form as you desire to receive these events.
As you can read in the documentation to KeyPreview, if you set the Handled property to true, you can prevent the event from being subsequently sent to the focused control, i.e. you can hide certain key events from being seen by the focused control.
I know that we can use pin no.3 to send the data as a output in RS232. But I am just wondering that there is another way to send only the voltage 5v to the RS232 in a short period? I just want that 5v to trigger a PIC Microcontroller to do something.
Thank you in advance.
You could use the DTREnable (Data Terminal Ready) property of the SerialPort class to apply a positive voltage to those respective pins. This could be used to signal an MCU.
Something along the lines of...
serialPort.DtrEnable = true; //High
currentThread.Sleep(1000);
serialPort.DtrEnable = false; //Low
currentThread.Sleep(1000);
However! the voltage is likely to be incompatible as RS232 operates -25 to 25 volts for 1/0's. You will likely need an inline driver/receiver such as a MAX232 chip to operate between the MCU and computer, or dependant on your skill level you could build a receiver circuit.
you can use RTS or DTR as long as you aren't using them on the PIC side for flow control
PIC Microcontroller with TTL interface used logic as follows:
Logic 1 == 5 volt.
Logic 0 == 0 volt.
Computer with RS232 interface used logic as follows:
Logic 1 == -3 volt until -25 volt.
Logic 0 == 0 until 25 volt.
For connecting device TTL logic to RS232 logic can used MAX232 IC. MAX232 will translate your TTL logic to RS232 Logic.
Another options - cheaper and simple, used TRANSISTOR for convert TTL logic to RS232 logic vice versa, look at http://www.kmitl.ac.th/~kswichit/ap275/ap275.htm for details.
If need send data without hardware handshaking, only need pin 2 (RX), pin 3(TX), pin 5(GND). If need handshaking, add pin 7(RTS) AND pin 8(CTS).
Transmitte data as follows:
serialPort1.Open();
serialPort1.Write("your data in here");
Receive data as dollows:
public Form1()
{
InitializeComponent();
this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(this.serialPort1_DataReceived);
serialPort1.Open();
}
void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int i = 0;
string[] DataReceived;
while (serialPort1.BytesToRead > 0)
{
DataReceived[i] = Convert.ToByte(serialPort1.ReadByte()); // data already in here
i++;
if (i == int.MaxValue-1)
i = 0;
}
// Parsing your data in here
}
If just need toggle output, used pin 4 (DTR) OR pint 7(RTS).
serialPort1.DtrEnable = true;ORserialPort1.RtsEnable = true;