简体   繁体   中英

C# BarCode Scanning Program won't Accept Alphabetic Characters

I've some code written in C# that allows the user to scan a barcode, and the label.Text changes to the input of the barcode. I used a label instead of textbox to prevent the user from fat-fingering a wrong barcode -basically disabling any keyboard input.

Everything works nice, except when the barcode being scanned has alphabetic characters in it. If the barcode starts with an alphabetic character and ends with an alphabetic character, then the barcode doesn't scan at all.

If the barcode starts with an alphabetic character, but ends with numeric characters, the program picks up only the trailing numeric characters.

Here's the code:

    char cforKeyDown = '\0';
    int _lastKeystroke = DateTime.Now.Millisecond;
    List<char> _barcode = new List<char>();
    bool UseKeyboard = false;

  private void Form1_Load(object sender, EventArgs e)
    {
        this.ActiveControl = label1;
        this.KeyDown += new KeyEventHandler(Form1_KeyDown);
        this.KeyUp += new KeyEventHandler(Form1_KeyUp);
    }
 private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        // if keyboard input is allowed to read
        if (UseKeyboard && e.KeyData != Keys.Enter)
        {
            MessageBox.Show(e.KeyData.ToString());
        }

        /* check if keydown and keyup is not different
         * and keydown event is not fired again before the keyup event fired for the same key
         * and keydown is not null
         * Barcode never fired keydown event more than 1 time before the same key fired keyup event
         * Barcode generally finishes all events (like keydown > keypress > keyup) of single key at a time, if two different keys are pressed then it is with keyboard
         */

        if (cforKeyDown != (char) e.KeyCode || cforKeyDown == '\0')
        {
            cforKeyDown = '\0';
            _barcode.Clear();
            return;
        }

        // getting the time difference between 2 keys
        int elapsed = (DateTime.Now.Millisecond - _lastKeystroke);

        /*
         * Barcode scanner usually takes less than 17 milliseconds to read, increase this if neccessary of your barcode scanner is slower
         * also assuming human can not type faster than 17 milliseconds
         */
        // Bumped it up to 35[ms]
        if (elapsed > 50)
            _barcode.Clear();

        // Do not push in array if Enter/Return is pressed, since it is not any Character that need to be read
        if (e.KeyCode != Keys.Return)
        {
            //_barcode.Add((char) e.KeyData);
            _barcode.Add((char) e.KeyData);
        }

        // Barcode scanner hits Enter/Return after reading barcode
        if (e.KeyCode == Keys.Return && _barcode.Count > 0)
        {
            string BarCodeData = new String(_barcode.ToArray());

            if (!UseKeyboard)
            {
                //MessageBox.Show(String.Format("{0}", BarCodeData));
                label1.Text = String.Format("{0}", BarCodeData);
            }
            //_barcode.Clear();
        }
        // update the last key stroke time
        _lastKeystroke = DateTime.Now.Millisecond;
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        //Debug.WriteLine("CS_Single_Label_Printer_KeyDown : " + (char)e.KeyCode);
        cforKeyDown = (char) e.KeyCode;
    }

I've narrowed down the problem to the fact that the alphabetic parts of the alpha-numeric barcodes being scanned are uppercase. I generated a test barcode using lower-case letters, and everything worked as it should, but this still doesn't fix the problem as I have to scan thousands of already printed barcodes that have uppercase characters encoded into the barcode data matrix.

Is there a way to switch the above code in order to account for the 'character | Shift' KeyData?

The answer is that KeyCode returns the KEY pressed. It does not respect the case of the key. Use Shift to get the case. Below is a working example based on your supplied code. The magic is in the local function ToCharacter. You'll need to play with the if statements at the top to include numbers too if that's your desire.

