C# USB掃碼槍winForm處理方法


網上大神的方法是無焦點接收USB掃碼槍數據,我的需求是當前窗口接收就行,沒有必要設置全局鍵盤鈎子。

自己琢磨了一個類,沒有API調用:

    /// <summary>
    /// 條碼解析類
    /// </summary>
    public class Cl_BarCodeReader
    {
        #region 屬性
        /// <summary>
        /// 發布器委托
        /// </summary>
        /// <param name="Barcode">有效碼值字符串</param>
        /// <param name="cl">條碼種類</param>
        public delegate void ScanerDelegate(string Barcode, Barcode_Class cl);
        /// <summary>
        /// 接收到有效條碼的事件發布器
        /// </summary>
        public event ScanerDelegate ScanerReceived;
        /// <summary>
        /// 條碼信息字符串
        /// </summary>
        public string BarCode { get; set; }
        /// <summary>
        /// 按鍵數組
        /// </summary>
        public List<Keys> MyKeys { get; set; }
        /// <summary>
        /// 初始按鍵時間
        /// </summary>
        public long MyTime { get; set; }
        #endregion
        #region 構造
        /// <summary>
        /// 空白構造函數
        /// </summary>
        public Cl_BarCodeReader()
        {
            BarCode = "";
            MyKeys = new List<Keys>();
            MyTime = 0;
        }#endregion
        #region 編輯
        /// <summary>
        /// 處理一個捕獲的按鍵鍵值,如果掃碼完畢,觸發接收事件ScanerReceived
        /// 傳遞包含的碼值字符串和條碼種類枚舉
        /// 編碼規則:nn...ED,n是數字,末尾兩個字母ED
        /// 前兩位數字表示預先規定的條碼的種類/來源,例如:
        /// 01 - 執行跟蹤號
        /// 02 - 計划跟蹤號
        /// ...
        /// </summary>
        /// <param name="key">按鍵鍵值</param>
        public void Add(Keys key)
        {
            //忽略掃碼槍傳來的Shift鍵值
            if (key == Keys.ShiftKey) return;
            var tick = DateTime.Now.Ticks;
            //初次接收
            if (MyKeys.Count == 0)
            {
                //如果不是數字,不處理
                if (!char.IsDigit(Convert.ToChar(key))) return;
                MyKeys.Add(key);
                MyTime = tick;
                return;
            }
            //計算和第一個鍵值的時間差
            var tsp = tick - MyTime;
            /*
            //在即時窗口輸出時間差、鍵值,調試用
            var tk = new Task(() => Debug.WriteLine(tsp.ToString() + " " + Convert.ToChar(key) + " " + key.ToString()));
            tk.Start();
            */
            //時間差大於50毫秒時,不是掃碼槍按鍵,重新捕獲
            if (tsp > 10000 * 50)
            {
                MyKeys.Clear();
                MyTime = 0;
                Add(key);
            }
            else
            {
                //檢查第二位是否為數字,此處需根據條碼的編碼規則修改
                if (MyKeys.Count == 1)
                {
                    if (!char.IsDigit(Convert.ToChar(key)))
                    {
                        MyKeys.Clear();
                        MyTime = 0;
                        return;
                    }
                }
                MyKeys.Add(key);
                //當存儲的鍵值超過4個時,檢查是否結束
                if (MyKeys.Count > 4)
                {
                    //末兩位是ED
                    if (MyKeys[MyKeys.Count - 2] == Keys.E && MyKeys[MyKeys.Count - 1] == Keys.D)
                    {
                        BarCode = "";
                        for (int i = 0; i < MyKeys.Count; i++)
                        {
                            BarCode += Convert.ToChar(MyKeys[i]);
                        }
                        MyKeys.Clear();
                        MyTime = 0;
                        var cd = Code();
                        //觸發事件
                        if (!string.IsNullOrEmpty(cd))
                            ScanerReceived(cd, BarCodeClass());
                    }
                }
            }
        }
        #endregion
        #region 判斷
        /// <summary>
        /// 判斷當前的條碼字符串是否有效
        /// </summary>
        /// <returns></returns>
        public bool IsEffect()
        {
            return IsEffect(BarCode);
        }
        /// <summary>
        /// 判斷指定的條碼字符串是否是有效條碼
        /// </summary>
        /// <param name="barcode"></param>
        /// <returns></returns>
        public static bool IsEffect(string barcode)
        {
//長度檢查
if (barcode.Length < 5) return false;
//前兩位數字檢查
if (!char.IsDigit(barcode, 0) || !char.IsDigit(barcode, 1)) return false;
//末兩位是否是ED
if (barcode.Substring(barcode.Length - 2, 2) != "ED") return false;
//條碼種類檢查
if (BarCodeClass(barcode.Substring(0, 2)) == Barcode_Class.Unkown) return false; return true; } #endregion #region 信息 /// <summary> /// 返回當前條碼字符串中的信息部分 /// 無效返回空字符串 /// </summary> /// <returns></returns> public string Code() { return Code(BarCode); } /// <summary> /// 返回條碼字符串中的信息部分 /// </summary> /// <param name="barcode"></param> /// <returns></returns> public static string Code(string barcode) { if (IsEffect(barcode)) {
//去除前兩位和末兩位
return barcode.Substring(2, barcode.Length - 4); } else return ""; } /// <summary> /// 返回當前條碼種類枚舉 /// </summary> /// <returns></returns> public Barcode_Class BarCodeClass() { if (BarCode.Length > 4) return BarCodeClass(BarCode.Substring(0, 2)); else return Barcode_Class.Unkown; } /// <summary> /// 返回當前條碼種類名稱 /// </summary> /// <returns></returns> public string BarCodeClassName() { var bclass = BarCodeClass();
//GetEnumDescription是一個利用反射獲取枚舉自定義特性的方法,具體實現可以百度
return Cl_General.GetEnumDescription(bclass); } /// <summary> /// 依據條碼前綴,返回條碼種類枚舉 /// </summary> /// <param name="codepre"></param> public static Barcode_Class BarCodeClass(string codepre) { switch (codepre) { case "01": return Barcode_Class.CarryTrackCode; case "02": return Barcode_Class.PlanTrackCode; default: return Barcode_Class.Unkown; } } /// <summary> /// 依據條碼前綴,返回條碼種類名稱 /// </summary> /// <param name="codepre"></param> /// <returns></returns> public static string BarCodeClassName(string codepre) { var bclass = BarCodeClass(codepre);
//GetEnumDescription是一個利用反射獲取枚舉自定義特性的方法,具體實現可以百度
return Cl_General.GetEnumDescription(bclass); } #endregion } /// <summary> /// 條碼種類枚舉 /// </summary> public enum Barcode_Class { [Description("未知")] /// <summary> /// 未知 /// </summary> Unkown, [Description("執行跟蹤號")] /// <summary> /// 執行跟蹤號 /// </summary> CarryTrackCode, [Description("計划跟蹤號")] /// <summary> /// 計划跟蹤號 /// </summary> PlanTrackCode }

