C#下usb條碼掃描槍的鉤子實現的改進
阿新 • • 發佈:2019-01-23
【目前的條形碼掃描器有點類似外接鍵盤(其實從訊息傳送上它就相當於一個鍵盤),把輸入焦點定位到可輸入的控制元件上,一掃描相應的條形碼資訊就輸入到文字框中去了,但是如果沒有輸入焦點,或另一個不相干的程式獲得輸入焦點,那就有點亂套了。我想實現的是,不管什麼情況,只要掃描器一工作,我的程式就能自動啟用,並能獲得當前輸入的條形碼資訊。 實現思路:我用的是litele牌的USB口的紅外條形碼掃描器,仔細分析了一下,掃描成功後,以鍵盤按鍵訊息的形式把條形碼輸入資訊通知給系統。這樣通過鍵盤鉤子就可以方便的獲得該資訊了。但是,怎樣區分資訊是鍵盤還是條形碼輸入的哪?很簡單,條形碼掃描器在很短的時間內輸入了至少3個字元以上資訊,並且以“回車”作為結束字元,在這種思想指引下,很完美的實現了預定功能。】
frmMain:
public BarCodeHook BarCode = new BarCodeHook(); public delegate void ShowInfoDelegate(BarCodeHook.BarCodes barCode); void ShowInfo(BarCodeHook.BarCodes barCode){ textBox_barCode.Text = barCode.BarCode; buttonX2.Focus(); } public void BarCode_BarCodeEvent(BarCodeHook.BarCodes barCode) { ShowInfo(barCode); } public frmMain() { InitializeComponent(); BarCode.BarCodeEvent += new BarCodeHook.BarCodeDelegate(BarCode_BarCodeEvent); }
如果焦點本來就在textBox上,會產生多餘的字元,所以在showInfo函式裡,每次都手動讓buttonX2成為焦點。
public class BarCodeHook { public delegate void BarCodeDelegate(BarCodes barCode); public event BarCodeDelegate BarCodeEvent; public struct BarCodes { public int VirtKey; //虛擬碼 public int ScanCode; //掃描碼 public string KeyName; //鍵名 public uint AscII; //AscII public char Chr; //字元 public string BarCode; //條碼資訊 public bool IsValid; //條碼是否有效 public DateTime Time; //掃描時間 } private struct EventMsg { public int message; public int paramL; public int paramH; public int Time; public int hwnd; } [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern bool UnhookWindowsHookEx(int idHook); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam); [DllImport("user32", EntryPoint = "GetKeyNameText")] private static extern int GetKeyNameText(int lParam, StringBuilder lpBuffer, int nSize); [DllImport("user32", EntryPoint = "GetKeyboardState")] private static extern int GetKeyboardState(byte[] pbKeyState); [DllImport("user32", EntryPoint = "ToAscii")] private static extern bool ToAscii(int VirtualKey, int ScanCode, byte[] lpKeyState, ref uint lpChar, int uFlags); delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam); BarCodes barCode = new BarCodes(); int hKeyboardHook = 0; public string strBarCode = ""; public int length; private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { barCode.IsValid = false; bool notChar = false; if (nCode == 0) { EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg)); if (wParam == 0x100) //WM_KEYDOWN = 0x100 { barCode.VirtKey = msg.message & 0xff; //虛擬碼 barCode.ScanCode = msg.paramL & 0xff; //掃描碼 StringBuilder strKeyName = new StringBuilder(255); if (GetKeyNameText(barCode.ScanCode * 65536, strKeyName, 255) > 0) { barCode.KeyName = strKeyName.ToString().Trim(new char[] { ' ', '\0' }); } else { barCode.KeyName = ""; } byte[] kbArray = new byte[256]; uint uKey = 0; GetKeyboardState(kbArray); if (ToAscii(barCode.VirtKey, barCode.ScanCode, kbArray, ref uKey, 0)) { barCode.AscII = uKey; barCode.Chr = Convert.ToChar(uKey); } else { notChar = true; //轉到ascii字元失敗,這不是一個正常字元,要去掉 } if (DateTime.Now.Subtract(barCode.Time).TotalMilliseconds > 30) //30ms可以過濾掉連續按住一個鍵時的情況 { if (notChar == false) strBarCode = barCode.Chr.ToString(); else strBarCode = ""; barCode.IsValid = false; } else { if (strBarCode.Length >= 5) { barCode.IsValid = true; //isValid為true表明這是個條碼 } if (notChar == false) { strBarCode += barCode.Chr.ToString(); } barCode.BarCode = strBarCode; } barCode.Time = DateTime.Now; if (BarCodeEvent != null && barCode.IsValid) BarCodeEvent(barCode); //觸發事件 } } return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam); } // 安裝鉤子 public bool Start() { if (hKeyboardHook == 0) { //WH_KEYBOARD_LL = 13 hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0); } return (hKeyboardHook != 0); } // 解除安裝鉤子 public bool Stop() { if (hKeyboardHook != 0) { bool result = UnhookWindowsHookEx(hKeyboardHook); hKeyboardHook = 0; //將hKeyboardHook 置為0 if (result) { //MessageBox.Show("true"); } return result; } return true; } }
是如果掃到的是英文字元的話,會有一個多餘的碼無法從鍵盤碼轉到ascii碼,需要去掉這個碼。同時設為30ms可以過濾掉一直按住一個鍵的情況。