winforms 如何监听键盘输入并将其修改为特定输入?

iqxoj9l9  于 2023-03-19  发布在  其他
关注(0)|答案(1)|浏览(166)

我有一个条形码扫描仪,作为一个键盘输入。我需要它只输入“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);

我如何修改它以实现我想要的目标?
如果有任何遗漏的描述,请告诉我。谢谢。

bsxbgnwa

bsxbgnwa1#

据我所知,您的问题是关于监听 * 来自条形码扫描仪 * 的键盘输入并以某种方式修改扫描的文本。据推测,这必须以不干扰用户尝试输入击键的方式完成。我认为您的思路是正确的,只是我发现通过在主窗体上实现IMessageFilter来挂钩键盘事件更容易。
此方案使用看门狗计时器作为速率检测器,以便它可以区分输入键击的人(较慢)。请注意,虽然它检测扫描,但不会“拦截”击键,因为这样做会吞掉任何较慢的人工击键。这意味着焦点TextBox仍将接收所有击键(例如“abc,def”),但是一旦检测到扫描已经发生,您就可以解析它,并根据需要进行字符串替换(例如“def”)。

public partial class BarcodeScannerForm : Form, IMessageFilter
{
    public BarcodeScannerForm()
    {
        InitializeComponent();
        // Add message filter to hook WM_KEYDOWN events.
        Application.AddMessageFilter(this);
        Disposed += (sender, e) => Application.RemoveMessageFilter(this);
        // Create the visible codes for testing purposes.
        initImages();
    }
    private readonly StringBuilder _buffer = new StringBuilder();
    const int WM_CHAR = 0x0102;
    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg.Equals(WM_CHAR)) detectScan((char)m.WParam);
        return false;
    }
    private void detectScan(char @char)
    {
        Debug.WriteLine(@char);
        if(_keyCount == 0) _buffer.Clear();
        int charCountCapture = ++_keyCount;
        _buffer.Append(@char);
        Task
            .Delay(TimeSpan.FromSeconds(SECONDS_PER_CHARACTER_MIN_PERIOD))
            .GetAwaiter()
            .OnCompleted(() => 
            {
                Debug.WriteLine($"{charCountCapture} {_keyCount}");
                if (charCountCapture.Equals(_keyCount))
                {
                    _keyCount = 0;
                    if(_buffer.Length > SCAN_MIN_LENGTH)
                    {
                        BeginInvoke(()=>MessageBox.Show(_buffer.ToString()));
                    }
                }
            });
    }        
    private void parseScannedText(string scannedText)
    {
        string[] parse = 
            scannedText
            .Split(',', StringSplitOptions.RemoveEmptyEntries)
            .Select(_=>_.Trim())
            .ToArray();
        textBoxIndex0.Text = parse[0];
        if(parse.Length > 1)
        {
            textBoxIndex1.Text= parse[1];
        }
        else
        {
            textBoxIndex1.Clear();
        }
    }
    int _keyCount = 0;
    const int SCAN_MIN_LENGTH = 8; 
    const double SECONDS_PER_CHARACTER_MIN_PERIOD = 0.1;
    .
    .
    .
}

测试

private void initImages()
{
    displayBarCode("abc, def");
    displayQRCode("ghi, jkl");
}
private void displayBarCode(string text)
{
    if (text.Length > 16)
    {
        pictureBoxBC.Image = null;
    }
    else
    {
        BarcodeLib.Barcode barcode = new BarcodeLib.Barcode();
        pictureBoxBC.Image =
            barcode
            .Encode(
                BarcodeLib.TYPE.CODE128,
                text,
                pictureBoxBC.Width,
                pictureBoxBC.Height
            );
    }
}
private readonly QRCodeGenerator _generator = new QRCodeGenerator();
private void displayQRCode(string text)
{
    var qrCode = new QRCode(
        _generator
        .CreateQrCode(text, ECCLevel.Q)
    );
    var image = new Bitmap(qrCode.GetGraphic(20), pictureBoxQR.Size);
    pictureBoxQR.Image = image;
}

相关问题