当前位置:  开发笔记 > 开发工具 > 正文

将键码转换为相关的显示字符

如何解决《将键码转换为相关的显示字符》经验,为你挑选了2个好方法。

在C#Windows.Forms项目中,我有一个不提供KeyPressed事件的控件(它是一个COM控件 - ESRI映射).

它仅提供包含KeyEventArgs结构的KeyUp和KeyDown事件.

如何将KeyEventArgs中的信息转换为可显示的Unicode字符,考虑当前的活动键盘布局等?



1> Itai Bar-Hai..:

诀窍是使用一组user32.dll函数:GetWindowThreadProcessId,GetKeyboardLayout,GetKeyboardState和ToUnicodeEx.

    将GetWindowThreadProcessId函数与您的控件句柄一起使用以实现相关的本机线程ID.

    将该线程ID传递给GetKeyboardLayout以获取当前的键盘布局.

    调用GetKeyboardState以获取当前键盘状态.这有助于下一个方法根据修饰符状态决定生成哪个字符.

    最后,调用ToUnicodeEx函数,使用所需的虚拟键代码和扫描代码(这两个可以是相同的),当前的键盘状态,字符串构建器作为字符串持有者(保存结果),没有标志(0),以及当前的键盘布局指针.

如果结果不为零,则返回第一个返回的字符.

  public class KeyboardHelper
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
        private static extern int ToUnicodeEx(
            uint wVirtKey,
            uint wScanCode,
            Keys[] lpKeyState,
            StringBuilder pwszBuff,
            int cchBuff,
            uint wFlags,
            IntPtr dwhkl);

        [DllImport("user32.dll", ExactSpelling = true)]
        internal static extern IntPtr GetKeyboardLayout(uint threadId);

        [DllImport("user32.dll", ExactSpelling = true)]
        internal static extern bool GetKeyboardState(Keys[] keyStates);

        [DllImport("user32.dll", ExactSpelling = true)]
        internal static extern uint GetWindowThreadProcessId(IntPtr hwindow, out uint processId);

        public static string CodeToString(int scanCode)
        {
            uint procId;
            uint thread = GetWindowThreadProcessId(Process.GetCurrentProcess().MainWindowHandle, out procId);
            IntPtr hkl = GetKeyboardLayout(thread);

            if (hkl == IntPtr.Zero)
            {
                Console.WriteLine("Sorry, that keyboard does not seem to be valid.");
                return string.Empty;
            }

            Keys[] keyStates = new Keys[256];
            if (!GetKeyboardState(keyStates))
                return string.Empty;

            StringBuilder sb = new StringBuilder(10);
            int rc = ToUnicodeEx((uint)scanCode, (uint)scanCode, keyStates, sb, sb.Capacity, 0, hkl);
            return sb.ToString();
        }
    }



2> Stephane..:

Itai Bar-Haim的解决方案很不错,但死键有问题.

当您第一次调用CodeToString(INT扫描码)用死键的扫描码,ToUnicodeEx()的返回代码为-1,你的方法返回正确的值.

但是在下一次调用时,ToUnicodeEx()将返回2.结果字符串将在预期结果之前包含死键,然后是内存垃圾数据.

例如,我用^(死键)然后用$调用你的方法.第一个调用返回^(不错),但第二个调用返回^ $ azertyui.

你必须做两件事来解决这个问题:

1)您必须使用ToUnicodeEx()返回代码绝对值来设置StringBuilder的长度.因此,您可以避免在字符后获取垃圾数据.

2)当ToUnicodeEx()返回代码为-1时,必须将StringBuilder的第一个char作为方法的结果.然后你必须从键盘状态中删除死键:使用Space键的扫描码调用ToUnicodeEx().

还有一个问题,你可以有:如果键盘状态已经由谁打一个死键调用ToUnicodeEx(之前用户修改),返回的字符串将包含该预期值前死键字符.我找到的解决方法是在实际调用之前使用Space键的scancode调用ToUnicodeEx().

希望这有帮助!

推荐阅读
牛尾巴2010
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有