Wie in der MaxGui den Event_KeyDown beschleunigen?

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

Midimaster

Betreff: Wie in der MaxGui den Event_KeyDown beschleunigen?

BeitragSa, Apr 16, 2011 16:06
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo ich habe ein Problem mit MaxGui, vielleicht weiss ja einer einen Ratschlag...

Ich benötige unter MaxGui eine sehr schnelle Abfrage der Tastatur. Das ganze wird Teil eines Rhythmus-Trainers für Musiker. Man bekommt einen Rhythmus vorgespielt und soll ihn mehrhändig nachspielen. Dafür benötige ich eine sehr schnelle Erkennung von gleichzeitigen Computer-Tastatur-Anschlägen.

Mein Problem dabei: Der EventHandler der MaxGui liefert immer nur 1 Event zu einer Zeit und bei mehreren Events kommen die nacheinander.

Nun habe ich festgestellt: Wenn ich auf der Computer-Tastatur 3 Tasten absolut gleichzeitig drücke, kommen die Events im Programm mit jeweils 40msec Verzögerung an. d.h. der letzte der 3 Events ist erst nach 80-120msec da. Für eine Bewertung des Rhythmus-Gefühls ein leider nicht mehr akzeptabler Fehler.

Meine Fragen nun:

1. Könnt Ihr das auf Euren Rechnern bestätigen? Es könnte ja auch an meinem alterschwachen Rechner oder der Tastatur liegen. Bitte testet das mal für mich und schreibt mir hier die Ergebnisse...

hier der Testcode:
BlitzMax: [AUSKLAPPEN]
SuperStrict 
Import MaxGUI.Drivers
Global LastDown% , Wert%
CreateTimer 60
Global Window:TGadget = CreateWindow("Test Keydown" , 0 , 0 ,600 , 400 , Null , WINDOW_DEFAULT|WINDOW_CLIENTCOORDS|WINDOW_CENTER)
Global Canvas:TGadget = CreateCanvas(0 , 0 , 600 , 400, Window)
ActivateWindow Window
ActivateGadget Canvas
While WaitEvent()
Select EventID()
Case EVENT_KEYDOWN
Wert = (MilliSecs()-lastdown)
If Wert<500 Then
Print "keydown" + wert
EndIf
LastDown=MilliSecs()
End Select
Wend


2. Gibt es eine Lösung für das Problem "Tastaturabfrage"?

Danke

Midimaster

p.s.
natürlich kann das Programm auch Eingaben über MIDI oder Audio-In. Dort bekomme ich bereits akzeptable Werte. In der Frage hier geht es mir ausschließlich um die Computer-Tastatur.
 

-Phoenix-

BeitragSa, Apr 16, 2011 17:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Meinst du so?

BlitzMax: [AUSKLAPPEN]
SuperStrict 
Import MaxGUI.Drivers
Global LastDown% , Wert%
CreateTimer 60
Global Window:TGadget = CreateWindow("Test Keydown" , 0 , 0 ,600 , 400 , Null , WINDOW_DEFAULT|WINDOW_CLIENTCOORDS|WINDOW_CENTER)
Global Canvas:TGadget = CreateCanvas(0 , 0 , 600 , 400, Window)
ActivateWindow Window
ActivateGadget Canvas

enablepolledinput

While WaitEvent()
Select EventID()
End Select


If KeyDown(KEY_DOWN)
Wert = (MilliSecs()-lastdown)
If Wert<500 Then
Print "keydown" + wert
EndIf
LastDown=MilliSecs()
EndIf
If KeyDown(KEY_UP)
Wert = (MilliSecs()-lastdown)
If Wert<500 Then
Print "keydown" + wert
EndIf
LastDown=MilliSecs()
EndIf
If KeyDown(KEY_LEFT)
Wert = (MilliSecs()-lastdown)
If Wert<500 Then
Print "keydown" + wert
EndIf
LastDown=MilliSecs()
EndIf
If KeyDown(KEY_RIGHT)
Wert = (MilliSecs()-lastdown)
If Wert<500 Then
Print "keydown" + wert
EndIf
LastDown=MilliSecs()
EndIf

Wend



