Kluczowe naciśnięcie generuje zdarzenie sprzętowe, które zgłasza "kod skanowania" do systemu operacyjnego Windows. Ten kod skanowania jest następnie przekształcone w „wirtualnego kod klucza” na podstawie kodu skanowania wraz z innymi czynnikami państwowymi klawiatura (Caps Lock stan, Shift,/Alt/Ctrl KeyState, a także wszelkie oczekiwaniu martwy klucz uderzeń). Przekonwertowana wartość VK jest określana przez zdarzenie KeyDown
itd.
Konwersja kodu skanowania na kod VK zależy od bieżących ustawień wejściowych - w uproszczeniu ustawienia narodowe określają mapowanie między kodami skanowania i kodami kluczy wirtualnych. Zobacz the MSDN documentation, aby uzyskać pełny opis wprowadzania danych z klawiatury.
Po odwróceniu tego procesu wyszukiwania możliwe jest określenie kodu skanowania, który odpowiada każdemu kodowi klucza wirtualnego (oczywiście ten sam kod skanowania zostanie odwzorowany na wiele kodów VK z powodu stanu zmiany/ctrl/alt itp.). Interfejs API Win32 udostępnia funkcję MapVirtualKeyEx
do wykonania tego mapowania za pomocą opcji MAPVK_VK_TO_VSC_EX
. Możesz użyć tego do określenia, który kod skanowania generuje konkretny kod VK.
Niestety, jest to tak daleko, jak można programowo - nie ma sposobu, aby ustalić fizyczny układ klawiatury lub lokalizację klucza dla każdego kodu skanowania. Jednak większość fizycznych klawiatur jest podłączonych w ten sam sposób, więc (na przykład) lewy górny klawisz będzie miał ten sam kod skanowania na większości fizycznych konstrukcji klawiatury. Za pomocą tej założonej konwencji można określić fizyczną lokalizację odpowiadającą kodowi skanowania, w zależności od podstawowego fizycznego układu klawiatury (101 klawiszy, 102 klawisze itp.). Nie jest to gwarantowane, ale jest to całkiem bezpieczne domysły.
Poniższy kod jest fragmentem większej biblioteki obsługi klawiatury, którą napisałem (miałem zamiar go otworzyć, ale nie miałem czasu). Metoda inicjuje tablicę (this._virtualKeyScanCodes
), która jest indeksowana przez kod VK dla danego ustawienia wejściowego (zapisanego w this._inputLanguage
, który jest zadeklarowany jako System.Windows.Forms.InputLanguage
. Możesz użyć tablicy do określenia kodu skanowania, który odpowiada kodowi VK, badając np. this._virtualKeyScanCodes[VK_NUMPAD0]
- jeśli kod skanowania wynosi zero, wówczas VK nie jest dostępny na klawiaturze w bieżącym ustawieniu wejściowym, jeśli jest niezerowy, jest to kod skanowania, z którego można wywnioskować klucz fizyczny.
Niestety, sprawy są nieco bardziej skomplikowane, gdy wchodzisz w obszary martwych kluczy (na przykład wiele kombinacji klawiszy, które tworzą znaki akcentowane). To wszystko jest zbyt skomplikowane, aby przejść teraz, ale Michael S. Kaplan napisał szczegółową serię blog posts, jeśli chcesz zbadać to dalej. Powodzenia!
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);
}
Edytuj: patrz również this question, który jest podobny do twojego.
Wygląda to miłego dodatku dla kogoś, kto napisze;) – Oded
Możesz uzyskać zdjęcia międzynarodowych układów klawiatury za pomocą obrazów Google. Spróbuj na przykład przejść do opcji [francuski układ klawiatury] (http://www.google.com/images?hl=pl&q=french+keyboard+layout). – Timwi
Tak, ale muszę narysować od zera z predefiniowanym stylem. Również jeśli używam układów, to będę musiał przechowywać wszystkie obrazy, prawda? Muszę to zrobić w czasie wykonywania dynamicznie (po uruchomieniu okna dostosowywania). –