2013-10-09 12 views
9

Zajmuję się tworzeniem aplikacji, w której użytkownik może zobaczyć coś i musi zareagować, klikając przycisk na klawiaturze. Czas reakcji jest kluczowy i im dokładniejszy, tym lepiej.Klucz WPF Dokładność czasu odpowiedzi

pisałem próbka App inf WPF tylko kilka linijek kodu, aby przetestować ustawienia domyślne:

namespace Test 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
    private Stopwatch sw; 
    public MainWindow() 
    { 
     InitializeComponent(); 
     sw = new Stopwatch(); 
     sw.Start(); 
     this.KeyDown += OnKeyDown; 
    } 

    private void OnKeyDown(object sender, KeyEventArgs keyEventArgs) 
    { 
     sw.Stop(); 

     lbl.Content = sw.ElapsedMilliseconds; 
     sw.Restart(); 
    } 
    } 
} 

lbl jest to tylko prosta etykieta.

Dziwne jest to, że gdy naciskam na przykład spację i przytrzymam ją, zmieni się wartość z zakresu: 30-33.

Więc nie mogę przewidzieć, jaka jest dokładność odpowiedzi? Czy nie można na przykład uzyskać dokładności 1 ms? Użytkownik trafia w przestrzeń iw tym samym czasie (na przykład dokładność 1 ms) Potrafię sobie z tym poradzić w procedurze obsługi zdarzeń?

Główne pytanie brzmi:

powiedzmy Mam obsługi zdarzeń key-dół:

Test_KeyDown(object sender, KeyEventArgs keyEventArgs) 
{ 
    time = stopwatch.elapsed(); 
    stopwatch.Restart(); 
} 

jaka jest minimalna wartość „czasu”, które mogą ewentualnie wystąpić? Czy mogę mieć pewność, że wartość czasu jest dokładna do 1 ms? W tej metodzie uruchamiam stoper, ale muszę czekać - jak długo - na odświeżenie GUI?

+0

Nie jestem pewien, co próbujesz zmierzyć, ani jak to robisz. 'KeyDown' nie jest wywoływane w sposób ciągły, gdy klawisz jest wyłączony (prawdopodobnie jest to" KeyPress "), więc przytrzymanie klawisza spacji nie powinno aktualizować etykiety więcej niż raz, prawda? Jeśli masz na myśli przytrzymanie klawisza spacji przed wyświetleniem okna, przetestuj kod pomiędzy konstruktorem, aż okno będzie w końcu aktywne i pompuje zdarzenia. – jods

+0

Z tego co wiem, wysłanie zdarzenia jest tak szybkie, jak to tylko możliwe i działa prawie tak samo, jak każda inna aplikacja Windows: klucz jest w dół obsługiwany przez system operacyjny, który następnie wysyła komunikat do kolejki komunikatów okna, który jest następnie pompowany, a odpowiednie zdarzenie jest wywoływane w kontrolce skupionej. Dokładność jest wystarczająco dobra w porównaniu do czasu reakcji człowieka, bez wykonywania pracy nad wątkiem interfejsu użytkownika. – jods

+0

Prędkość naciśnięcia klawisza zależy od konfiguracji okna częstości powtarzania klawiszy. http://windows.microsoft.com/is-is/windows-xp/help/adjust-the-character-repeat-rate – Tony

Odpowiedz

5

pierwsze, jeśli Stopwatch.IsHighResolution jest true, następnie Stopwatch wykorzystuje QueryPerformanceCounter i można go mierzyć przedziały czasowe < z rozdzielczością 1 ms.

Po drugie, po naciśnięciu i przytrzymaniu klawisza spacji system Windows rozpoczyna wielokrotne wysyłanie wiadomości WM_KEYDOWN, a stoper będzie mierzył interwał między tymi wiadomościami. Ten przedział jest określony przez klucz rejestru HKCU\Control Panel\Keyboard\KeyboardSpeed.

Jego domyślną wartością jest 31, która jest najszybszą prędkością powtarzania, co oznacza około 30 znaków na sekundę. Dlatego mierzysz przedziały około 1000/30 = 33 ms.

Jeśli ustawisz go na 0, czyli na najwolniejszą częstotliwość powtarzania, co oznacza około 2 znaków na sekundę, należy zmierzyć około. Interwały 500 ms. Przetestowałem Twój kod przy tym ustawieniu i uzyskałem 500 ms. (Nie zapomnij ponownie uruchomić systemu Windows po zmianie KeyboardSpeed!)

