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

时间:2013-11-12 15:33:10

标签: 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)
    {
        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);
    }
}

2 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

扫描仪充当键盘但不是。

通过调用WinApi.ToAscii()窗口将输入转换为“有效”键映射。 ToAscii()将0x02解释为映射到'b'的键。但这取决于当前有效的已安装/配置键盘。所以只依靠'b'和& 'c'会导致问题......俄语键盘: - )

只需使用原始输入数据,在STX / ETX之间提取数据并将该部分映射到Ascii。 该密钥代码应位于lParam.vkCodelParam.scanCode中。 KBDLLHOOKSTRUCT

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

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);
    }
}