enablepolledinput lässt dich die standard befehle wie keydown nutzen
  • Zuletzt bearbeitet von -Phoenix- am Sa, Apr 16, 2011 18:22, insgesamt einmal bearbeitet

mpmxyz

BeitragSa, Apr 16, 2011 18:14
Antworten mit Zitat
Benutzer-Profile anzeigen
@-Phoenix-
Das wird wahrscheinlich keine Lösung sein, da sowohl brl.PolledInput als auch brl.EvenQueue auf brl.Event aufbauen.

Ich vermute, dass es an der Rate, mit der die Tastatur abgefragt wird, liegen kann.
Bei mir sind nämlich die Verzögerungen in etwa Vielfache von 8 ms, wenn ich die Tasten nicht zeitgleich drücke. Ansonsten kommen die Events zeitgleich an.
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

-Phoenix-

BeitragSa, Apr 16, 2011 18:17
Antworten mit Zitat
Benutzer-Profile anzeigen
versuch mein code und sein und du wirst den unterschied sehen

bei seinem code ist es 1 event auf aufmal, also über mehrere Frames verteilt
meinen code gibt continuierlichen output jede frame, also kann man alle tasten in der gleichen Frame abfragen

daher kein delay

ich krieg bei seinem code bei 4 tasten 20 - 30 delay pro taste
bei meinem 0 - 3

mpmxyz

BeitragSa, Apr 16, 2011 18:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Kannst du mir einen Grund nennen, warum sein Code über mehrere Frames verteilt die Events aufspürt? (Hinweis: Es gibt hier keine Frames.)
Bei mir gibt es kaum eine Verzögerung über brl.EventQueue. (0 ms oder 8 ms)
Bei deinem Code gibt es in etwa genau so viel Verzögerung. (Du solltest auch KeyHit anstelle von KeyDown nutzten, wenn du die beiden Codes vergleichbar halten bzw. eine Aussage treffen möchtest.)
Dass ein anderes Ergebnis dort herauskommt, macht irgendwie wenig Sinn, da beide Möglichkeiten die gleichen Möglichkeiten nutzen.
mfG
mpmxyz
PS: Willkommen im Blitzforum!
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

-Phoenix-

BeitragSa, Apr 16, 2011 19:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Der Grund ist weil bei seinem code nur 1 event pro loop geschaut wird, bei meinem werden so viele tasten in einem loop abgefragt wie man will, das geht auch mit keyhit

natürlich ist der unterschied normalerweise klein, aber falls man am loop später den waittimer ansetzt oder man viele andere events kriegt von gadgets wird der unterschied merkbar

Ich kann nicht erklären warum der delay bei seinem code auf meinem pc höher ist als bei dir, aber weil polledinput einen eigenen eventstack hat sollte es delay minimieren

mpmxyz

BeitragSa, Apr 16, 2011 19:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Schleifen an sich sind so gut wie geschenkt.
Daher ist es auch relativ egal, ob man Abfragen in verschiedenen Durchläufen oder direkt hintereinander abarbeitet. Waittimer ist bei einer Event-Schleife in der Tat eine schlechte Idee. Daher nutzt man dann das Event "EVENT_TIMERTICK".
Ob man nun zwischen jeder einzelnen Abfrage andere Events abarbeitet oder zwischen einer Gruppe an Abfragen, - etwas anderes macht deine Variante nicht - ist relativ egal.
Die eine Variante erkennt die Tastenbetätigungen gleichzeitig, die andere zeitlich versetzt.
Die eine Variante schreibt bei Events direkt in ein Array, die andere fügt die Events in eine (durch ein Array gebildete) Liste ein. (Ein Stack kommt bei keiner Variante vor.)
Die größten Unterschiede liegen dabei im Mikrosekundenbereich.
Der einzige 'richtige' Unterschied liegt in einer C-Zeile: "MsgWaitForMultipleObjects( 0,0,0,INFINITE,QS_ALLINPUT );"
Diese sollte aber bei richtiger Funktionsweise pünktlich zum Entstehen eines Events aufhören.
->Beide Möglichkeiten sind theoretisch gleichwertig. Daher sind die unterschiedlichen Ergebnisse ziemlich seltsam.
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer

Midimaster

BeitragSo, Apr 17, 2011 14:22
Antworten mit Zitat
Benutzer-Profile anzeigen
@Phoenix

Oh! Danke...ich hatte ja keine Ahnung, dass trotz MaxGUI die klassischen BlitzMax KeyDown noch ebenso parallell funktionieren. Das hilft mir tatsächlich weiter. Da bastle ich mir was d'raus.

dieses "enablepolledinput" wird beim Editor nicht gelb und ist auch nicht unter den Befehlen aufgelistet. Ist es regulärer Bestandteil des brl. ? Ist es über alle Betriebsysteme vorhanden? Handle ich mir darüber irgendwelche Nachteile ein? Werden die anderen Events (Button-Events, Scrolls..., Paints...) noch wie vorher erscheinen?

Gibt es tiefergehende Informationen über diesen "Befehl"? Im der Forumssuche kommt gar nichts zu dem Thema.


Vielen Dank jedenfalls an Euch beide erst mal!

mpmxyz

BeitragSo, Apr 17, 2011 14:39
Antworten mit Zitat
Benutzer-Profile anzeigen
@Midimaster
Der Befehl existiert in brl.PolledInput. (Ich sehe immer in den Modul-Code, wenn ich Fragen habe.)
Er aktiviert die entsprechenden Input-Befehle für eine bestimmte bzw. bei Angabe von Null für jede Quelle.
Da er in anderen Modulen verwendet wird, ist es eher unwahrscheinlich, dass er plötzlich wegfällt.
BlitzMax: [AUSKLAPPEN]
Function EnablePolledInput( source:Object=Null )
If enabled Return
inputSource=source '<-inputSource wird als Filter für die Eingaben verwendet.
FlushKeys
FlushMouse
AddHook EmitEventHook,Hook,Null,0 '<- Hiermit werden die Events überwacht.
enabled=True
End Function

Wie jede der Event-Funktionen ist auch diese vom Betriebssystem unabhängig.
Die Events werden dabei nicht beeinflusst.
Es kann aber vorkommen, dass bei EndGraphics oder beim Vernichten eines OpenGL-Kontextes "DisablePolledInput" aufgerufen wird. Solange du aber nicht mehrere OpenGL-Kontexte verwendest oder ein "richtiges" Grafikfenster schließt, wird nichts passieren.
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer

Midimaster

BeitragSo, Apr 17, 2011 19:04
Antworten mit Zitat
Benutzer-Profile anzeigen
ich mache da jetzt gerade so meine tests mit eurem code und glaube, ich bin da auf einen denkfehler gestoßen.

Die KEY_DOWN-Abfrage klappt ja nur, weil doch immer irgend ein Event gemeldet wird. z.b. der EVENT_TIMERTICK.

Aber theoretisch könnte die Event-Meldung ja zufällig auch aufgrund des EVENT_KEYDOWN erfolgen.

Jedesmal, wenn dies der Fall ist, verschluckt euer Code eine Meldung, da der EVENT_KEYDOWN den "gepollten" Keydown schon gelöscht hat.

Dies geschieht zwar aufgrund des häufig erscheinenden Timers() nur selten, aber gelegentlich dürfte so ein Event verloren gehen , oder?

Man bemerkt es, wenn man den Timer mal abschaltet:
BlitzMax: [AUSKLAPPEN]
SuperStrict 
Import MaxGUI.Drivers
Global LastDown% , Wert%
'CreateTimer 120
Global Window:TGadget = CreateWindow("Test Keydown" , 0 , 0 ,600 , 400 , Null , WINDOW_DEFAULT|WINDOW_CLIENTCOORDS|WINDOW_CENTER)
Global Canvas:TGadget = CreateCanvas(0 , 0 , 600 , 400, Window)
ActivateWindow Window
ActivateGadget Canvas

enablepolledinput

While WaitEvent()
Print "E"+EventID()
If KeyDown(KEY_DOWN)
Wert = (MilliSecs()-lastdown)
If Wert<500 Then
Print "keydown" + wert
EndIf
LastDown=MilliSecs()
EndIf
Select EventID()
Case EVENT_KEYDOWN
'ScanTasten EventID(),1
Print "keydown nur bei event " + (MilliSecs()-lastdown)
Case EVENT_WINDOWCLOSE
If EventSource()=Window Then
End
EndIf
End Select

