Może to pomoże... (cytat z PDF-a)
Pobieranie stanu klawiszy
Otrzymywanie komunikatów o klawiszach jest biernym sposobem kooperacji z klawiaturą. Istnieją też metody, w których to aplikacja ma większą kontrolę nad tym procesem i sama sprawdza stany poszczególnych klawiszy.
O takim sprawdzaniu opowiemy sobie w tym paragrafie. Obejmie to między innymi dokładne omówienie funkcji GetKeyState() i GetAsyncKeyState(), z którymi zapoznaliśmy się już w podobnej sytuacji dotyczącej myszy.
Stan pojedynczego klawisza
Jak pamiętamy, sprawdzaniu stanu pojedynczego klawisza służy funkcja GetKeyState():
SHORT GetKeyState(int nVirtKey);
Należy jej podać kod kontrolowanego, wirtualnego klawisza. Jest to jedna ze stałych VK_, ewentualnie (w przypadku klawiszy liter i liczb) kod ASCII odpowiedniego znaku.
W zamian dostajemy… wynik :) Jest nim wartość typu SHORT (2 bajty) i składa się z dwóch części:
Ø górny bajt (czytany przez HIBYTE()) po zrzutowaniu na typ logiczny[12] informuje o wciśnięciu klawisza. true, TRUE lub ogólnie wartość różna od zera wskazuje na to, że klawisz jest wciśnięty. Nietrudno się domyślić, że zero znaczy coś przeciwnego :D
Ø dolny bajt (LOBYTE()) daje wiedzę o tym, czy klawisz jest włączony. Większości klawiszy nie dotyczy ta własność, jest ona ważna tylko dla „locków”: Num Lock, Caps Lock i Scroll Lock[13]. Podobnie jak wyżej, logiczna prawda wskazuje na włączenie danego klawisza, fałsz - przeciwnie.
Trzeba jeszcze powiedzieć jedną bardzo ważną rzecz na temat tej funkcji - skąd ona bierze stan klawiszy?… Wcale nie „pyta” o niego samej klawiatury (tak robi GetAsyncKeyState()), lecz uzyskuje go na podstawie kolejki komunikatów. Decyduje tu ostatnio otrzymany komunikat klawiatury, dotyczący sprawdzanego klawisza. Uzyskiwane informacje są więc zależne od komunikatów, jakie otrzymuje wątek (tzn. cała aplikacja - najczęściej) i nie dotyczą globalnego stanu klawiatury. Nie pochodzą z poziomu przerwań sprzetowych, lecz zdarzeń systemowych.
Czy jest to wada? Nieszczególnie. GetKeyState() używamy głównie do sprawdzania stanu takich klawiszy jak Shift i Ctrl podczas przetwarzania zdarzeń innych klawiszy, np.:
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_F1:
if (HIBYTE(GetKeyState(VK_SHIFT))
// kombinacja Shift+F1
else
// samo F1
break:
// itd.
}
}
Stan tych innych klawiszy otrzymujemy w komunikatach i to właśnie ich powinniśmy używać do reakcji na wciśnięcia i zwolnienia klawiszy w normalnych aplikacjach.
Stan całej klawiatury
W Windows API znajdziemy też funkcję pobierająca stan wszystkich klawiszy - GetKeyboardState():
BOOL GetKeyboardState(PBYTE lpKeyState);
Działa ona mniej więcej tak, jak zastosowanie GetKeyState() dla parametrów z przedziału od zera do 256. GetKeyboardState() przyjmuje mianowicie tablicę 256 bajtów, której indeksami są kody kolejnych wirtualnych klawiszy.
Wynikiem funkcji jest TRUE dla operacji zakończonej powodzeniem i zero (FALSE) w innym przypadku.
Jest jeszcze funkcja SetKeyboardState(), pozwalająca ustawić chwilowy stan klawiatury dla danego wątku. Możesz o niej poczytać w MSDN.
Lepszą formą zmiany stanu klawiatury jest aczkolwiek użycie symulowane wejścia, czyli funkcji SendInput().
Asynchroniczne pobieranie stanu klawisza
Drugą z funkcji stworzonych do uzyskiwania stanu pojedynczego klawisza jest GetAsyncKeyState():
SHORT GetAsyncKeyState(int vKey);
Tak samo przynosimy jej kod wirtualnego klawisza, który chcemy sprawdzać. A co z wynikiem? Również jest podzielony na dwie części po jednym bajcie każda:
Ø starszy bajt (HIBYTE()) znaczy to samo, co w GetKeyState(): po konwersji na wartość logiczną informuje o wciśniętym klawiszu (true) lub zostawionym w spokoju (false)
Ø młodszy bajt (LOBYTE()) wskazuje, czy klawisz był wciskany (logiczna prawda) od czasu ostatniego wywołania GetAsyncKeyState(). Trzeba jednak wiedzieć, że to ostatnie wywołanie wcale nie musi pochodzić z naszej aplikacji i dlatego omawiana tu wartość nie ma praktycznego sensu
Co różni tę funkcję od GetKeyState()? Pewne wskazówki co do tego mogłeś wyczytać między wierszami powyższego opisu i w akapicie o tamtej pokrewnej funkcji. Powiedzmy jednak wprost, o co chodzi.
Otóż GetAsyncKeyState(), czyniąc zadość swej nazwie, pobiera tzw. asynchroniczny stan klawisza. Asynchroniczy to znaczy niezależny od wątku, a mówiąc po ludzku - globalny dla całego systemu oraz niezależny od kolejki komunikatów. Funkcja ta pobiera dane bezpośrednio od sprzętu, niejako z pominięciem mechanizmu zdarzeń Windows. Przejawia się to chociażby w tym, że kontroluje stan fizycznych, a nie logicznych przycisków myszki, o czym wspomniałem przy pierwszym spotkaniu z tą funkcją.
Ze względu na ten sposób działania GetAsyncKeyState() jest przydatna w programach czasu rzeczywistego. Będziemy więc używać tej funkcji do pobierania stanu klawiszy w naszych grach - przynajmniej na początku. Przygotuj się zatem na wiele długich i owocnych spotkań z funkcją GetAsyncKeyState() ;)</span>