【问题标题】:Blocking input from keyboard HID阻止来自键盘 HID 的输入
【发布时间】:2013-11-19 16:31:37
【问题描述】:

我正在将 USB 条形码扫描仪的支持集成到 WPF 应用程序中,但遇到了障碍。

目前我在this 文章的帮助下成功识别和捕获输入。

我面临的问题是,虽然我成功识别和路由来自扫描仪设备的输入,但我无法阻止输入事件以进行进一步处理(例如,如果我的应用程序上的文本框控件具有输入焦点,则输入从扫描仪将被写入它)。

我尝试了两种捕获输入的方法:

var wndSourceHandle = HwndSource.FromHwnd(new WindowInteropHelper(
                                          _wndEventSource = value).Handle);
wndSourceHandle.AddHook(this.WndProc);

WndProc 定义:

private IntPtr WndProc(IntPtr hwnd, int iMessage, IntPtr wParam, IntPtr lParam, ref  bool bisHandled)
    {
        if (iMessage == Win32.WM_INPUT)
        {
            var result = ProcessRawInput(lParam);
            bisHandled = result != null && result.Value;
            return IntPtr.Zero;
        }

        return IntPtr.Zero;
    }

还有:

ComponentDispatcher.ThreadFilterMessage += (ref MSG msg, ref bool handled) =>
                {
                    if (msg.message == Win32.WM_INPUT)
                    {
                        var result = ProcessRawInput(msg.lParam);
                        handled = result != null && result.Value;
                        return;
                    }

                    handled = false;
                };

如果输入源是条码扫描器,ProcessRawInput 方法返回 true,否则返回 false。

【问题讨论】:

    标签: c# wpf barcode-scanner hid


    【解决方案1】:

    经过更多研究,我找到了适用于 WinForms here 的解决方案。我能够为 WPF 修改它,如下所示:

    ComponentDispatcher.ThreadFilterMessage += (ref MSG msg, ref bool handled) =>
                    {
                        if (msg.message == Win32.WM_INPUT)
                        {
                            var result = ProcessRawInput(msg.lParam);
                            this.m_bIgnoreNextKeyDownMessage = result != null && result.Value;
                            return;
                        }
                        if (msg.message == Win32.WM_KEYDOWN && this.m_bIgnoreNextKeyDownMessage)
                        {
                            handled = true;
                        }
    
                        this.m_bIgnoreNextKeyDownMessage = false;
                    };
    

    此解决方案基本上将条形码 WM_INPUT 消息之后的第一个 WM_KEYDOWN 消息标记为“已处理”。我不确定这是否是唯一/最好/最安全的解决方案,但看起来它可以解决问题。

    更新:

    通过上述解决方案,我仍然发现扫描条形码中的一个随机字符会不时地滑入焦点文本框 - 我不确定为什么会这样 - 可能是键盘事件的时间问题,因为它们通过消息处理程序传递。检查是否应忽略 WM_KEYDOWN 消息的另一种解决方案:

    if (msg.message == Win32.WM_KEYDOWN && !String.IsNullOrEmpty(this.m_strKeyInput))
    {
        handled = true;
    }
    

    缓冲区 m_strKeyInput 包含当前扫描的条形码值 - 当没有可用的条形码时,此缓冲区为空,当条形码扫描仪向下推条形码时一次建立一个字符 - 然后在生成自定义 BarcodeScanned 事件后清空。我能想到的这个解决方案的唯一缺点是,所有键盘都会在从扫描仪推送条形码的几毫秒内停止工作——这对我的场景来说是可以接受的。

    【讨论】:

    • 程序最小化时应用程序是否工作? - 所以如果你在桌面上扫描,你的应用程序会捕获数据吗?
    • 我已经测试过,即使程序最小化,它也能捕捉到条形码数据。对于我的要求,这不是问题。
    • 你能给我看一个完整的代码示例吗?
    【解决方案2】:

    听起来,因为您正在将来自扫描仪的输入(将其视为键盘)路由到一个文本框,您可以简单地使用该文本框上的 Preview* 事件之一来执行您的额外处理。例如你可以覆盖PreviewTextInput

    private void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
    {
      // MyBarcodeScanner would be a reference to the IInput device that represents the scanner:
      if (e.Device == MyBarcodeScanner)
      {
        // Process the text, rejecting it in this case.
        // Marking the event as handled will prevent the 'TextChanged' event 
        // from firing, so the characters will not appear in the text box.
        e.Handled = true;
      }
      else
      {
        // This is some other keyboard, by not handling the event,
        // the users will be allowed to enter text normally.
      }
    }
    

    您可能需要进行一些尝试和错误,才能弄清楚如何识别由“e.Device”识别的条形码扫描仪,但这应该相对容易。抱歉,我不能更完整,但我没有自己的条形码扫描仪可以试验。

    【讨论】:

    • 扫描仪的输入由后台线程处理 - 我试图阻止扫描仪设备的输入在执行扫描时显示在我的应用程序中的任何焦点文本框中。
    • 然后使用相同的事件来阻止输入。查看更新的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 1970-01-01
    • 2014-08-23
    • 2012-02-04
    • 2014-02-02
    • 2016-03-15
    • 2021-06-14
    相关资源
    最近更新 更多