Wend
 

-Phoenix-

BeitragSo, Apr 17, 2011 19:09
Antworten mit Zitat
Benutzer-Profile anzeigen
Ersetz WaitEvent() durch PollEvent() und du hast auch as problem gelöst
dann wird der code nicht beim waitevent warten bis ein event kommt um was zu tun sondern non stop loopen

Midimaster

BeitragSo, Apr 17, 2011 19:13
Antworten mit Zitat
Benutzer-Profile anzeigen
das ist aber gar keine gute Idee...

da hätte ich ja dauernd 100% Auslastung, oder?
 

-Phoenix-

BeitragSo, Apr 17, 2011 20:17
Antworten mit Zitat
Benutzer-Profile anzeigen
Ja, hättest du, es sei denn du machst ein timer oder delay, es gibt halt keine wunderlösung

WaitEvent() macht intern auch nichts anderes als dauernd zu pollen mit einem delay dahinter, ich denke daher kommt auch der delay bei den tasten events (also der von paar millisekunden)
Ich könnte auch falsch liegen
Aber keine angst sogar delay 1 reicht um die auslastung auf 0% zu bringen (hängt vom code ab) und 1 millisekunde macht beim timing nichts aus

mpmxyz

BeitragMo, Apr 18, 2011 9:36
Antworten mit Zitat
Benutzer-Profile anzeigen
@Midimaster
EVENT_KEYDOWN und KeyDown() sind untschiedliche Dinge!
Wenn du EVENT_KEYDOWN direkt ersetzen möchtest, musst du KeyHit() nutzen. (Das Event wird bei jeder Betätigung einer Taste ausgelöst, während KeyDown angibt, ob die Taste in dem Moment gedrückt gehalten wird.)
Außerdem: WaitEvent() beeinflusst das PolledInput-Modul in keiner Weise. Beide nutzen "Hooks", um die Events zu beachten. Dabei gehen keine Events verloren.
Bei mir gibt es auch keine Probleme, die auf gegenteiliges hindeuten. Drückst du vielleicht nicht lang genug die Taste? (Das erste Mal KeyDown(...)=True wird durch die Zeitabfrage verschluckt!)
@-Phoenix-
WaitEvent nutzt kein Delay, sondern WaitSystem. Wink
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer

Midimaster

BeitragMo, Apr 18, 2011 15:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Vielen Dank noch mal an Euch beide. Jetzt klären sich einige Ungereimtheiten. Eure Diskussion war sehr hilfreich: nur so kam ich auf die eigentliche Fehlerursache.

Durch das "Pollen" wurde meine Tastaturabfrage nun nicht wirklich beschleunigt! So bin ich drauf gekommen, dass meine Funk-Tastatur die Daten so träge sendet! Sie sendet nur alle 40msec eine Nachricht.

Teste ich auf der Notebook-Tastatur komme ich via GUI-Events auch ohne Tricks auf unter 2msec für ein 3-Tasten-Paket. Wegen der "seriellen" Art der GUI-Events "verliere" ich hier jeweils 1 msec pro Taste. Durch das "Pollen" liese sich da für weitere gleichzeitig gedrückte Tasten nur dann etwas beschleunigen, wenn die Tastatur die Daten wirklich schon bereitstellen konnte.

Die scheinbar tollen Messergebnisse stammen immer aus dem Zeitunterschied zwischen 1. und 2. KeyDown-Check derselben Taste. Setzt man gleich beim ersten Mal ein "gedrückt"-Flag, dann wird deutlich, dass zwischen den drei gleichzeitig gedrückten Tasten nach wie vor die selbe Zeit benötigt wird wie durch die reine GUI-Event-Abfrage.

Fazit: Das Ankommen der Tastatur-Daten und die Geschwindigkeit der Tastaturevents scheinen sehr vom Tastatur-Modell und der jeweiligen Verbindung zum Computer abzuhängen. Das Einschalten von EnablePolledInput bringt bei einer langsamen Tastatur keinen Vorteil.


Vielen Dank für eure Erläuterungen.

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group