我把這個類放在了我的基窗口里,繼承窗口只需要override ScanerHandler來實現具體的收到條碼方法,窗體Load時調用一次SetBarCodeReader即可:

public partial class fm_BaseForm : Form
    {
        protected Cl_BarCodeReader BReader = null;
        /// <summary>
        /// 窗體鍵抬起事件處理過程,用於截獲掃碼槍消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void Form_KeyUp(object sender, KeyEventArgs e)
        {
            BReader.Add(e.KeyCode);
        }
        /// <summary>
        /// 啟用掃碼槍監視對象
        /// </summary>
        protected virtual void SetBarCodeReader(bool setkeypre = true)
        {
            if (setkeypre)
            {
                this.KeyPreview = true;
                this.KeyUp += Form_KeyUp;
            }
            if (BReader == null)
            {
                BReader = new Cl_BarCodeReader();
                BReader.ScanerReceived += ScanerHandler;
            }
        }
        /// <summary>
        /// 停止掃碼槍監視對象
        /// </summary>
        protected virtual void StopBarCodeReader(bool setkeypre = true)
        {
            if (setkeypre)
            {
                this.KeyUp -= Form_KeyUp;
                this.KeyPreview = false;
            }
            if (BReader != null)
            {
                BReader.ScanerReceived -= ScanerHandler;
                BReader = null;
            }
        }
        /// <summary>
        /// 收到有效條碼時的處理過程
        /// </summary>
        /// <param name="bcode"></param>
        protected virtual void ScanerHandler(string bcode, Barcode_Class cl)
        {
            //收到有效條碼時的詳細過程...

        }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM