Search code examples
c#event-handlingbarcode-scanner

Read barcode scanner entry when focused on button


I use a barcode scanner listener using the key-press event as follows (from another post):

public Form2() {
     InitializeComponent();
     //
     this.KeyPreview = true;
     this.KeyPress += Form2_KeyPress;
     this.Button1_click += (s, e) => {
           // --- even if I don't close the form, the click event firing
           // prevents the "Process barcode" to execute...
           //this.Close();
           Console.Writeln("hitting focused button.");
      }
 }
 public void KeyPress_scanner_preview(object sender, KeyPressEventArgs e) {
      // check timing (keystrokes within 100 ms)
      TimeSpan elapsed = (DateTime.Now - _lastKeystroke);
      if (elapsed.TotalMilliseconds > 100)
        _barcode.Clear();

      // record keystroke & timestamp
      _barcode.Add(e.KeyChar);
      _lastKeystroke = DateTime.Now;

      // process barcode
      if (e.KeyChar == 13 && _barcode.Count > 0) {
        string msg = new String(_barcode.ToArray());
        MessageBox.Show("Read barcode: " + new String(_barcode.ToArray()));
        _barcode.Clear();
      }
    }

Now my problem is that, with my scanner, when I have focus on a button, the "button_click" event fires BEFORE the BarCodeScannedis fired.

Any hint as to how to prevent this to happen? Possibly disable the button?

EDIT: I added the button click event handler and the form's constructor. Note that I have a single button on the for itself, which is hence automatically focused. Firing the "button click" event prevents the barcode event to be fired (here, showing a messagebox). Note that whether I register the button click event or not doesn't make any difference...


Solution

  • I simply reformat TaW's answer to reflect the case that hitting "Enter" should NOT fire an empty barcode scanned event.

    NOTE With the original parameters, I was able to fire the barcode scanned event from the keayboard quite easily. I therefore reduced the elapsed typing time to 50ms and made sure the _barcode was at least 7 charactes long. This is ok with EAN-8 and EAN-13 formats. Even using both hands, I wasn't able to erroneously fire a barcode saneed event.

    UPDATE the logic was wrong as the ProcessCmdKey should return true if the event key is handled. I implemented the logic in the updated code.

    Here the code:

    DateTime _lastKeystroke = new DateTime(0);
    string _barcode = string.Empty;
    
    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
    {
        bool res = processKey(keyData);
        return keyData == Keys.Enter ? res : base.ProcessCmdKey(ref msg, keyData);
    }
    
    bool processKey(Keys key)
    {
        // check timing (>7 keystrokes within 50 ms)
        TimeSpan elapsed = (DateTime.Now - _lastKeystroke);
        if (elapsed.TotalMilliseconds > 50)
        {
            _barcode = string.Emtpy;
        }
        // record keystroke & timestamp
        _barcode += (char)key;
        _lastKeystroke = DateTime.Now;
        // process barcode
        // --- barcode length should be > 1, not 0 (as the return char
        // itself was added above)
        if (key == Keys.Enter && _barcode.Length > 1)
        {
            string msg = new String(_barcode.ToArray());
            MessageBox.Show(msg);
            _barcode = string.Empty;
            return true;
        }
        return false;
    }