From1.cs

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace DesktopApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        char cforKeyDown = '\0';
        int _lastKeystroke = DateTime.Now.Millisecond;
        List<char> _barcode = new List<char>();
        bool UseKeyboard = false;

        private void Form1_Load(object sender, EventArgs e)
        {
            this.ActiveControl = InputBox;
            this.InputBox.KeyDown += new KeyEventHandler(Form1_KeyDown);
            this.InputBox.KeyUp += new KeyEventHandler(Form1_KeyUp);
        }
        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            char NotALetter = '-';

            DebugBox.Items.Clear();
            DebugBox.Items.Add($"KeyEventArgs->KeyCode = {e.KeyCode.ToString()}");
            DebugBox.Items.Add($"KeyEventArgs->KeyData = {e.KeyData.ToString()}");
            DebugBox.Items.Add($"KeyEventArgs->KeyValue = {e.KeyValue.ToString()}");
            DebugBox.Items.Add($"KeyEventArgs->e.Shift = {e.Shift.ToString()}");
            DebugBox.Items.Add($"ToCharacter = {ToCharacter(e) ?? NotALetter}");


            char? ToCharacter(KeyEventArgs kea)
            {
                int DtoNumPadOffset = (int)(Keys.NumPad0 - Keys.D0);
                if (kea.KeyCode < Keys.D0) return null; // Keys.D0 through Kyes.D9 are the Keys on the top row of the keyboard. D9 is right next to A in the enum type. 
                if (kea.KeyCode > Keys.NumPad9) return null;
                if (kea.KeyCode > Keys.Z && kea.KeyCode < Keys.NumPad0) return null; //knocks out keys between Z and NumPad0
                if (kea.Shift && kea.KeyCode < Keys.A) return null; // rejects special characters when numbers across the top are used with the <shift> key.

                if (kea.KeyCode < Keys.A) return (char)kea.KeyCode;
                if (kea.KeyCode > Keys.Z) return (char)((int)kea.KeyCode - DtoNumPadOffset);

                return kea.Shift
                    ? (char)kea.KeyCode
                    : char.ToLower((char)kea.KeyCode);
            }


            // if keyboard input is allowed to read
            if (UseKeyboard && e.KeyData != Keys.Enter)
            {
                MessageBox.Show(e.KeyData.ToString());
            }

            /* check if keydown and keyup is not different
             * and keydown event is not fired again before the keyup event fired for the same key
             * and keydown is not null
             * Barcode never fired keydown event more than 1 time before the same key fired keyup event
             * Barcode generally finishes all events (like keydown > keypress > keyup) of single key at a time, if two different keys are pressed then it is with keyboard
             */

            //if (cforKeyDown != (char)e.KeyCode || cforKeyDown == '\0')
            //{
            //    cforKeyDown = '\0';
            //    _barcode.Clear();
            //    return;
            //}

            // getting the time difference between 2 keys
            int elapsed = (DateTime.Now.Millisecond - _lastKeystroke);

            /*
             * Barcode scanner usually takes less than 17 milliseconds to read, increase this if neccessary of your barcode scanner is slower
             * also assuming human can not type faster than 17 milliseconds
             */
            // Bumped it up to 35[ms]
            //if (elapsed > 2000)
            if (e.KeyCode == Keys.Return)
            {
                InputBox.Text = String.Empty;
                _barcode.Clear();
            }

            // Do not push in array if Enter/Return is pressed, since it is not any Character that need to be read
            if (e.KeyCode != Keys.Return)
            {
                char? TestForCharacter = ToCharacter(e);

                if (TestForCharacter != null)
                {
                    //_barcode.Add((char) e.KeyData);
                    _barcode.Add((char)TestForCharacter);
                }
            }

            OutputBox.Text = string.Concat(_barcode);

            // Barcode scanner hits Enter/Return after reading barcode
            if (e.KeyCode == Keys.Return && _barcode.Count > 0)
            {
                string BarCodeData = new String(_barcode.ToArray());

                if (!UseKeyboard)
                {
                    //MessageBox.Show(String.Format("{0}", BarCodeData));
                    OutputBox.Text = String.Format("{0}", BarCodeData);
                }
                //_barcode.Clear();
            }
            // update the last key stroke time
            _lastKeystroke = DateTime.Now.Millisecond;
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            //Debug.WriteLine("CS_Single_Label_Printer_KeyDown : " + (char)e.KeyCode);
            cforKeyDown = (char)e.KeyCode;
        }
    }
}

