Как преобразовать код виртуальной клавиши в символ в соответствии с текущей раскладкой клавиатуры? - PullRequest
19 голосов
/ 03 августа 2011

Я просмотрел несколько предыдущих вопросов по этому поводу, и лучший ответ, который я нашел до сих пор, выглядит примерно так:

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

Однако это не работает двумя способами:

  • Всегда возвращает заглавные буквы.Для Keys.A я ожидаю получить символ a, а для Keys.A | Keys.ShiftKey ожидаю получить A;однако, я, кажется, получаю A для обоих.

  • Кажется, он не учитывает раскладки клавиатуры.Например, для Keys.OemMinus мне всегда кажется, что я получаю символ -, даже если текущая раскладка клавиатуры немецкая, и я ожидаю, что эта клавиша вернет ß.

Какое для этого правильное решение?

Ответы [ 3 ]

23 голосов
/ 05 августа 2011

Правильным решением является ToUnicode функция WinAPI:

[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);

Один из способов обернуть это в разумный и удобный метод:

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

Теперь мы можем получать символы и получать ожидаемые результаты:

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 É

Можно также использовать ToUnicodeEx для извлечения символов для раскладки клавиатуры, которая не является активной в данный момент. Сигнатура та же, за исключением одного дополнительного параметра - идентификатора входного языкового стандарта, который можно получить с помощью функции LoadKeyboardLayout.

1 голос
/ 28 февраля 2014
    [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();
    }
1 голос
/ 04 августа 2011

Я думаю, что это может быть достигнуто с помощью этого метода:

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

Пример использования можно найти здесь: http://www.pcreview.co.uk/forums/toascii-function-t1706394.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...