C# GetKeyboardState和ToAscii并不总是正确处理STX和ETX字符

C# GetKeyboardState和ToAscii并不总是正确处理STX和ETX字符,c#,winapi,keyboard,ascii,keyboard-hook,C#,Winapi,Keyboard,Ascii,Keyboard Hook,我正在使用一个全局键盘挂钩来处理条形码阅读器。条形码阅读器在条形码前面发送一个STX字符,在条形码后面发送一个ETX字符 有时,ToAscii函数会产生正确的STX和ETX代码(0x02或0x03),但大多数情况下会变成0x62(b)或0x63(c) 这是否可以解释并最好解决 为了清晰起见,我在下面添加了钩子回调: private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam) {

我正在使用一个全局键盘挂钩来处理条形码阅读器。条形码阅读器在条形码前面发送一个STX字符,在条形码后面发送一个ETX字符

有时,ToAscii函数会产生正确的STX和ETX代码(0x02或0x03),但大多数情况下会变成0x62(b)或0x63(c)

这是否可以解释并最好解决

为了清晰起见,我在下面添加了钩子回调:

    private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
    {
        if (nCode >= 0)
        {
            // Prepare the characters and retrieve the keyboard state.
            char[] characters = new char[2];
            byte[] keyState = GetKeyboardState();


            if (KeyPressed != null && WinAPI.ToAscii(lParam.vkCode, lParam.scanCode, keyState, characters, 0) == 1)
            {
                // Initialize the event arguments and fire the KeyPressed event.
                GlobalKeyboardHookEventArgs e = new GlobalKeyboardHookEventArgs(characters, (int)wParam);
                KeyPressed(null, e);

                // Do not call the next hook if the event has been handled.
                if (e.Handled)
                {
                    return (IntPtr)1;
                }
            }
        }

        // Call the next hook.
        return WinAPI.CallNextHookEx(hook, nCode, wParam, ref lParam);
    }
}

扫描仪充当键盘,但不是

通过调用
WinApi.ToAscii
(),windows将输入转换为“有效”键映射
ToAscii()
将0x02解释为映射到“b”的键。但这取决于当前安装/配置的活动键盘。所以仅仅依靠“b”和“c”可能会在a上引起问题。。。俄语键盘:-)

只需使用原始输入数据,提取STX/ETX之间的数据,并将该部分映射到Ascii。 该键码应位于
lParam.vkCode
lParam.scanCode

结果可能如下,但我现在无法验证

private bool _isScanningCode;

private IntPtr HookCallback(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam)
    {
        if (nCode >= 0)
        {
            // Prepare the characters and retrieve the keyboard state.
            char[] characters = new char[2];
            byte[] keyState = GetKeyboardState();

            if (lParam.scanCode == 0x02)
            {
                _isScanningCode == true;
                return (IntPtr)1; // act like key is handled
            }
            if (lParam.scanCode == 0x03)
            {
                _isScanningCode == false;
                return (IntPtr)1; //act like key is handled
            }

            if (_isScanningCode)
            {

                if (KeyPressed != null &&
                    WinAPI.ToAscii(lParam.vkCode, lParam.scanCode, keyState, characters, 0) == 1)
                {
                    // Initialize the event arguments and fire the KeyPressed event.
                    GlobalKeyboardHookEventArgs e = new GlobalKeyboardHookEventArgs(characters, (int) wParam);
                    KeyPressed(null, e);

                    // Do not call the next hook if the event has been handled.
                    if (e.Handled)
                    {
                        return (IntPtr) 1;
                    }
                }
            }
        }

        // Call the next hook.
        return WinAPI.CallNextHookEx(hook, nCode, wParam, ref lParam);
    }
}

由于扫描仪是并且必须配置为USB键盘,因此我不得不使用低级键盘挂钩捕获输入。但是,我现在没有使用STX/ETX字符作为前缀/后缀,而是将扫描仪设置为发送键盘命令(Alt+Shift+Backspace)作为前缀和后缀

这使我能够确定条形码何时出现以及何时完成。为了防止用户意外(或有意)使用键盘命令,我实现了一个计时器。计时器确保在100毫秒后没有收到条形码时取消条形码解析

使用RegisterHotKey和UnregisterHotKey Windows API调用捕获键盘命令


在条形码处理过程中吞咽输入时,不要吞咽退格字符非常重要。在热键回调之前调用低级键盘钩子,吞下退格字符将防止热键回调发生。

有很多理由考虑。。。请发布一些代码,以便我们了解上下文。我添加了回调代码。STX和ETX是串行端口通信中常用的控制代码。它们对键盘没有意义,您不应该将它们传递给ToAscii()。是否有更好的方法来检测条形码读取器的输入,或者在不调用ToAscii的情况下检测STX和ETX?低级键盘挂钩运行在安装挂钩的线程上,而不是接收按键的线程上。因此,
GetKeyboardState
返回安装钩子的线程中的Ctrl键是否已按下,这可能是“否”。您需要自己管理状态或使用不同类型的钩子。(或者使用其他机制从条形码阅读器接收数据。注入的按键非常脆弱,尤其是在非英语键盘布局的情况下。在中文系统上运行程序,事情会变得非常奇怪。)虽然原始输入数据可以工作,它不允许我吞下扫描仪的输入,以防止它被用于其他地方。此外,我不明白在同一台电脑上,它怎么可能既能工作又不能随机工作。我担心你建议的方法不起作用。显然,0x02或0x03从未直接放在扫描代码或虚拟键代码中。还有其他建议吗?无法将扫描仪配置为串行设备而不是键盘?