Можно ли создать раскладку клавиатуры, идентичную используемой клавиатуре? - PullRequest
7 голосов
/ 28 января 2011

Если мне нужно сгенерировать раскладку клавиатуры для настройки пользователя, которая выглядит как его / ее клавиатура, как я могу это сделать?

Например, что-то вроде этого:

enter image description here

Французский, шведский, английский, канадский и т. Д. Будут иметь разные макеты, верно.Это большая работа или просто вопрос использования каких-то встроенных региональных классов .NET?

Ответы [ 2 ]

10 голосов
/ 28 января 2011

Нажатие клавиши генерирует аппаратное событие, которое сообщает «код сканирования» операционной системе Windows. Этот код сканирования затем преобразуется в «код виртуальной клавиши» на основе кода сканирования вместе с другими факторами состояния клавиатуры ( Caps Lock состояние, Shift / Alt / Ctrl , а также любые ожидающие нажатия клавиш. Преобразованное значение VK - это то, что сообщается событием KeyDown и т. Д.

Преобразование из кода сканирования в код VK зависит от текущего языкового стандарта ввода - проще говоря, языковой стандарт ввода определяет отображение между кодами сканирования и кодами виртуальных клавиш. См. документацию MSDN для полного описания ввода с клавиатуры.

Путем изменения этого процесса поиска можно определить код сканирования, который соответствует каждому коду виртуальной клавиши (конечно, один и тот же код сканирования будет отображаться в несколько кодов VK из-за состояния shift / ctrl / alt и т. Д.). Win32 API предоставляет функцию MapVirtualKeyEx для выполнения этого сопоставления с помощью параметра MAPVK_VK_TO_VSC_EX. Вы можете использовать это, чтобы определить, какой код сканирования генерирует конкретный код ВКонтакте.

К сожалению, это все, что вы можете сделать программно - нет способа определить физическую раскладку клавиатуры или расположение клавиши для каждого кода сканирования. Однако большинство физических клавиатур подключены одинаково, поэтому (например) верхняя левая клавиша будет иметь одинаковый код сканирования на большинстве физических конструкций клавиатуры. Вы можете использовать это предполагаемое соглашение, чтобы вывести физическое местоположение, соответствующее коду сканирования, в зависимости от базовой физической раскладки клавиатуры (клавиша 101, клавиша 102 и т. Д.). Это не гарантировано, но это довольно безопасное предположение.

Следующий код является выдержкой из большой библиотеки для работы с клавиатурой, которую я написал (я собирался открыть ее, но у меня не было времени). Метод инициализирует массив (this._virtualKeyScanCodes), который индексируется кодом VK для заданного языкового стандарта ввода (хранится в this._inputLanguage, который объявлен как System.Windows.Forms.InputLanguage. Вы можете использовать массив для определения кода сканирования, который соответствует Код VK путем проверки, например, this._virtualKeyScanCodes[VK_NUMPAD0] - если код сканирования равен нулю, тогда этот VK недоступен на клавиатуре в текущей локали ввода, если он не равен нулю, это код сканирования, из которого можно вывести физический ключ.

К сожалению, дела обстоят немного сложнее, чем это, когда вы попадаете в области мертвых ключей (например, несколько комбинаций клавиш, которые производят символы с ударением). Это слишком сложно, чтобы разобраться прямо сейчас, но Майкл С. Каплан написал подробную серию сообщений в блоге , если вы хотите изучить это подробнее. Удачи!

private void Initialize()
{
    this._virtualKeyScanCodes = new uint[MaxVirtualKeys];

    // Scroll through the Scan Code (SC) values and get the Virtual Key (VK)
    // values in it. Then, store the SC in each valid VK so it can act as both a 
    // flag that the VK is valid, and it can store the SC value.
    for (uint scanCode = 0x01; scanCode <= 0xff; scanCode++)
    {
        uint virtualKeyCode = NativeMethods.MapVirtualKeyEx(
            scanCode, 
            NativeMethods.MAPVK_VSC_TO_VK, 
            this._inputLanguage.Handle);
        if (virtualKeyCode != 0)
        {
            this._virtualKeyScanCodes[virtualKeyCode] = scanCode;
        }
    }

    // Add the special keys that do not get added from the code above
    for (KeysEx ke = KeysEx.VK_NUMPAD0; ke <= KeysEx.VK_NUMPAD9; ke++)
    {
        this._virtualKeyScanCodes[(uint)ke] = NativeMethods.MapVirtualKeyEx(
            (uint)ke, 
            NativeMethods.MAPVK_VK_TO_VSC, 
            this._inputLanguage.Handle);
    }

    this._virtualKeyScanCodes[(uint)KeysEx.VK_DECIMAL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_DECIMAL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_DIVIDE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_DIVIDE, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_CANCEL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_CANCEL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);

    this._virtualKeyScanCodes[(uint)KeysEx.VK_LSHIFT] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RSHIFT] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LCONTROL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RCONTROL] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LMENU] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RMENU] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LWIN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_LWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RWIN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_RWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_PAUSE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_UP] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_UP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_DOWN] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_DOWN, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_MUTE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_VOLUME_MUTE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);

    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_NEXT_TRACK] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_NEXT_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PREV_TRACK] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_PREV_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PLAY_PAUSE] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_PLAY_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_STOP] =
        NativeMethods.MapVirtualKeyEx(
            (uint)KeysEx.VK_MEDIA_STOP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle);

    this._stateController = new KeyboardStateController();
    this._baseVirtualKeyTable = new VirtualKeyTable(this);
}

Изменить: см. Также этот вопрос , который похож на ваш.

2 голосов
/ 28 января 2011

Нет встроенного класса .NET, который содержит раскладки клавиатуры.Раскладки клавиатуры являются функцией операционной системы, обычно Windows.Ко времени включения .NET нажатая клавиша была преобразована из аппаратного события в программное.Если вы хотите увидеть это в действии, найдите 2 раскладки клавиатуры, в которых между ними была перемещена клавиша.Установите фиктивное приложение с обработчиком событий для события Key_Down, а затем обратите внимание, что аргументы события идентичны;если вы нажали клавишу - , вы нажали клавишу - независимо от того, где находится эта клавиша - .

...