C# 使用预过滤消息读取条形码时出现问题

C# 使用预过滤消息读取条形码时出现问题,c#,keyboard,barcode,keycode,imessagefilter,C#,Keyboard,Barcode,Keycode,Imessagefilter,我的任务是从符号LS2208条形码扫描仪读取条形码。 扫描仪设置为deafult,但前缀为F13,surfix为“Enter”。使用此功能,扫描仪可以模拟美国键盘。我的键盘是丹麦语,操作系统语言设置为丹麦语。 我喜欢独立于区域设置的最终用户 现在,我正在使用以下方法实现IMessageFilter: private const int WM_KEYDOWN = 0x100; private List<Keys> keysSequence = new List<K

我的任务是从符号LS2208条形码扫描仪读取条形码。
扫描仪设置为deafult,但前缀为F13,surfix为“Enter”。使用此功能,扫描仪可以模拟美国键盘。我的键盘是丹麦语,操作系统语言设置为丹麦语。
我喜欢独立于区域设置的最终用户

现在,我正在使用以下方法实现IMessageFilter:

    private const int WM_KEYDOWN = 0x100;
    private List<Keys> keysSequence = new List<Keys>();
    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_KEYDOWN)
        {
            Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
            if (keyCode == Keys.F13)
            {
                ...
                return true;
            }
            if (keyCode == Keys.Enter)
            {
                ...
                string barcode = GenerateBarcode(keysSequence);
                return true;
            }

            keysSequence.Add(keyCode);
        }
    }
我在这里操作换档和altGr键

现在是问题的原因了
GetCharsFromKeys
方法:

    [DllImport("user32.dll")]
    public static extern int ToUnicodeEx(uint virtualKeyCode, uint scanCode,
            byte[] keyboardState,
            [Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)]
            StringBuilder receivingBuffer,
            int bufferSize, uint flags, IntPtr dwhkl);

    public static string GetCharsFromKeys(Keys keys, bool shift, bool altGr)
    {
        var buf = new StringBuilder(256);
        var keyboardState = new byte[256];
        if (shift)
            keyboardState[(int)Keys.ShiftKey] = 0xff;
        if (altGr)
        {
            keyboardState[(int)Keys.ControlKey] = 0xff;
            keyboardState[(int)Keys.Menu] = 0xff;
        }

        // Because the Symbol LS2208 maps a US keyboard we need to convert the Keys correctly to chars
        ToUnicodeEx((uint)keys, 0, keyboardState, buf, buf.Capacity, 0, InputLanguage.FromCulture(new System.Globalization.CultureInfo("en-US")).Handle);

        return buf.ToString();
    }
我正在尝试将条形码扫描仪输入的密钥转换为字符串。对于大多数常用字符来说,这都能很好地工作(包括小写和大写字符和数字),而且键盘上数字上方的一些特殊字符也能工作(例如“$”)

但是当使用“12/34-56”这样的条形码进行测试时,我的输出结果是“12-34=56”

我认为这与我们和丹麦键盘之间的映射有关,但我不明白为什么?

有人能帮我做这个转换吗?

我无法用我想要的方式解决这个问题:
通过使用条形码扫描仪设置使用US键盘,并接收与设置的Windows区域键盘设置无关的字符

因此,我不得不将我的要求限制在:
“条形码扫描仪和Windows必须具有相同的键盘设置。”

这让一切变得简单多了。我仍然在实现IMessageFilter并同时使用VM_KEYDOWN和VM_MSG。下面是我使用的代码(尽管仍然缺少一些错误/超时处理):

公共类BarcodeScannerMessageFilter:IMessageFilter
{
公共事件事件处理程序BarcodeScannerReady;
private bool barcodeStarted=假;
私有StringBuilder barcodeBuilder=新StringBuilder();
公共条形码扫描器MessageFilter()
{
Application.AddMessageFilter(此);
}
#区域IMessageFilter成员
私有常量int WM_KEYDOWN=0x100;
私有常量int WM_MSG=0x102;
公共bool预过滤器消息(参考消息m)
{
if(m.Msg==WM_KEYDOWN)//使用KEYDOWN查找前缀和surfix
{
Keys-keyCode=(Keys)(int)m.WParam和Keys.keyCode;
如果(!barcodeStarted)//阻止F13捕获,直到上一步结束
{
//检查启动捕获键(F13)
if(keyCode==Keys.F13)
{
barcodeStarted=true;
返回true;
}
}
其他的
{
//检查结束捕获键(输入)
if(keyCode==Keys.Enter)
{
//使用条形码引发条形码捕获事件
RaiseBarcodeReadyEventAsync(barcodeBuilder.ToString());
//结束序列
barcodeBuilder.Clear();
barcodeStarted=false;
返回true;
}
}
}
else if(m.Msg==WM_Msg)//捕获所有字符消息
{
char c=(char)m.WParam;
//否则,只需将char附加到barcodeBuilder以生成条形码
条形码生成器。附加(c);
返回true;
}
返回false;
}
#端区
私有无效RaiseBarcodeReadyEventAsync(字符串条形码)
{
Task.Factory.StartNew(()=>
{
尝试
{
//生成条形码
Console.WriteLine(“F13激活的条形码[“+条形码+”]);
if(BarcodeScannerReady!=null)
{
BarcodeScannerReady(这是新的BarcodeScannerReadyEventArgs(条形码));
}
}
捕获(例外情况除外)
{
//如果需要,做一些错误日志记录
控制台写入线(ex);
}
});
}
}
公共类条形码扫描程序ReadyEventArgs:EventArgs
{
公共字符串条形码{get;private set;}
公共条形码扫描器ReadyEventArgs(字符串条形码)
{
这个。条形码=条形码;
}
}

