我有一个条形码扫描仪,作为一个键盘输入。我需要它只输入“def”当我扫描“abc,def”在任何输入领域,如网页,应用程序等。
此程序将在Windows 10和11上运行。
该代码包括我尝试过的三个方法。
我尝试使用下面的代码进行全局监听。
//install hook
public bool KeyboardStart()
{
if (hKeyboardHook == 0)
{
hookproc = new HookProc(KeyboardHookProc);
IntPtr moduleptr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);
hKeyboardHook = SetWindowsHookEx(13, hookproc, moduleptr, 0);
//WH_KEYBOARD_LL=13
//hKeyboardHook = SetWindowsHookEx(13, new HookProc(KeyboardHookProc), Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);
}
return (hKeyboardHook != 0);
}
//uninstall hook
public bool KeyboardStop()
{
if (hKeyboardHook != 0)
{
return UnhookWindowsHookEx(hKeyboardHook);
}
return true;
}
以下是在使用KeyboardHookProc
侦听期间尝试的方法。
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
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(225);
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.Ascll = uKey;
barCode.Chr = Convert.ToChar(uKey);
}
TimeSpan ts = DateTime.Now.Subtract(barCode.Time);
if (ts.TotalMilliseconds > 50)
{
strBarCode = barCode.Chr.ToString();
}
else
{
if ((msg.message & 0xff) == 13 && strBarCode.Length > 3)
{
barCode.BarCode = strBarCode;
barCode.IsValid = true;
//methods 1
//it can run on button click event and hook
//------------------------------------------------
IntPtr foregroundWindow = GetForegroundWindow();
int foregroundWindowProcessId;
GetWindowThreadProcessId(foregroundWindow, out foregroundWindowProcessId);
Process foregroundProcess = Process.GetProcessById(foregroundWindowProcessId);
List<IntPtr> result = new List<IntPtr>();
int ct = 0;
IntPtr prevChild = IntPtr.Zero;
IntPtr currChild = IntPtr.Zero;
while (true && ct < 100)
{
currChild = FindWindowEx(foregroundProcess.MainWindowHandle, prevChild, null, null);
if (currChild == IntPtr.Zero) break;
result.Add(currChild);
prevChild = currChild;
++ct;
}
Point caretPos = Cursor.Position;
IntPtr target = IntPtr.Zero;
target = WindowFromPoint(caretPos);
foreach (IntPtr hWnd in result)
{
if (hWnd == target)
{
Clipboard.SetText(BarcodeSplit(strBarCode) + "\r");
SendMessage(hWnd, WM_PASTE, 0, "");
}
}
private string BarcodeSplit(string str)
{
string[] BarcodeArray = str.Split(',');
if (LimitCode.Contains(BarcodeArray[2]))
{
return BarcodeArray[0];
}
else
{
return BarcodeArray[1];
}
}
//------------------------------------------------
//methods 2
//it can not run on hook
//------------------------------------------------
IntPtr foregroundWindow = GetForegroundWindow();
//set windows focus
SetForegroundWindow(foregroundWindow);
INPUT Input = new INPUT();
Input.type = 1; //keyboard_input
Input.ki.wVk = 0x42; //CAPS_Lock
Input.ki.dwFlags = 0;
SendInput(1, ref Input, Marshal.SizeOf(Input));
Input = new INPUT();
Input.type = 1;
Input.ki.wVk = 0x42;
Input.ki.dwFlags = 2;//key_up
SendInput(1, ref Input, Marshal.SizeOf(Input));
//------------------------------------------------
//methods 3
//it can not run on hook
//------------------------------------------------
IntPtr foregroundWindow = GetForegroundWindow();
//set windows focus
SetForegroundWindow(foregroundWindow);
SendKeys.Send(barCode.BarCode);
//------------------------------------------------
}
strBarCode += barCode.Chr.ToString();
}
barCode.Time = DateTime.Now;
if (BarCodeEvent != null) BarCodeEvent(barCode);
barCode.IsValid = false;
}
}
//stop keyboard key in
return 1;
}
public struct BarCodes
{
public int VirtKey;
public int ScanCode;
public string KeyName;
public uint Ascll;
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;
}
[StructLayout(LayoutKind.Explicit)]
internal struct INPUT
{
[FieldOffset(0)]
internal int type;//0:mouse event;1:keyboard event;2:hardware event
[FieldOffset(4)]
internal KEYBDINPUT ki;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
internal ushort wVk;
internal ushort wScan;
internal uint dwFlags;
internal uint time;
internal IntPtr dwExtraInfo;
}
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, string lParam);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint SendInput(uint nInput, ref INPUT pInput, int cbSize);
我如何修改它以实现我想要的目标?
如果有任何遗漏的描述,请告诉我。谢谢。
1条答案
按热度按时间bsxbgnwa1#
据我所知,您的问题是关于监听 * 来自条形码扫描仪 * 的键盘输入并以某种方式修改扫描的文本。据推测,这必须以不干扰用户尝试输入击键的方式完成。我认为您的思路是正确的,只是我发现通过在主窗体上实现IMessageFilter来挂钩键盘事件更容易。
此方案使用看门狗计时器作为速率检测器,以便它可以区分输入键击的人(较慢)。请注意,虽然它检测扫描,但不会“拦截”击键,因为这样做会吞掉任何较慢的人工击键。这意味着焦点
TextBox
仍将接收所有击键(例如“abc,def”),但是一旦检测到扫描已经发生,您就可以解析它,并根据需要进行字符串替换(例如“def”)。测试