Form1.Designer.cs

namespace DesktopApp2
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.OutputBox = new System.Windows.Forms.TextBox();
            this.InputBox = new System.Windows.Forms.TextBox();
            this.DebugBox = new System.Windows.Forms.ListBox();
            this.SuspendLayout();
            // 
            // OutputBox
            // 
            this.OutputBox.Location = new System.Drawing.Point(52, 93);
            this.OutputBox.Name = "OutputBox";
            this.OutputBox.ReadOnly = true;
            this.OutputBox.Size = new System.Drawing.Size(650, 22);
            this.OutputBox.TabIndex = 1;
            // 
            // InputBox
            // 
            this.InputBox.Location = new System.Drawing.Point(52, 45);
            this.InputBox.Name = "InputBox";
            this.InputBox.Size = new System.Drawing.Size(650, 22);
            this.InputBox.TabIndex = 2;
            // 
            // DebugBox
            // 
            this.DebugBox.FormattingEnabled = true;
            this.DebugBox.ItemHeight = 16;
            this.DebugBox.Location = new System.Drawing.Point(52, 131);
            this.DebugBox.Name = "DebugBox";
            this.DebugBox.Size = new System.Drawing.Size(650, 308);
            this.DebugBox.TabIndex = 3;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(716, 450);
            this.Controls.Add(this.DebugBox);
            this.Controls.Add(this.InputBox);
            this.Controls.Add(this.OutputBox);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion
        private System.Windows.Forms.TextBox OutputBox;
        private System.Windows.Forms.TextBox InputBox;
        private System.Windows.Forms.ListBox DebugBox;
    }
}

Tidy helper class for dealing with KeyEventArgs
The Is* functions group the keycodes into ranges and detect (if appropriate) the shift states. To* functions produce the char that best represents the KeyCode in the event. ToAlphaNumericAsciiCharacter simply pairs up detectors with producers.

public static class KeyEventArgs_Functions
{
    public static bool Between(this Keys source, Keys lhv, Keys rhv)
    {
        return source >= lhv && source <= rhv;
    }
    public static bool IsLetterKeyBoardChar(this KeyEventArgs source)
    {
        return source.KeyCode.Between(Keys.A, Keys.Z);
    }
    public static bool IsNumberKeyBoardChar(this KeyEventArgs source)
    {
        return !source.Shift && source.KeyCode.Between(Keys.D0, Keys.D9);
    }
    public static bool IsNumber10KeyPadChar(this KeyEventArgs source)
    {
        return source.KeyCode.Between(Keys.NumPad0, Keys.NumPad9);
    }
    public static char ToLetterKeyBoardChar(this KeyEventArgs source) // Only returns a valid value if IsLetterKeyBoardChar returns true.
    {
       return source.Shift ? (char)source.KeyCode: char.ToLower((char)source.KeyCode);
    }
    public static char ToNumberKeyBoardChar(this KeyEventArgs source) // Only returns a valid value if IsNumberKeyBoardChar returns true.
    {
        return (char)source.KeyCode;
    }
    public static char ToNumber10KeyPadChar(this KeyEventArgs source) // Only returns a valid value if IsNumber10KeyPadChar returns true.
    {
        const int DtoNumPadOffset = (int)(Keys.NumPad0 - Keys.D0);
        return (char)((int)source.KeyCode - DtoNumPadOffset);
    }
    public static char? ToAlphaNumericAsciiCharacter(this KeyEventArgs source)
    {
        if (source.IsLetterKeyBoardChar()) return source.ToLetterKeyBoardChar();
        if (source.IsNumberKeyBoardChar()) return source.ToNumberKeyBoardChar();
        if (source.IsNumber10KeyPadChar()) return source.ToNumber10KeyPadChar();
        return null;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM