2011-01-27 8 views
6

Jeśli muszę wygenerować układ klawiatury, aby dostosować użytkownika do jego klawiatury, jak mogę to zrobić?Czy można utworzyć układ klawiatury identyczny z używaną klawiaturą?

Na przykład coś takiego:

enter image description here

francuski, szwedzki, angielski, kanadyjski, itp mają różne układy, racja. Czy to dużo pracy, czy tylko kwestia korzystania z jakichś wbudowanych klas regionalnych .NET?

+4

Wygląda to miłego dodatku dla kogoś, kto napisze;) – Oded

+0

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

+0

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). –

Odpowiedz

8

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.

+2

+1 To jest lepsze niż to, o czym dyskutowaliśmy w komentarzach do mojej odpowiedzi :) – GWLlosa

2

Nie ma wbudowanej klasy .NET, która zawiera układy klawiatury. Układy klawiatury są funkcją systemu operacyjnego, zazwyczaj Windows. Do czasu .NET włącza się, naciśnięty klawisz został przekształcony ze zdarzenia sprzętowego na programowy. Jeśli chcesz zobaczyć to w akcji, znajdź 2 układy klawiatury, w których klucz między nimi został przeniesiony. Skonfiguruj fałszywą aplikację z obsługą zdarzeń w zdarzeniu Key_Down, a następnie zwróć uwagę, że argumenty zdarzeń są identyczne; jeśli naciśniesz klawisz, który został naciśnięty, niezależnie od miejsca, w którym znajduje się klucz -.

+0

Dzięki, to ma sens. Ale jak sobie radzą z rosyjskimi, chińskimi klawiszami? Podobnie jak klucz zwraca Keys.A, itp. Również, w jaki sposób niektóre aplikacje robią to, gdzie są w stanie odtworzyć układ klawiatury używanej na ekranie. Czy klawiatura Windows OSD to robi? –

+0

Mogą one używać OSD Windows; ponieważ jest to narzędzie systemu operacyjnego, w rzeczywistości jest ono zgodne z układem; zobacz http://www.microsoft.com/windowsxp/using/accessibility/osklayout.mspx – GWLlosa

+0

Dzięki, ale jak mogą z niego korzystać? Czy nie jest to kolejna aplikacja, która wygląda na to, że nie ma w niej API? –

Powiązane problemy