convert a keycode to the relevant display character

后端 未结 3 1391
醉酒成梦
醉酒成梦 2021-02-10 02:02

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

It only supplies the KeyUp and KeyDown events,

3条回答
  •  失恋的感觉
    2021-02-10 02:18

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

    1. Use the GetWindowThreadProcessId function with your control handle to achieve the relevant native thread id.
    2. Pass that thread id to GetKeyboardLayout to get the current keyboard layout.
    3. Call GetKeyboardState to get the current keyboard state. This helps the next method to decide which character to generate according to modifiers state.
    4. 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();
            }
        }
    

提交回复
热议问题