Musisz uchwycić pojedyncze zdarzenie keydown, a nie powtórzone zdarzenia, aby nie trzeba było zmieniać ustawienia KeyboardSpeed. Twój program powinien po prostu pokazać obiekt użytkownikowi, uruchomić stoper i zatrzymać go, jeśli wystąpi zdarzenie keydown. ElapsedMilliseconds da czas reakcji. Zmierz go kilka razy i użyj średniej.

Problem polega na tym, że nawet jeśli QueryPerformanceCounter dokładnie mierzy upływ czasu, występuje opóźnienie spowodowane przez klawiaturę i sam system Windows, co zwiększy zmierzony czas reakcji. Co więcej, opóźnienie nie jest stałe: jeśli system Windows jest zajęty w momencie, w którym powinien obsłużyć zdarzenie keydown, opóźnienie będzie większe. Jeśli poważnie podchodzisz do tego zadania, powinieneś skalibrować swój program.

Chodzi o to, że powinieneś kupić lub zbudować małe, oparte na mikrokontrolerach urządzenie elektroniczne, które włącza diodę LED i wykrywa czas, jaki upłynął między włączeniem diody LED a użytkownikiem naciśnięciem przycisku.Wykonaj 10-20 (im więcej, tym lepiej) pomiarów czasu reakcji za pomocą tego urządzenia i z tą samą osobą testującą, wykonaj kolejne 10-20 pomiarów w swoim programie. Różnica między tymi dwoma daje opóźnienie spowodowane przez klawiaturę i system Windows. Różnicę tę można odjąć od czasu reakcji mierzonego przez program.

(Ktoś mógłby zapytać, dlaczego nie powinieneś używać małego, ale precyzyjnego urządzenia elektronicznego zamiast aplikacji Windows, po pierwsze, oprogramowanie do produkcji i sprzedaży jest znacznie łatwiejsze i tańsze niż sprzęt do produkcji i sprzedaży. może być skomplikowany (np. szachownica), a złożone obiekty mogą być renderowane o wiele bardziej wydajnie na komputerze.)

+0

Mogę zasugerować, że zmiana rejestru użytkowników może nie być najlepszym sposobem na zrobienie tego, ale po prostu odczytanie tej wartości i wykrycie gospodarstwa określonego klucza. – SeToY

+0

@SeToY Zmieniłem rejestr tylko po to, aby przetestować moją hipotezę na temat interwału 33 ms mierzonego przez OP, kiedy przestrzeń była wciskana w sposób ciągły. Precyzja pomiaru przedziału czasu nie ma związku z tym, więc OP nie powinien modyfikować rejestru użytkownika. – kol

11

Twój test jest z pewnością nieważny, mierzy jedynie częstotliwość powtarzania klawiszy wskazaną przez kilku innych współpracowników. Ale przydaje się niezamierzona korzyść, możesz zobaczyć, że nie będziesz miał problemu z klawiaturą.

Większość zdarzeń w systemie Windows występuje z częstotliwością określoną przez częstotliwość przerwań zegara. Który domyślnie zaznacza 64 razy na sekundę, raz co 15.625 milisekund. To budzi jądro i idzie sprawdzić, czy coś trzeba zrobić, szukając pracy, aby przejść do rdzenia procesora. Najczęściej nie ma nic do zrobienia, a rdzeń jest zamykany za pomocą instrukcji HLT. Do następnego wystąpienia przerwania.

Tak więc problemem może być to, że Twój test nie może być dokładniejszy niż 15.625 milisekund. I twoja obserwacja pasuje, przez przypadek, to, co widzisz, było dwa razy tyle. Ale tak się nie dzieje i możesz użyć programu, aby to zobaczyć. Użyj panelu sterowania + klawiatura i dostosuj suwak częstości powtarzania. Zwróć uwagę, w jaki sposób możesz go dostosować i zmienić numer na wartości, które nie są wielokrotnością 15.625.

To nie jest całkowicie przypadek, kontroler klawiatury generuje również przerwanie, podobnie jak zegar. Masz pozytywny dowód, że to przerwanie jest już wystarczająco dobre, aby twój program ponownie się aktywował. I można powiedzieć, że kontroler klawiatury sam w sobie jest wystarczająco szybki do skanowania matrycy klawiatury. Twój pasek błędów z klawiatury nie będzie większy niż +/- 2 milisekundy, o szumie widocznym na wyświetlanym numerze. Jeśli masz klawiaturę, która skanuje wolniej, możesz ją wyeliminować za pomocą tego testu.


