Heh, to bardziej skomplikowane, niż sądziłem :).
Mój rzeczywisty kod wygląda mniej więcej tak. Na początku każdej klatki leci GetKeyboardState()
, który zapisuje stan klawiatury do zmiennej CurrentControlState
(które jest unsigned char[256]
, a stan może wynosić albo 1 - klawisz wciśnięty, albo 0 - klawisz nie jest wciśnięty). Następnie w pętli porównywane są kolejne indeksy z CurrentControlState
i PreviousControlState
(który to przechowuje stan klawiatury z ostatniej klatki). W zależności od wyniku porównania, zapalane są odpowiednie flagi dla każdego klawisza, przechowywane w osobnej tablicy:
struct BasicKey
{
bool Pressed;
bool Released:
bool Held;
}
Flagi Pressed
i Released
są jednorazowymi 'eventami' więc zostają zapalone tylko to końca klatki, w których nastąpiła zmiana flagi (dzięki czemu możliwe jest np. if (Key[VK_SPACE].Pressed)
, ktore będzie wykonane tylko jednokrotnie, niezależnie od tego w czasie ilu klatek klawisz rzeczywiście był wciśnięty). To oznacza, że obie te flagi na początku każdej kolejnej klatki muszą zostać zgaszone, więc u mnie wygląda to tak:
for (int I = 0; I < 256; I++)
{
if (Control[I].Pressed) Control[I].Pressed = false;
if (Control[I].Released) Control[I].Released = false;
if (CurrentControlState[I] != PreviousControlState[I])
{
if (CurrentControlState[I])
{
Control[I].Pressed = true;
Control[I].Held = true;
}
else
{
Control[I].Released = true;
Control[I].Held = false;
}
PreviousControlState[I] = CurrentControlState[I];
}
}
I to zerowanie Pressed
i Released
jest nieoptymalne, bo często będzie dochodziło do sprawdzania stanu tych flag bez potrzeby. Np. gdy klawisz jest cały czas nieaktywny, a więc PreviousControlState = 0
i CurrentControlState = 0
. Zastanawiałem się więc, czy w takiej sytuacji nie zastosować nadpisania zmiennej (bez sprawdzania), a w przypadku zmiany false
na false
kompilator mógłby po prostu to zoptymalizować.