14. Arbeit mit der Tastatur
14.2 Schreiben eines Tastaturhandlers Zur Entgegennahme von Nutzereingaben über die Tastatur stehen dem R-BASIC Programmierer drei Möglichkeiten zur Verfügung:
^14.1 Überblick über TastaturereignisseUm mit den Tastaturhandlern arbeiten zu können sollte man mindestens in Grundzügen verstanden haben, wie GEOS mit Tastaturereignissen umgeht. Im Folgenden wir das Prinzip erklärt, für vollständige Informationen muss auf weiterführende Literatur verweisen werden.Es gibt genau drei Situationen, in denen ein Tastaturereignis erzeugt wird:
Bei den erweiterten ASCII-Codes sind die höherwertigen 8 Bit immer gesetzt, die unteren 8 Bit enthalten die Information, z.B. den Steuercode der zur gedrückten Taste gehört. Man kann ihn abfragen indem man die oberen 8 Bit mit der AND-Operation ausblendet. |
code = character AND 255 ' d.h. AND &hFF |
Diese Codes sind oft, aber nicht immer identisch mit den für das PRINT-Kommando verwendeten Steuercodes (siehe Anhang, Kapitel A). Zum Beispiel ist der PRINT Code für "Cursor nach links" 14 (&h0E), der Tastencode ist jedoch 147 (&h93). Anmerkungen zu Punkt 3: Drückt der Nutzer die Tasten Shift + 'a' wird der Buchstabe 'A' erzeugt. Die Shift-Taste ist damit ausgewertet und wird NICHT mehr in das Tastaturereignis aufgenommen.Es ist nun möglich sich unter R-BASIC an bestimmten Stellen in den Tastaturhandler einzuklinken und Tastaturereignisse zu "überschreiben". Das heißt man kann sie mitlesen, bei Bedarf verhindern dass sie weitergeleitet werden oder auch dem System eigene "Ereignisse" unterschieben. Der folgende Abschnitt beschreibt die Konzepte dahinter. ^14.2 Schreiben eines TastaturhandlersUm sich in das Tastaturhandling einzuklinken muss man einen Tastaturhandler (auch Keyboardhandler) schreiben. Dazu stehen die folgenden Instancevariablen zur Verfügung:
Der OnKeyPressed Handler wird gerufen, wenn das Objekt ein Tastaturereignis erhält. Er muss als KeyboardAction deklariert werden. Die inputFlags bestimmen, in welchen Fällen das Ereignis vom Objekt selbst, vom BASIC Handler oder von beiden behandelt werden soll. Für die folgenden Objektklassen sind Keyboardhandler und inputFlags definiert:
Einige der Objekte (z.B. InputLine und Memo) behandeln das Ereignis per default selbst, andere (z.B. View oder VisContent) leiten es nur an untergeordnete Objekte weiter. Details oder Besonderheiten zum Tastaturhandling der einzelnen Objekte finden Sie in den entsprechenden Kapiteln zu den Objekten.
OnKeyPressedDer OnKeyPressed Handler wird aufgerufen, wenn das Objekt ein Tastaturereignis erhält. Der Handler muss als KeyboardAction deklariert sein. Der BASIC Handler wird erst gerufen nachdem das Objekt das Ereignis selbst behandelt bzw. an untergeordnete Objekte weitergeleitet hat.Syntax UI- Code: OnKeyPressed = <Handler> Schreiben: <obj>.OnKeyPressed = <Handler> KeyboardAction Handler haben die folgenden Parameter:
Folgende Werte bzw. Konstanten sind definiert:
Anmerkungen:
inputFlagsMit Hilfe der Instancevariablen inputFlags kann man steuern, ob ein Tastaturereignis vom Objekt selbst, vom BASIC Handler oder von beiden behandelt werden soll.Syntax UI-Code: inputFlags = bits bits: Kombination der IF_-Werte laut Tabelle unten Lesen: <numVar> = <obj>.inputFlags Schreiben: <obj>.inputFlags = bits Per default ist inputFlags Null, d.h. Tastaturereignisse werden sowohl vom Objekt als auch vom BASIC-Handler (so einer gesetzt ist) behandelt. Als Faustregel gilt: Setzen Sie nur die Bits, die sie auch wirklich für die Programmfunktion benötigen.
Das Tastaturhandling wird von einem BitmapContent gemacht. Da dieses keinen eigenen Tastaturhandler und keine Children hat benötigen wir kein IF_IGNORE~ Bits. Außerdem wollen wir bei jedem Tastendruck nur genau einen Schritt machen, auch wenn die Taste länger gedrückt ist. Deswegen leiten wir REPEAT_PRESS und RELEASE-Ereignisse nicht an den BASIC Handler weiter. Die SUB's MoveWillyUp usw. müssen natürlich irgendwo definiert sein. UI-Code |
BitmapContent GameBoard
OnKeyPressed = KeyHandler
inputFlags = IF_HANDLER_NO_REPEAT_PRESS + \
IF_HANDLER_NO_RELEASE
End Object
|
| BASIC Code |
Include "KeyCodes" ' Konstanten KEY_UP usw. einbinden
KEYBOARDACTION KeyHandler
ON character SWITCH
CASE KEY_UP: ' Cursor nach oben
MoveWillyUp
END CASE
CASE KEY_DOWN: ' Cursor nach unten
MoveWillyDown
END CASE
CASE KEY_LEFT: ' Cursor nach links
MoveWillyLeft
END CASE
CASE KEY_RIGHT: ' Cursor nach rechts
MoveWillyRight
END CASE
END SWITCH
End ACTION
|
^14.3 Simulieren von Tastaturereignissen
Die Methoden KbdEvent und KbdEventWithScancode erzeugen ein Tastaturereignis und senden es an das entsprechende Objekt. Diese Methoden sind für alle Objektklassen definiert.
In den meisten Fällen reicht es aus, KbdEvent zu verwenden.
KbdEventSyntax im BASIC Code: <obj>.KbdEvent character, keyState, keyFlags character: ASCII-Code oder erweiterter ASCII-Code keyState: Kombination von KS_~Bits (siehe OnKeyPressed) keyFlags: Eines der KF_~ Bits (siehe OnKeyPressed) Die übergebenen Werte character, keyState und keyFlags werden 1:1 als Parameter an den Tastaturhandler des Objekts und an den BASIC Tastaturhandler weitergegeben. Im Unterschied zum echten Tastendruck übergibt KbdEvent als "scanCode" jedoch den Wert Null an das Objekt, so dass sowohl das Objekt als auch der BASIC Handler echte von vorgetäuschten Tastendrücken unterscheiden können. Per default werden mit KbdEvent simulierte Tastaturereignisse nicht vom Objekt behandelt, sondern sie werden gleich an den BASIC Handler weitergegeben. Details dazu siehe auch: inputFlags.
UI-Code |
Memo Text1 OnKeyPressed = KeyHandler End OBJECT Memo Text2 End OBJECT |
| BASIC Code |
KEYBOARDACTION KeyHandler ' Handler von Text1 sendet an Text2 Text2.KbdEvent character, keyState, keyFlags End ACTION |
|
|
DemoApplication.KbdEvent ASC("A"), 0, KF_FIRST_PRESS
DemoApplication.KbdEvent ASC("A"), 0, KF_RELEASE
|
|
|
Target.KbdEvent ASC("Z"), 0, KF_FIRST_PRESS
Target.KbdEvent ASC("Z"), 0, KF_RELEASE
|
KbdEventWithScancodeIn einigen Fällen werten die Objekte außer dem ASCII-Code und dem Tastaturstatus auch den Scancode der Taste aus. Das ist insbesondere bei der Tastaturnavigation durch Menüs der Fall, wenn bei der Definition des Tastenkürzels (siehe Instancevariable kbdShortcut, Objekthandbuch, Kapitel 3.1.4) das Bit KSM_PHYSICAL gesetzt ist. Typischer Weise ist dieses Bit bei den Menüeinträgen zum Drucken (Strg-P), Kopieren (Strg-C), Einfügen (Strg-V) usw. gesetzt.Für den seltenen Fall, dass Sie einen solchen Button durch ein simuliertes Tastaturereignis aktivieren wollen gibt es die Methode KbdEventWithScancode. In allen anderen Fällen sollten Sie die Methode KbdEvent verwenden. Syntax im BASIC Code: <obj>.KbdEventWithScancode character, keyState, keyFlags, scanCode character: ASCII-Code oder erweiterter ASCII-Code keyState: Kombination von KS_~Bits (siehe OnKeyPressed) keyFlags: Eines der KF_~ Bits (siehe OnKeyPressed) scanCode: Scancode der zu 'character' gehörenden Taste Die übergebenen Werte werden 1:1 als Parameter an den Tastaturhandler des Objekts und an den BASIC Tastaturhandler weitergegeben. Im Unterschied zu KbdEvent muss der Scancode der simulierten Taste übergeben werden. Das Objekt kann jetzt den simulierten Tastendruck nicht mehr von einem echten Tastendruck unterscheiden. Passen ASCII-Code und Scancode nicht zueinander, so erkennen Objekte, die den Scancode auswerten, die Taste nicht. Das folgenden Bild zeigt die Scancodes einer MF II Tastatur. Diese Codes sind auch für neuere Tastaturen gültig, die weitere Tasten (und damit weitere Scancodes) haben.
Scancodes einer MF II Tastatur
14.4 Komplexes Beispiel - Filtern von TastaturereignissenWir wollen bei einem Textobjekt nur Ziffern zulassen sowie die Buchstaben im Bereich von 'A' bis 'F'. Das Objekt soll alle anderen Buchstaben und Zeichen herausfiltern. Ein Blick auf die Instancevariable textFilter ergibt, dass es dafür keinen passenden Wert gibt.Diese Aufgabe erfordert eine komplexe Lösung, da das Objekt per default das Tastaturereignis zuerst selbst behandelt. Im Anschluss daran ruft es den BASIC Handler. Wir wollen jedoch, dass der BASIC Handler das Ereignis zuerst erhält, damit wir unerwünschte Zeichen herausfiltern können. Erst danach darf das Textobjekt das Ereignis behandeln. Um das zu erreichen muss man die inputFlags auf den Wert IF_IGNORE_ANY_KEY setzen und einen Keyboardhandler implementieren. UI Code |
Memo Text1 OnKeyPressed = KeyHandler inputFlags = IF_IGNORE_ANY_KEY ' betrifft nur echte Tastendrücke End OBJECT |
Intern passiert jetzt folgendes:
BASIC Code |
! -------- Handler KeyHandler --------
! Aufgabe: Tastaturereignisse ausfiltern
! Parameter: sender AS Object, character AS Word,
! keyState AS Word, keyFlags AS Byte, scanCode AS Byte
!scanCode = Null wenn mit Methode KbdEvent erzeugt
! --------------------------------
KEYBOARDACTION KeyHandler
DIM ch
' Statt den Befehl GOTO zu verwenden erzeugen wir
' eine "Endlos-Schleife"
' Diese verlassen wir mit BREAK, wenn wir einen
' akzeptablen ASCII-Code gefunden haben. Dann wird
' hinter der Schleife weiter gemacht.
' Wir verlassen sie mit RETURN, wenn wir den ASCII-Code
' ignorieren wollen
REPEAT
' Steuerzeichen und Sondertasten haben die höherwertigen
' Bits im Parameter "character" gesetzt.
' Wir verlassen in diesem Fall die Schleife mit BREAK.
IF character AND &hFF00 THEN BREAK
' Normale Codes prüfen
ch = character ' Das ist kürzer zu schreiben
' aber eigentlich überflüssig
' Ziffer ?
IF (ch >= ASC("0") ) AND (ch <= ASC("9")) THEN BREAK
' Buchstabe von A bis F ?
IF (ch >= ASC("A") ) AND (ch <= ASC("F")) THEN BREAK
' Kleinbuchstabe von a bis f ?
IF (ch >= ASC("a") ) AND (ch <= ASC("f")) THEN
character = ch - 32 ' a->A usw.
BREAK ' Buchstabe
End IF
RETURN ' Code nicht akzeptieren
UNTIL TRUE
' Jetzt ASCII-Code an das Textobjekt zurücksenden
sender.KbdEvent character, keyState, keyFlags
END ACTION
|
Den kompletten Quellcode hierfür finden Sie bei den Beispielen unter "Objekte\Text\Keyboard Handler Demo".
^ |