Znacznie większym problemem jest wideo. Karta wideo zwykle odświeża monitor LCD z szybkością 60 aktualizacji na sekundę. W najgorszym przypadku obiekt badany nie byłby w stanie uzyskać fizycznego obrazu o długości 17 msek. Same monitory LCD też nie są takie szybkie, tania ma czas reakcji 16 ms lub gorzej. Efekt uboczny Crystal in the Liquid nie jest w stanie szybko odwrócić.

Wyeliminowanie błędu częstotliwości odświeżania wymaga, aby program był synchronizowany z vertical blanking interval. Coś, co możesz zrobić z DirectX. Możesz znaleźć ekskluzywne monitory LCD o czasie odpowiedzi około 4 milisekund, popularne wśród graczy.

1

Chciałbym zwrócić uwagę na inne narzędzie do śledzenia Twojego czasu tutaj. Ponieważ rozważasz testowanie odpowiedzi aplikacji i jak ktoś wspomniał, że dotyczy to komunikatów systemu operacyjnego, możesz użyć Spy ++, aby zobaczyć czas tych wiadomości. Skopiowałem wyjście spacji do okna, którego słuchałem tylko z komunikatów Klawiatury, po włączeniu wszystkich wyjść. Nacisnąłem raz przestrzeń i wypuściłem ją tak szybko, jak tylko mogłem na klawiaturze USB, która przechodzi przez stację dokującą. Możesz zobaczyć, że przetworzenie w dół i w górę trwało ~ 0,05 ms.

<00001> 00090902 P WM_KEYDOWN nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000020 lParam:00390001 time:1:07:38.116 point:(183, 290)] 
<00002> 00090902 P WM_CHAR chCharCode:'32' (32) cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000020 lParam:00390001 time:1:07:38.116 point:(183, 290)] 
<00003> 00090902 P WM_KEYUP nVirtKey:VK_SPACE cRepeat:1 ScanCode:39 fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000020 lParam:C0390001 time:1:07:38.163 point:(183, 290)] 

Spy ++ to narzędzie dostarczane z Visual Studio. Możesz go znaleźć pod numerem C:\Program Files\Microsoft Visual Studio XYZ\Common7\Tools\spyxx.exe, gdzie XYZ ma 8, 9,0 i 10,0, które mogę potwierdzić.

Co można zrobić, aby dokładniej przetestować taktowanie, to słuchanie Spy ++ przy użyciu poleceń klawiaturowych i WM_PAINT lub czegoś podobnego, aby sprawdzić, jak szybko program reaguje na komunikat Klawiatura ze zmianą interfejsu użytkownika.

Na przykład poniżej jest czysty dziennik po kalkulatorze z 3+3 już, a następnie naciśnięcie Enter. Widać, że kalkulator był w stanie obliczyć i wyświetlić przed .062ms trwało między KeyDown i KeyUp do przetwarzania.

<00001> 00090902 P WM_KEYDOWN nVirtKey:VK_RETURN cRepeat:1 ScanCode:1C fExtended:1 fAltDown:0 fRepeat:0 fUp:0 [wParam:0000000D lParam:011C0001 time:1:19:12.539 point:(179, 283)] 
<00002> 00090902 S WM_PAINT hdc:00000000 [wParam:00000000 lParam:00000000] 
<00003> 00090902 R WM_PAINT lResult:00000000 
<00004> 00090902 S WM_PAINT hdc:00000000 [wParam:00000000 lParam:00000000] 
<00005> 00090902 R WM_PAINT lResult:00000000 
<00006> 00090902 S WM_PAINT hdc:00000000 [wParam:00000000 lParam:00000000] 
<00007> 00090902 R WM_PAINT lResult:00000000 
<00008> 00090902 S WM_PAINT hdc:00000000 [wParam:00000000 lParam:00000000] 
<00009> 00090902 R WM_PAINT lResult:00000000 
<00010> 00090902 P WM_KEYUP nVirtKey:VK_RETURN cRepeat:1 ScanCode:1C fExtended:1 fAltDown:0 fRepeat:1 fUp:1 [wParam:0000000D lParam:C11C0001 time:1:19:12.601 point:(179, 283)] 

edit- In Spy ++ Sugeruję przejście do Logging Options, które pokazuje okno dialogowe Message Options. Przejdź do zakładki Wiadomości, kliknij Wyczyść wszystko, zaznacz "Klawiatura", a następnie przewiń listę i wybierz WM_PAINT. W ten sposób masz tylko żądane wiadomości, w przeciwnym razie zostaniesz zalany nimi.