掃碼識別實現方法
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace CashierProject.ManageUtils
{
/// <summary>
/// 掃碼識別
/// </summary>
public class ScanHook
{
public List<string> matchString { get; set; }//驗證是否正確的收款碼等信息
public const int WM_KEYDOWN = 256;
public const int WM_KEYUP = 257;
public const int WM_SYSKEYDOWN = 260;
public const int WM_SYSKEYUP = 261;
private int hKeyboardHook;
private static HookProc hookproc;
private static ScanHook instance;
public delegate void ScanerDelegate(string code);
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
public event ScanerDelegate ScanerEvent;
private int delayInputTime = 150;
private int delayOutputTime = 1000;
private List<EventMsg> keys = new List<EventMsg>();
private int last;
private int first;
private bool isPause;
private Thread delayThread;
private bool isBreak = true;
private object lockObject = new object();
public struct EventMsg
{
public int keyCode;
public int paramL;
public int paramH;
public int Time;
public int hwnd;
public int keyType;
}
public struct Result
{
public List<EventMsg> keyCodes;
public string result;
public bool isIntercept;
public bool isScan;
}
public static ScanHook getInstance()
{
if (instance == null)
{
instance = new ScanHook();
}
return instance;
}
/// <summary>
/// 加載鉤子
/// </summary>
/// <param name="idHook"></param>
/// <param name="lpfn"></param>
/// <param name="hInstance"></param>
/// <param name="threadId"></param>
/// <returns></returns>
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
/// <summary>
/// 卸載鉤子
/// </summary>
/// <param name="idHook"></param>
/// <returns></returns>
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto)]
private static extern bool UnhookWindowsHookEx(int idHook);
/// <summary>
/// 當一個文件被映射到調用進程的地址空間時,GetModuleHandle函數得到其中某一模塊的句柄
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string name);
public void SetDelayInputTime(int delayTime)
{
delayInputTime = delayTime;
}
public void SetDelayOutputTime(int delayTime)
{
delayOutputTime = delayTime;
}
/// <summary>
/// 開啓鍵盤監聽
/// </summary>
/// <returns></returns>
public bool Start()
{
if (hKeyboardHook == 0)
{
hookproc = new HookProc(KeyboardHookProc);
IntPtr moduleHandle = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hKeyboardHook = SetWindowsHookEx(13, hookproc, moduleHandle, 0);
return hKeyboardHook != 0;
}
Stop();
return Start();
}
/// <summary>
/// 關閉鍵盤監聽
/// </summary>
/// <returns></returns>
public bool Stop()
{
if (hKeyboardHook != 0)
{
bool flag =UnhookWindowsHookEx(hKeyboardHook);
if (flag)
{
hKeyboardHook = 0;
}
return flag;
}
return true;
}
/// <summary>
/// 監聽鍵盤按鍵
/// </summary>
/// <param name="nCode"></param>
/// <param name="wParam"></param>
/// <param name="lParam"></param>
/// <returns></returns>
private int KeyboardHookProc(int nCode, int wParam, IntPtr lParam)
{
EventMsg msg = (EventMsg)Marshal.PtrToStructure(lParam, typeof(EventMsg));
msg.keyType = wParam;
Result result = Add(msg);
if (result.isIntercept && ScanerEvent != null && result.isScan && !string.IsNullOrEmpty(result.result))
{
if (matchString != null && matchString.Count > 0)
{
bool flag = false;
foreach (string match in matchString)
{
if (IsMatchRegular(result.result, match))
{
flag = true;
break;
}
}
if (flag)
{
ScanerEvent.BeginInvoke(result.result, null, null);//執行掃碼事件
}
else
{
Input(result.keyCodes);
}
}
else
{
Input(result.keyCodes);
}
}
if (!result.isIntercept)
{
return 0;
}
return 1;
}
public Result Add(EventMsg msg)
{
Result result2;
lock (this)
{
Result result = default(Result);
if (isPause)
{
result.isIntercept = false;
result2 = result;
}
else
{
bool flag2 = msg.Time - last < delayInputTime;
last = msg.Time;
if (IsNumberCode(msg))
{
if (keys.Count == 0)
{
first = msg.Time;
}
keys.Add(msg);
DelayInput();
result.isIntercept = true;
result2 = result;
}
else
{
if (msg.keyCode == 13 && keys.Count > 0 && flag2)
{
keys.Add(msg);
result.keyCodes = new List<EventMsg>(keys);
result.result = GetResult();
result.isIntercept = true;
if (msg.keyType == 257)
{
keys.Clear();
result.isScan = true;
}
}
else
{
Input(keys);
keys.Clear();
result.isIntercept = false;
}
result2 = result;
}
}
}
return result2;
}
private void DelayInput()
{
isBreak = true;
if (delayThread == null)
{
delayThread = new Thread(new ThreadStart(ThreadStart));
delayThread.Start();
}
}
/// <summary>
/// 開啓線程
/// </summary>
private void ThreadStart()
{
for (; ; )
{
if (isBreak)
{
isBreak = false;
}
else
{
Thread.Sleep(delayInputTime);
if (isBreak)
{
isBreak = false;
}
else
{
Input(keys);
keys.Clear();
}
}
}
}
/// <summary>
/// 模擬鍵盤輸入掃碼結果
/// </summary>
/// <param name="pressList"></param>
public void Input(List<EventMsg> pressList)
{
object obj = lockObject;
lock (obj)
{
try
{
List<EventMsg> list = new List<EventMsg>(pressList);
if (list.Count > 0)
{
isPause = true;
}
foreach (EventMsg eventMsg in list)
{
if (eventMsg.keyType == 256)
{
KeyBoardUtil.DownKey(eventMsg.keyCode);
}
else if (eventMsg.keyType == 257)
{
KeyBoardUtil.UpKey(eventMsg.keyCode);
}
}
isPause = false;
}
catch
{
}
}
}
/// <summary>
/// 根據鍵盤獲取對應的數字
/// </summary>
/// <returns></returns>
private string GetResult()
{
StringBuilder stringBuilder = new StringBuilder();
foreach (EventMsg eventMsg in keys)
{
if (eventMsg.keyType == 256)
{
switch (eventMsg.keyCode)
{
case 48:
stringBuilder.Append("0");
break;
case 49:
stringBuilder.Append("1");
break;
case 50:
stringBuilder.Append("2");
break;
case 51:
stringBuilder.Append("3");
break;
case 52:
stringBuilder.Append("4");
break;
case 53:
stringBuilder.Append("5");
break;
case 54:
stringBuilder.Append("6");
break;
case 55:
stringBuilder.Append("7");
break;
case 56:
stringBuilder.Append("8");
break;
case 57:
stringBuilder.Append("9");
break;
}
}
}
return stringBuilder.ToString();
}
/// <summary>
/// 正則驗證
/// </summary>
/// <param name="s"></param>
/// <param name="match"></param>
/// <returns></returns>
public static bool IsMatchRegular(string s, string match)
{
bool result;
try
{
result = new Regex(match).IsMatch(s);
}
catch
{
result = false;
}
return result;
}
private bool IsNumberCode(EventMsg msg)
{
return msg.keyCode >= 48 && msg.keyCode <= 57;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CashierProject.ManageUtils
{
/// <summary>
/// 鍵盤輸入模擬
/// </summary>
public class KeyBoardUtil
{
/// <summary>
/// 鼠標事件枚舉數據
/// </summary>
private enum MouseEventFlag : uint
{
Move = 1U,
LeftDown,
LeftUp = 4U,
RightDown = 8U,
RightUp = 16U,
MiddleDown = 32U,
MiddleUp = 64U,
XDown = 128U,
XUp = 256U,
Wheel = 2048U,
VirtualDesk = 16384U,
Absolute = 32768U
}
/// <summary>
/// 模擬鍵盤輸入事件
/// </summary>
/// <param name="bVk"></param>
/// <param name="bScan"></param>
/// <param name="dwFlags"></param>
/// <param name="dwExtraInfo"></param>
[DllImport("user32.dll", SetLastError = true)]
private static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
/// <summary>
/// 模擬鼠標事件
/// </summary>
/// <param name="flags"></param>
/// <param name="dx"></param>
/// <param name="dy"></param>
/// <param name="data"></param>
/// <param name="extraInfo"></param>
[DllImport("user32.dll")]
private static extern void mouse_event(MouseEventFlag flags, int dx, int dy, uint data, UIntPtr extraInfo);
/// <summary>
/// 把光標移到屏幕的指定位置
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern int SetCursorPos(int x, int y);
/// <summary>
///
/// </summary>
/// <param name="key"></param>
public static void PressKey(Keys key)
{
DownKey(key);
UpKey(key);
}
/// <summary>
///
/// </summary>
/// <param name="keys"></param>
public static void PressKey(Keys[] keys)
{
for (int i = 0; i < keys.Length; i++)
{
DownKey(keys[i]);
}
Array.Reverse(keys);
for (int i = 0; i < keys.Length; i++)
{
UpKey(keys[i]);
}
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
public static void PressKey(int key)
{
PressKey((Keys)Enum.ToObject(typeof(Keys), key));
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
private static void UpKey(Keys key)
{
keybd_event(key, 0, 2U, 0U);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
private static void DownKey(Keys key)
{
keybd_event(key, 0, 0U, 0U);
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
public static void UpKey(int key)
{
UpKey((Keys)Enum.ToObject(typeof(Keys), key));
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
public static void DownKey(int key)
{
DownKey((Keys)Enum.ToObject(typeof(Keys), key));
}
/// <summary>
///
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public static void MouseClick(int x, int y)
{
SetCursorPos(x, y);
mouse_event(MouseEventFlag.LeftDown, x, y, 0U, UIntPtr.Zero);
mouse_event(MouseEventFlag.LeftUp, x, y, 0U, UIntPtr.Zero);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cashier.Model;
using CommonUtils;
namespace CashierProject.ManageUtils
{
public class ScanUtil: MarshalByRefObject
{
static string scanCode = "";
/// <summary>
/// 開啓/關閉掃碼監聽
/// </summary>
public static void OpenOrStopScaner()
{
List<string> list = new List<string>();
list.Add("^((10)|(11)|(12)|(13)|(14)|(15))\\d{16}$");//微信支付碼驗證規則
list.Add("^((25)|(26)|(27)|(28)|(29)|(30))\\d{14,22}$");//支付寶付款碼驗證規則
//list.Add("^[0-9]*$");//用於測試的驗證規則 只能是整數
ScanHook.getInstance().matchString = list;
ScanHook.getInstance().ScanerEvent -= new ScanHook.ScanerDelegate(RequestCode);
ScanHook.getInstance().ScanerEvent += new ScanHook.ScanerDelegate(RequestCode);
ScanHook.getInstance().SetDelayInputTime(150);
ScanHook.getInstance().Start();
//ScanHook.getInstance().Stop();
}
/// <summary>
/// 收款碼
/// </summary>
/// <param name="result"></param>
private static void RequestCode(string result)
{
scanCode = result;
//需要執行的事件
}
}
}
調用示例(只需在程序啓動時調用一次就可以)
ManageUtils.ScanUtil.OpenOrStopScaner();