开发者

How to convert a virtual-key code to a character according to the current keyboard layout?

开发者 https://www.devze.com 2023-03-25 05:03 出处:网络
I have browsed several earlier questions about this, and the best answer I found so far is something like this:

I have browsed several earlier questions about this, and the best answer I found so far is something like this:

(char) WinAPI.MapVirtualKey((uint) Keys.A, 2)

However, this doesn't work in two ways:

  • It always returns capital letters. For Keys.A I expect to get the character a, while for Keys.A | Keys.ShiftKey I expect to get A开发者_开发技巧; however, I seem to get A for both.

  • It doesn't seem to take keyboard layouts into account. For example, for Keys.OemMinus I always seem to get the character -, even if the current keyboard layout is German, where I expect this key to return ß.

What is the correct solution for this?


The correct solution is the ToUnicode WinAPI function:

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

One way to wrap this into a sensible, convenient method would be:

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;
    }
    WinAPI.ToUnicode((uint) keys, 0, keyboardState, buf, 256, 0);
    return buf.ToString();
}

Now we can retrieve characters and actually get the expected results:

Console.WriteLine(GetCharsFromKeys(Keys.E, false, false));    // prints e
Console.WriteLine(GetCharsFromKeys(Keys.E, true, false));     // prints E

// Assuming British keyboard layout:
Console.WriteLine(GetCharsFromKeys(Keys.E, false, true));     // prints é
Console.WriteLine(GetCharsFromKeys(Keys.E, true, true));      // prints É

It is also possible to use ToUnicodeEx to retrieve the characters for a keyboard layout that is not the currently active one. The signature is the same except for one extra parameter, the input locale ID, which can be retrieved using the LoadKeyboardLayout function.


I think this can be achieved using this method:

[DllImportAttribute("User32.dll")]
public static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState,
        byte[] lpChar, int uFlags);

The example usage can be found here: http://www.pcreview.co.uk/forums/toascii-function-t1706394.html


    [DllImport("user32.dll")]
    static extern int MapVirtualKey(int uCode, uint uMapType);

    private void textBox1_OnKeyDown(object sender, KeyEventArgs e)
    {
        char c = (char)MapVirtualKey((int)e.KeyData, (uint)2);
        if (char.IsNumber(c)) DoSomething();
        else if (!char.IsNumber(c)) DoNothing();
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消