我希望这能帮助其他人解决像我这样的问题。

之后试图综合键盘状态是一个失败的尝试。尤其是当你试图处理死键的时候。只是不要这样做,当你得到关键点时生成角色。Pinvoke GetKeyboardState()获取准确的状态。感谢您回答@HansPassant。我不确定我是否正确理解您的意思,但我尝试按照您的建议使用
GetKeyboardState
获取键盘状态,并使用输出作为
ToUnicodeEx
的输入。但结果仍然相同,带有奇怪的条形码输出。你能举个例子吗?
    [DllImport("user32.dll")]
    public static extern int ToUnicodeEx(uint virtualKeyCode, uint scanCode,
            byte[] keyboardState,
            [Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)]
            StringBuilder receivingBuffer,
            int bufferSize, uint flags, IntPtr dwhkl);

    public static string GetCharsFromKeys(Keys keys, bool shift, bool altGr)
    {
        var buf = new StringBuilder(256);
        var keyboardState = new byte[256];
        if (shift)
            keyboardState[(int)Keys.ShiftKey] = 0xff;
        if (altGr)
        {
            keyboardState[(int)Keys.ControlKey] = 0xff;
            keyboardState[(int)Keys.Menu] = 0xff;
        }

        // Because the Symbol LS2208 maps a US keyboard we need to convert the Keys correctly to chars
        ToUnicodeEx((uint)keys, 0, keyboardState, buf, buf.Capacity, 0, InputLanguage.FromCulture(new System.Globalization.CultureInfo("en-US")).Handle);

        return buf.ToString();
    }
public class BarcodeScannerMessageFilter : IMessageFilter
{
    public event EventHandler<BarcodeScannerReadyEventArgs> BarcodeScannerReady;

    private bool barcodeStarted = false;
    private StringBuilder barcodeBuilder = new StringBuilder();

    public BarcodeScannerMessageFilter()
    {
        Application.AddMessageFilter(this);
    }

    #region IMessageFilter Members
    private const int WM_KEYDOWN = 0x100;
    private const int WM_MSG = 0x102;
    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_KEYDOWN) // Use KeyDown to look for prefix and surfix
        {
            Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;

            if (!barcodeStarted) // Prevent F13 Capture until previous is ended
            {
                // Check for start capture key (F13)
                if (keyCode == Keys.F13)
                {
                    barcodeStarted = true;
                    return true;
                }
            }
            else
            {
                // Check for end capture key (Enter)
                if (keyCode == Keys.Enter)
                {
                    // Raise barcode capture event with barcode
                    RaiseBarcodeReadyEventAsync(barcodeBuilder.ToString());

                    // End sequence
                    barcodeBuilder.Clear();
                    barcodeStarted = false;
                    return true;
                }
            }
        }
        else if (m.Msg == WM_MSG) // Catch all char messages
        {
            char c = (char)m.WParam;
            // Else just append char to barcodeBuilder to generate barcode
            barcodeBuilder.Append(c);
            return true;
        }

        return false;
    }

    #endregion

    private void RaiseBarcodeReadyEventAsync(string barcode)
    {
        Task.Factory.StartNew(() =>
        {
            try
            {
                // Generate barcode
                Console.WriteLine("F13 activated barcode [" + barcode + "]");

                if (BarcodeScannerReady != null)
                {
                    BarcodeScannerReady(this, new BarcodeScannerReadyEventArgs(barcode));
                }
            }
            catch (Exception ex)
            {
                // Do some error logging if needed
                Console.WriteLine(ex);
            }
        });
    }
}

public class BarcodeScannerReadyEventArgs : EventArgs
{
    public string Barcode { get; private set; }

    public BarcodeScannerReadyEventArgs(string barcode)
    {
        this.Barcode = barcode;
    }
}