转换的关键code到相关的显示字符字符、关键、code

2023-09-03 02:59:54 作者:拿根辣条砸死你

在一个C#Windows.Forms的项目,我有一个控制,不提供键pressed事件(这是一个COM控件 - ESRI地图)。

In a C# Windows.Forms project I have a control that does not supply the KeyPressed event (It’s a COM control – ESRI map).

它仅提供了的KeyUp和的KeyDown事件,包含的 KeyEventArgs 结构。

It only supplies the KeyUp and KeyDown events, containing the KeyEventArgs structure.

我如何可以转换在KeyEventArgs至可以显示的统一code人物有关的信息,以当前活动的键盘布局考虑,等等。?

How can I convert the information in KeyEventArgs to a displayable Unicode character, taking the current active keyboard layout into account, etc.?

推荐答案

的技巧是使用一组user32.dll中的功能:的ToUni$c$cEx 。

The trick is to use a set of user32.dll functions: GetWindowThreadProcessId, GetKeyboardLayout, GetKeyboardState and ToUnicodeEx.

使用 GetWindowThreadProcessId 的功能与您的控制手柄来实现相关本地线程ID。 在传递的主题ID GetKeyboardLayout ,以获得当前的键盘布局。 呼叫 GetKeyboardState ,以获得当前键盘状态。这有助于接下来的方法来决定哪些字符根据修饰符状态产生。 最后,调用与该 ToUni codeEX 功能想虚拟按键code和扫描code(这两个可以是相同的),当前的键盘状态下,一个字符串生成器作为一个字符串持有人(持有的结果),无标志(0),而目前键盘布局的指针。 Use the GetWindowThreadProcessId function with your control handle to achieve the relevant native thread id. Pass that thread id to GetKeyboardLayout to get the current keyboard layout. Call GetKeyboardState to get the current keyboard state. This helps the next method to decide which character to generate according to modifiers state. Finally, call the ToUnicodeEx function with the wanted virtual key code and scan code (those two can be the same), the current keyboard state, a string builder as a string holder (to hold the result), no flags (0), and the current keyboard layout pointer.

如果结果不为零,只返回第一返回字符

If the result is not zero, just return the first returned character.

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