Нажатие клавиши генерирует аппаратное событие, которое сообщает «код сканирования» операционной системе 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);
}
Изменить: см. Также этот вопрос , который похож на ваш.