C# GetKeyboardState和ToAscii并不总是正确处理STX和ETX字符
我正在使用一个全局键盘挂钩来处理条形码阅读器。条形码阅读器在条形码前面发送一个STX字符,在条形码后面发送一个ETX字符 有时,ToAscii函数会产生正确的STX和ETX代码(0x02或0x03),但大多数情况下会变成0x62(b)或0x63(c) 这是否可以解释并最好解决 为了清晰起见,我在下面添加了钩子回调: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) {
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从未直接放在扫描代码或虚拟键代码中。还有其他建议吗?无法将扫描仪配置为串行设备而不是键盘?