Frage deutsch
~~~~~~~~~~~~~~
Wie frage ich Mehrfach-Tastenbetätigungen ab?
 

Question English
~~~~~~~~~~~~~~
How to scan multiple simultaneaous key presses ?
How to scan multiple key strokes?
 
 

Antwort 1
~~~~~~~~
[ von Thomas Antoni, 25.8.2003 ]

Zum Abfragen von Mehrfach-Tastenbetätigungen sind die in QBasic verfügbaren Befehle INKEY$, INPUT und ON KEY leider nicht geeignet. Du musst dafür direkt auf das Tastatur-Statusregister &H60 zugreifen (Adresse 60 Hexadezimal = 96 dezimal).
 
Dort werden für betätigte Tasten nicht die von INKEY$ gewohnten ASCII-Codes angezeigt, sondern die so genannten "Scancodes". Die Scancodes einiger Tasten sind in der QBasic-Online-Hilfe aufgelistet unter "Hilfe | Inhalt | Tastatur-Abfragecodes
 
Das folgende Programm SCANKEY.BAS zeigt, wie Du auf diese Weise das Drücken und Loslassen von Tasten erfassen kannst, ohne hier schon auf das Erfassen gleichzeitig betätigter Tasten einzugehen. Das Programm zeigt den Scancode der gerade betätigten Taste an. Weitere Infos findest Du im Programmkopf.
 
'**********************************************************
' KEYSCAN.BAS = Tastenbetaetigungen erfassen ueber &H60
' ============
' Dies QBasic-Programm liest in einer Dauerschleife das
' Keyboard-Status-Register &H60 aus, um das Druecken
' und Loslassen von Tasten zu erfassen. Dort werden die
' Tasten nicht im ASCII-Code, sondern im so genannten
' Scancode dargestellt. Die Scancodes der einzelnen
' Tasten sind in der QBasic-Hilfe unter "Inhalt |
' Tastatur-Abfragecodes" aufgelistet
'
' Das Statuswort &H60 enthaelt immer eine Information ueber
' die zuletzt erfolgte Tastenbetaetigung, also entweder
' ueber das zuletzt erfolgte Druecken oder Loslassen einer
' Taste. Beim Druecken wird der Scancode der betreffenden
' Taste angezeigt, beim Loslassen der Scancode+128.
'
' Beispiel: Taste "U" gedrueckt : &H60 = 22
' Taste "U" losgelassen: &H60 = 150 (=22+128)
'
' Der Inhalt von &H60 bleibt so lange erhalten bis eine
' andere Taste gedrueckt oder losgelassen wird. Es kann
' also u.U. stundenlang der Wert von der letzten
' Tastenbetaetigung anstehen bleiben.
'
' Das Programm beendet sich bei Betaetigung der Esc-
' Taste (Scancode = 1)
'
' (c) Thomas Antoni, Nimes, 24.8.2003 - 25.8.2003
'**********************************************************
'
CLS
DEF SEG = 0
oldkey% = 256
DO
POKE &H41A, PEEK(&H41C)
keycode% = INP(&H60)
PRINT keycode%;
LOOP UNTIL keycode% = 1 'Ende mit Esc (Scancode 1)
DEF SEG
END
 
Das obige Programm steht im Verzeichnis Progs\ zur Verfügung sowie online unter www.antonis.de/faq/progs/keyscan.bas .
 
Anmerkung: Laut der Tischer-Bibel "PC intern" gibt es im &h60-Code noch einen Prefix &HE0 für die Sondertasten der AT-Tastatur (BildHoch usw.).
 
Wie Du nun mit Hilfe dieser Methode eine Mehrfach-Tastenabfrage realisieren kannst, zeigt mein untenstehendes Programm MULTIKEY.BAS . Die Details sind im Programmkopf erläutert.
 
'************************************************************
' MULTIKEY.BAS = Erfassen von Mehrfachtastenbetaetigungen
' ============
' Dies QBasic-Programm liest das Keyboard-Statusregister
' &H60 aus, um das Druecken und Loslassen von Tasten zu
' erfassen. Dort werden die Tasten nicht im ASCII-Code,
' sondern im so genannten Scancode dargestellt. Die
' Scancodes der einzelnen Tasten sind in der QBasic-Hilfe
' unter "Inhalt | Tastatur-Abfragecodes" aufgelistet.
'
' Beim Druecken wird der Scancode der betreffenden
' Taste angezeigt, beim Loslassen der Scancode+128. Bei
' einige Tasten, z.B. SHIF-TRechts/Links, Del, Ins, Home
' End, Pgp, PgDn gibt es leider Abweichungen von der
' Differenz von 128 zwischen gedrueckter und losgelassener
' Taste. Die Abweichung bei Shift-Links/Rechts ist in diesem
' Programm abgefangen. Die anderen jedoch nicht.
'
' Das Programm trägt bis zu 4 gleichzeitig gedrueckte Tasten
' in den Tastenpuffer keybuffer%() mit ihrem Tastencode ein.
' Losgelassene Tasten werden durch ueberschreiben mit "0"
' aus dem Tastenpuffer geloescht. Bei jeder Veränderung des
' Statusworts &H60 wird der gesamte Tastenpufferinhalt
' auf dem Bildschirm angezeigt. Hier koennte auch Deine
' spezielle Abfrage-Routine stehen.
'
' Mit der Esc-Taste (Tastencode = 1) wird das Programm
' beendet.
'
' (c) Thomas Antoni, 24.8.2003 - 25.8.2003
'************************************************************
'
DIM keybuffer%(1 TO 4)
CLS
DEF SEG = 0
oldkey% = 256
DO
'
'--- Tastencode aus Statuswort lesen ----------------------
POKE &H41A, PEEK(&H41C)
keycode% = INP(&H60)
IF keycode% <> oldkey% THEN 'neuer Tastenstatus
oldkey% = keycode% 'Tastencode merken
'
'--- "Taste losgelassen" erkannt ----------------------------
IF keycode% > 128 AND keycode% <> 250 THEN 'Taste losgelassen
IF keycode% = 170 OR keycode% = 182 THEN
keyoff% = 250
'Sonderbehandlung fuer Shift-Links bzw. -Rechts-Taste
'Taste gedrueckt=170 bzw. 182, losgelassen=250
ELSE
keyoff% = keycode% - 128 'Scancode d.losgelassenen Taste
END IF
FOR i% = 1 TO 4
IF keybuffer%(i%) = keyoff% THEN
keybuffer%(i%) = 0 'Taste im Puffer loeschen
END IF
NEXT i%

'
'---- "Taste gedrueckt" erkannt
ELSE 'Taste gedrueckt
FOR i% = 1 TO 4
IF keybuffer%(i%) = 0 THEN
keybuffer%(i%) = keycode%
'Taste im Puffer am ersten freien Platz eintragen
EXIT FOR 'Schleife abbrechen
END IF
NEXT i%
END IF
'
'---- Code der gerade gedrueckten max. 4 Tasten anzeigen ----
'---- (Anzeige 0 0 0 0, wenn keine Taste gedrckt -----------
FOR i% = 1 TO 4
PRINT keybuffer%(i%);
NEXT i%
PRINT "" 'Zeilenvorschub
END IF
LOOP UNTIL keycode% = 1 'Ende mit Esc
DEF SEG
 
Das obige Programm stehtmultikey.bas.
 
 

Antwort 2
~~~~~~~~
[ von Tobias Doerffel ("todo"; mailtodo*web.de ), per Mail, 29.4.02 ]
Also, man kann diese nicht einfach so abfragen. Da steckt mehr dahinter. Also erstes braucht man den Tastatur-Hardware-Port 60h (&H60). Dieser liefert immer den Tastatur-Code der gedrückten Taste oder den Code der Taste + 128, wenn die Taste losgelassen wurde (d.h. wenn keine Taste gedrückt ist, ist der Code, der zurückgeliefert wird der Code der zuletzt betätigten Taste + 128). Um feststellen zu können, ob mehrere Tasten gedrückt sind, muss das Programm immmer "am Draht bleiben". Man liest immer den Tastatur-Port aus, was wie folgt geschieht:
KeyCode = INP(&H60)
 
Wenn der Code kleiner als 128 ist, weiß man, dass eine Taste gedrückt ist. Das Abfragen macht man ja mit einer Schleife. Und so sollte man in der Schleife den alten Tasten-Code immer sichern, bevor man den neuen abfragt (der Sinn kommt gleich):
DO
KeyCode = INP(&H60)
...
OldKeyCode = KeyCode
LOOP UNTIL KeyCode = 1 REM 1 = Esc
 
Wenn sich der Tasten-Code ändert (angenommen, eine Taste ist gedrückt), kommt es drauf an wie. Wenn der neue Code größer als 128 ist, ist es klar, es ist keine Taste mehr gedrückt. Wenn nun jedoch der neue Code auch kleiner als 128 ist (aber sich doch vom alten unterscheidet!) kann man davon ausgehen, dass die erste Taste auch noch gedrückt ist. Wie bekommt man nun heraus, wann welche Taste wieder losgelassen wurde? Wenn die zuletzt gedrückte Taste losgelassen wird, ist der neue Tasten-Code größer als 128, also 128 + Tasten-Code der losgelassenen Taste. Um nun festzustellen, welche Taste noch gedrückt ist, sollte der Status jeder Taste in einem Array verzeichnet sein. Wenn eine Taste gedrückt wird, sollte der entsprechende Array-Eintrag auf TRUE (-1) gesetzt werden. Den Array-Eintrag der Taste, die losgelassen wurde (aktueller Code - 128) kann auf FALSE (0) gesetzt werden. Das heißt es sind alle Tasten gedrückt, deren Array-Eintrag auf TRUE stehen. Auf diese Weise lässt es sich auch feststellen, welche 10 (!) Tasten gleichzeitig gedrückt sind. Aber nun Beispielcode:
DEFINT A-Z
DIM KeyStateArray(1 TO 128)
OldKeyCode = INP(&H60)
CLS
DO
KeyCode = INP(&H60)
IF KeyCode <> OldKeyCode THEN
IF KeyCode > 128 THEN
KeyStateArray(KeyCode - 128) = 0
ELSE
KeyStateArray(KeyCode) = -1
END IF
CLS
LOCATE 1, 1
FOR i = 1 TO 128
IF KeyStateArray(i) THEN PRINT i;
NEXT i
END IF
OldKeyCode = KeyCode
a$ = INKEY$
LOOP UNTIL KeyCode = 1 REM 1 = Esc
 
Dieses kleine Beispielprogramm zeigt die Tasten-Codes aller gedrückten Tasten an. D.h. um festzustellen, welche Tasten gedrückt sind, muss man einfach das ganze Array mit einer Schleife durchlaufen. Wenn ein Eintrag TRUE (-1) ist, ist der aktuelle Arrayindex/Schleifenindex (hier i) der Tasten-Code einer gedrückten Taste.
 
Hinweis: Mit den Pfeiltaste, Bild hoch/runter, Einfügen, Entfernen, Pos1 und Ende (nicht auf dem Nummernblock!) funktioniert es nur, wenn Num-Lock aus ist.
 
 
 

Antwort 3
~~~~~~~~~
[ von Breeze ( PedderBank*Lycos.de ) im QB-Forum, 29.7.2003 - 3.9.03 ]
 
*** Anmerkung von Thomas Antoni
Breeze nennt hier einen sehr originellen Lösungsansatz für die Mehrfach-Tastenabfrage. Ich habe das Beispielprogramm stark vereinfacht und von jeglichem nicht direkt zum Problem gehörenden Beiwerk befreit.
 
*** Lösungsvorschlag von Breeze
Ich habe das folgende Programm MULTITAS.BAS geschrieben, das in ein Feld von 1 bis 128 hineinschreibt, ob eine Taste gedrückt ist, funktioniert mit bis zu 5 Tasten und mehr gleichzeitig.
 
'**********************************************************
' MULTITAS.BAS = Erfassen von Mehrfachstastenbetaetigungen
' ============
'
' (c) Breeze, 29.7.2003 - 3.9.2003
' (Vereinfachungen von Thomas Antoni)
'**********************************************************
'
DIM Tasten%(1 TO 128)
'Tastenpuffer. Hier ist jedem der Tastencodes 1-128 ein
'Feldelement zugeordnet. Das Feldelement wird auf 1 gesetzt,
'wenn die Taste gerade gedrueckt ist und auf 0 gesetzt, wenn
'sie losgelassen ist.
'
CLS
Alttast% = 256 'Vorbesetzung fuer gemerkte Taste
DEF SEG = 0
'
'--- Tastenpuffer updaten -------------------------------------
DO
POKE &H41A, PEEK(&H41C)
Tastcode% = INP(&H60) 'Keyboard-Statuswort einlesen
IF Tastcode% <> Alttast% THEN
'Es wird nur was getan bei Aenderung des Tastenstatus
Alttast% = Tastcode%
IF Tastcode% > 128 THEN
Tasten%(Tastcode% - 128) = 0 'Taste losgelassen
ELSE
Tasten%(Tastcode%) = 1 'Taste gedrueckt
END IF
'
'--- Codes aller gedrueckten Tasten im Tastenpuffer anzeigen ---
FOR i% = 1 TO 128
IF Tasten%(i%) = 1 THEN PRINT i%;
NEXT i%
PRINT " " 'Zeilenvorschub erzwingen
END IF
LOOP UNTIL Tasten%(1) = 1 'Beenden mit Esc-Taste
DEF SEG
END
 
Das obige Programm steht im Verzeichnis Progs\ zur Verfügung sowie online unter www.antonis.de/faq/progs/multitas.bas .
 
 
 
*** Anmerkung von Breeze, 3.9.03
Die UpdateKeyStaus SUB ist vielleicht besser. Dann kann man das an mehreren Stellen aufrufen.
 
Man könnte also:
 
'KEYCHECK.BAS
'by Breeze
DIM SHARED Tasten(1 TO 128) AS INTEGER
'Tastenpuffer. Hier ist jedem der Tastencodes 1-128 ein
'Feldelement zugeordnet. Das Feldelement wird auf 1 gesetzt,
'wenn die Taste gerade gedrueckt ist und auf 0 gesetzt, wenn
'sie losgelassen ist.
'So kann man eifach mit IF Tasten("Tastencode") THEN die
'Tasten abfragen.
'Es können bis zu 5 (!) Tasten gleichzeitig gedrückt werden.
'------------------------------------------------
CLS
DO
UpdateKeyStatus
'...Hier kann man dann seinen Programmtext einfügen.
LOOP UNTIL Tasten(1) = 1 'Beenden mit Esc-Taste
END
'
SUB UpdateKeyStatus
DEF SEG = 0 'BIOS-Datensegment
DIM Tastcode AS INTEGER 'Eine Variable brauchen wir
POKE &H41A, PEEK(&H41C) 'Keyboardpuffer leeren (sonst piepst es)
Tastcode = INP(&H60) 'Keyboard-Statuswort einlesen
IF Tastcode > 128 THEN
Tasten(Tastcode - 128) = 0 'Taste losgelassen
ELSE
Tasten(Tastcode) = 1 'Taste gedrueckt
END IF
DEF SEG
END SUB
 
 

Antwort 4
~~~~~~~~~~
[ von MisterD (jd-sw*gmx.de) im QB-Forum, 22.4.2004 ]
Oh, Gott. Die vorstehend genannten Antworten sind alle so umständlich! Ich würde das einfach so machen:
 
'*************************************************
' MEHRTAST.BAS by MisterD
' (wollt ich auch mal schreiben)
'*************************************************
PRINT "NumLock muss deaktiviert sein!"
DIM taste(128) AS INTEGER
'
DO
'Programmcode des Users
t = INP(&H60)
IF t > 128 THEN taste(t-128) = 0 ELSE taste(t) = 1
SELECT CASE 1
CASE taste(1): SYSTEM 'Escape
CASE taste(13): ... ' ENTER
...
END SELECT
'
'Programmcode des Users
LOOP
 
 
Das ist kurz, einfach und Funktioniert!
Die Zahlen der Tasten gibts in der QB-Online-Hilfe unter "Hilfe | Inhalt | Tastatur-Abfragecodes".
 
 
 
 
Antwort 5
~~~~~~~~
[ von Soeren Dressler (
http://qmystic.de.vu ) im QB-Forum, 18.5.2002 ]
Die in Antwort 1 genannte Lösung funktioniert zwar, hat aber folgenden Nachteil: Sobald die Schleife zu groß wird, werden Tasten übersehen da INP() den Zeitpunkt des Tastendrucks nicht kennt.
 
Ich hab auf meiner Webseite
http://qmystic.de.vu eine Lib mit Namen DKey. zum Download bereitgestellt, die diesem abhilft. Diese arbeitet mit Interrupt 9, wodurch Tastenerkennung in Echtzeit möglich wird.
 
In Basic geht das nicht, da Interrupts überschieben werden müssen. Die Beschreibung zur Lib ist in Deutsch.
 
 

Antwort 6
~~~~~~~~
[ von TheShadow (
www.quickbasic.de.vu ), im QB-Forum, 18.5.02 ]
Die in Antwort 1 genannte Lösung funktioniert zwar, hat aber folgenden Nachteil: Sobald die Schleife zu groß wird, werden Tasten übersehen da INP() den Zeitpunkt des Tastendrucks nicht kennt.
 
Auf
http://www.quickbasic.de.vu gibt's in der Rubrik "SUBs" eine Tasten-Funktion, die diesen Nachteil nicht aufweist. Damit kannst du viele Tasten gleichzeitig abfragen... Nachteil: Einige QBasic-Befehle wie INPUT funktionieren bei Verwendung dieser Funktion nicht mehr.
 

Antwort 7
~~~~~~~~~
Frage:
Wie kann ich mit QB erkennen, dass mehrere Tasten gedrückt werden und nicht nur die zuletzt betätigte?
 
Ich brauche dies damit ich in meinem Spiel mit den vier Pfeiltasten auch eine diagonale Bewegung bewirken kann, und zusätzlich auch noch mit Space den Laser abfeuern kann.
 
Antwort:
[ von Peter V. ( peter.vollenweider*gmx.ch ) im QB-Forum, 15.6.2002 ]
Hier sind zwei Programme. Programm 2 wird laufend verbessert.
 
Dazu noch ein paar Tipps und ein Vergleich der beiden Programme:
Wenn du bei Programm 2 vor der Zeile "GOTO weiter" ein Hochkomma "'" setzt, werden immer alle Tastencodes der gedrückten Tasten angezeigt
Wenn bei Programm 2 mehr als 4 Tasten gleichzeitig gedrückt werden kommt es zu Fehlern, nämlich dass eine der (z.B. 5) Tasten immer noch als gedrückt angesehen wird. Dies bin ich im Moment noch am eliminieren.
beide Programme ergeben dieselben Tastencodes
Bei Programm 1 funktionieren nach der Anweisung "onkb" keine der folgenden QBasic-Befehle mehr:
 
- INPUT
- ON KEY GOSUB
- INKEY$
- SLEEP
- Ctrl+Pause bzw. Ctrl+C zum Abbrechen
usw.
 
Programm 1 braucht grosse Assemblerroutinen, die zuerst eingelesen werden müssen (ich habs etwas umgeschrieben, jetzt ist es immerhin automatisch)
Programm 1 verlangsamt das Programm merklich, ich glaube ca. 10%-20%, Programm 2 muss in der Hauptschleife die SUB routine ausführen.
Die Tasten werden im Programm 1 mit kbmatrix(tastencode) abgefragt, in Programm 2 mit ison(tastencode)
Programm 1 aktualisiert den Status dauernd, Programm 2 nur in der SUB routine. Ich finde
es ist besser, wenn alle Tasten zur selben Zeit abgefragt werden (Programm 2)
 
Meine Meinung:
Im jetzigen Zustand ist Programm 1 in großen Programmen vorzuziehen, aber sobald die Probleme im Programm 2 gelöst sind, ist das schlanke und extrem schnelle Programm 2 sicher die bessere Lösung.
 
Tja, ich werde weiter arbeiten. So schwer kann es nicht sein. Schick mir unbedingt ein Mail
wenn du die fehlerfreie Version von Programm 2 willst.
 

*** Programm 1
 
DECLARE SUB offkb()
DECLARE SUB onkb ()
DIM kbcontrol(128) AS INTEGER, kbmatrix(128) AS INTEGER
onkb 'Install keyboard interrupt
WHILE NOT kbmatrix(1)
taste$ = ""
FOR taste% = 0 TO 128
IF kbmatrix(taste%) THEN taste$ = LTRIM$(STR$(taste%))
NEXT
PRINT taste$
IF taste$ = "1" THEN offkb: END
WEND
offkb 'Uninstall keyboard interrupt
'useful scancodes:
'up = 72
'right = 77
'down = 80
'left = 75
'space = 57
'alt = 56
'ctrl = 29
'esc = 1
'+ = 78
'enter = 28
'- = 74
'a = 30
's = 31
'd = 32
'w = 17
'h = 35
'j = 36
'k = 37
'l = 38
'x = 45
'(num)7 = 71
'(num)9 = 73
'(num)5 = 76
'(num)1 = 79
'(num)3 = 81
'g = 34
'z = 44
'c = 46
'end-> useful scancodes
kbisrdata:
DATA &HE9,&H1D,&H00 : '0000 JMP 0020 ;Jump to INSTALL INTERRUPT
DATA &HE9,&H3C,&H00 : '0003 JMP 0042 ;Jump to UNINSTALL INTERRUPT
DATA &H00,&H00 : '0006 ADD [BX+SI],AL ;\
DATA &H00,&H00 : '0008 ADD [BX+SI],AL ; \
DATA &H00,&H00 : '000A ADD [BX+SI],AL ; } Unused space
DATA &H00,&H00 : '000C ADD [BX+SI],AL ; /
DATA &H00,&H00 : '000E ADD [BX+SI],AL ;/
DATA &H00,&H00 : '0010 ADD [BX+SI],AL ;variable: keyboard_matrix_segment
DATA &H00,&H00 : '0012 ADD [BX+SI],AL ;variable: keyboard_matrix_offset
DATA &H00,&H00 : '0014 ADD [BX+SI],AL ;variable: dos_isr_handler_offset
DATA &H00,&H00 : '0016 ADD [BX+SI],AL ;variable: dos_isr_handler_segment
DATA &H00,&H00 : '0018 ADD [BX+SI],AL ;\
DATA &H00,&H00 : '001A ADD [BX+SI],AL ; \
DATA &H00,&H00 : '001C ADD [BX+SI],AL ; / Unused space
DATA &H00,&H00 : '001E ADD [BX+SI],AL ;/
DATA &H1E : '0020 PUSH DS ;INSTALL INTERRUPT save DS for QBASIC
DATA &H31,&HC0 : '0021 XOR AX,AX ;\
DATA &H8E,&HD8 : '0023 MOV DS,AX ; } DS:SI -> interrupt vector 9
DATA &HBE,&H24,&H00 : '0025 MOV SI,0024 ;/
DATA &H0E : '0028 PUSH CS ;
DATA &H07 : '0029 POP ES ;ES = CS
DATA &HBF,&H14,&H00 : '002A MOV DI,0014 ;ES:DI -> dos_isr_handler_offset
DATA &HFC : '002D CLD ;Increment SI, DI on string moves
DATA &HA5 : '002E MOVSW ;\
DATA &HA5 : '002F MOVSW ;/ Read address of old handler
DATA &H8C,&HC3 : '0030 MOV BX,ES ;BX = CS
DATA &H8E,&HC0 : '0032 MOV ES,AX ;ES = 0
DATA &HBF,&H24,&H00 : '0034 MOV DI,0024 ;ES:DI -> keyboard interrupt vector
DATA &HB8,&H56,&H00 : '0037 MOV AX,0056 ;AX = Offset of new handler from CS
DATA &HFA : '003A CLI ;Disable interrupts
DATA &HAB : '003B STOSW ;\
DATA &H89,&HD8 : '003C MOV AX,BX ; } Change keyboard interrupt vector
DATA &HAB : '003E STOSW ;/ to point to new handler
DATA &HFB : '003F STI ;Enable interrupts
DATA &H1F : '0040 POP DS ;Restore DS for QBASIC
DATA &HCB : '0041 RETF ;
DATA &H1E : '0042 PUSH DS ;UNINSTALL INTERRUPT save DS for QBASIC
DATA &H31,&HC0 : '0043 XOR AX,AX ;\
DATA &H8E,&HC0 : '0045 MOV ES,AX ; } ES:DI -> keyboard interrupt vector
DATA &HBF,&H24,&H00 : '0047 MOV DI,0024 ;/
DATA &HBE,&H14,&H00 : '004A MOV SI,0014 ;\
DATA &H0E : '004D PUSH CS ; } DS:SI -> address of old handler
DATA &H1F : '004E POP DS ;/
DATA &HFC : '004F CLD ;Increment SI, DI on string moves
DATA &HFA : '0050 CLI ;Disable interrupts
DATA &HA5 : '0051 MOVSW ;\
DATA &HA5 : '0052 MOVSW ;/ Change interrupt vector
DATA &HFB : '0053 STI ;Enable interrupts
DATA &H1F : '0054 POP DS ;Restore DS for QBASIC
DATA &HCB : '0055 RETF ;
DATA &HFB : '0056 STI ;INTERRUPT HANDLER enable interrupts
DATA &H9C : '0057 PUSHF ;Save flags
DATA &H50 : '0058 PUSH AX ;Save registers
DATA &H53 : '0059 PUSH BX ;
DATA &H51 : '005A PUSH CX ;
DATA &H52 : '005B PUSH DX ;
DATA &H1E : '005C PUSH DS ;
DATA &H56 : '005D PUSH SI ;
DATA &H06 : '005E PUSH ES ;
DATA &H57 : '005F PUSH DI ;
DATA &HE4,&H60 : '0060 IN AL,60 ;AL = Scan code
DATA &HB4,&H01 : '0062 MOV AH,01 ;Assume it's a make code
DATA &HA8,&H80 : '0064 TEST AL,80 ;
DATA &H74,&H04 : '0066 JZ 006C ÚÄÄÄ;If it's not a break code then jump
DATA &HB4,&H00 : '0068 MOV AH,00 ³ ; It's a break code
DATA &H24,&H7F : '006A AND AL,7F ³ ; key index = code AND 127
DATA &HD0,&HE0 : '006C SHL AL,1 ÀÄÄ>;\
DATA &H88,&HC3 : '006E MOV BL,AL ; } BX = key index * 2
DATA &HB7,&H00 : '0070 MOV BH,00 ;/
DATA &HB0,&H00 : '0072 MOV AL,00 ;
DATA &H2E : '0074 CS: ;
DATA &H03,&H1E,&H12,&H00 : '0075 ADD BX,[0012] ;BX = BX + offset of matrix
DATA &H2E : '0079 CS: ;
DATA &H8E,&H1E,&H10,&H00 : '007A MOV DS,[0010] ;DS = segment of matrix
DATA &H86,&HE0 : '007E XCHG AH,AL ;
DATA &H89,&H07 : '0080 MOV [BX],AX ;Store key state
DATA &HE4,&H61 : '0082 IN AL,61 ;Interrupt Clean up
DATA &H0C,&H82 : '0084 OR AL,82 ;
DATA &HE6,&H61 : '0086 OUT 61,AL ;
DATA &H24,&H7F : '0088 AND AL,7F ;
DATA &HE6,&H61 : '008A OUT 61,AL ;
DATA &HB0,&H20 : '008C MOV AL,20 ;
DATA &HE6,&H20 : '008E OUT 20,AL ;
DATA &H5F : '0090 POP DI ;Restore registers
DATA &H07 : '0091 POP ES ;
DATA &H5E : '0092 POP SI ;
DATA &H1F : '0093 POP DS ;
DATA &H5A : '0094 POP DX ;
DATA &H59 : '0095 POP CX ;
DATA &H5B : '0096 POP BX ;
DATA &H58 : '0097 POP AX ;
DATA &H9D : '0098 POPF ;Restore flags
DATA &HCF : '0099 IRET ;Exit interrupt
DATA -1
'
SUB offkb
SHARED keyboardonflag%, kbcontrol() AS INTEGER
IF keyboardonflag% < 1 THEN EXIT SUB
keyboardonflag% = -1
DEF SEG = VARSEG(kbcontrol(0))
CALL ABSOLUTE(3)
DEF SEG
END SUB
'
SUB onkb
SHARED keyboardonflag%, kbcontrol() AS INTEGER, kbmatrix() AS INTEGER
IF keyboardonflag% = 1 THEN EXIT SUB
IF keyboardonflag% = 0 THEN
RESTORE kbisrdata
DEF SEG = VARSEG(kbcontrol(0))
I& = 0
GOTO skip0
DO
POKE I&, q%
I& = I& + 1
skip0:
READ q%
LOOP WHILE q% > -1
I& = 16
n& = VARSEG(kbmatrix(0)): l& = n& AND 255: H& = ((n& AND &HFF00) \ 256): POKE I&, l&: POKE I& + 1, H&:
I& = I& + 2
n& = VARPTR(kbmatrix(0)): l& = n& AND 255: H& = ((n& AND &HFF00) \ 256): POKE I&, l&: POKE I& + 1, H&: I&
= I& + 2
DEF SEG
END IF
keyboardonflag% = 1
DEF SEG = VARSEG(kbcontrol(0))
CALL ABSOLUTE(0)
DEF SEG
END SUB
 
 

*** Programm 2
 
'Mehrere Tasten gleichzeitig druecken mit INP(&H60)
'
DECLARE SUB routine ()
DIM SHARED ison(128) AS INTEGER
GOTO weiter
WHILE NOT ison(1)
routine '\_,- Hauptbestandteile
dummy$ = INKEY$ '/
'Demo:
hitkey% = 0
FOR taste% = 1 TO 128
IF ison(taste%) THEN PRINT taste%: hitkey% = -1
NEXT
IF hitkey% = 0 THEN PRINT
WEND
weiter:
'"demo code" von KB2.bas („hnliche Funktion aber mit Assemblerroutinen),
'leicht ver„ndert
CLS
WAIT 986, 8
WAIT 986, 8, 8
SCREEN 12
PRINT "Press ESC to end program"
x% = 320
y% = 240
DO
routine '\_,- Hauptbestandteile
dummy$ = INKEY$ '/
IF ison(72) THEN y% = y% - 1
IF ison(77) THEN x% = x% + 1
IF ison(80) THEN y% = y% + 1
IF ison(75) THEN x% = x% - 1
IF oldx% <> x% OR oldy% <> y% THEN
WAIT 986, 8
WAIT 986, 8, 8
IF oldx% <> 0 OR oldy% <> 0 THEN CIRCLE (oldx%, oldy%), 50, 0
CIRCLE (x%, y%), 50, 10
END IF
'LOCATE 1, 1, 0: PRINT INP(96)
oldx% = x%
oldy% = y%
LOOP UNTIL ison(1)
'end -> demo code
'
'"useful scancodes" von KB2.bas
'up = 72
'right = 77
'down = 80
'left = 75
'space = 57
'alt = 56
'ctrl = 29
'esc = 1
'+ = 78
'enter = 28
'- = 74
'a = 30
's = 31
'd = 32
'w = 17
'h = 35
'j = 36
'k = 37
'l = 38
'x = 45
'(num)7 = 71
'(num)9 = 73
'(num)5 = 76
'(num)1 = 79
'(num)3 = 81
'g = 34
'z = 44
'c = 46
'end-> useful scancodes
'
DEFINT A-Z
SUB routine
STATIC alttaste
taste = INP(&H60)
ison(taste MOD 128) = taste < 128
END SUB
 
 

Antwort 8
~~~~~~~~~
[ von BugFinder (
qb-elite*gmx.ch - http://www.qb-elite.ch.vu/ ), 26.3.01 ]
Wenn man zum Beispiel zwei Tasten drücken will, hat man bei INKEY$ kein Chance. Darum nimmt man den Befehl INP. Er wird ganz einfach benutzt.
INP(&H60)
 
Wenn man jetzt z.B. ESC drücken will, benutzt man einfach diesen Tastencode, den man in der QB-Hilfe nachlesen kann.
IF INP(&H60)=1 THEN PRINT "[ESC]-Taste gedrückt"
 
Mit mehreren Tasten, muss man einfach die Zahlen zusammenzählen und aufschreiben:
taste1=a 'Tastencode
taste2=b 'Tastencode
'
IF INP(&H60)=(taste1+taste2) THEN PRINT"Zwei
Tasten gedrückt"
 
 

Answer 9
~~~~~~~~
How can I detect multiple keypresses at one time?
You can code this yourself with PEEK and whatnot, but I recommend subs/routines already made for this purpose, which
make it's implementation the simplest. DirectQB (libraries section) has such features, as well as Milo Sedlacek's keyboard
routines, and Aaron Severn's keyboard routines.
 
 

Answer 10
~~~~~~~~
[ Tip by Buff ]
Here's another way, perhaps easier, (at least to understand) to access Ctl, Alt and other keys too (find if they've been pressed)
 
'check key status for several keys
DEF SEG = 0
KeyStatus = PEEK(1047) ''or &H417
'
'This is where the key status is stored. The values are:
'
'(INS 128 'CAPS 64 'NUM 32 'SCROLL 16 'ALT 8 'CTRL 4 'RSHIFT 2 'LSHIFT 1)
IF KeyStatus > 127 THEN KeyStatus = KeyStatus - 128: InsertStatus = 1
IF KeyStatus > 63 THEN KeyStatus = KeyStatus - 64 : CapsStatus = 1
IF KeyStatus > 31 THEN KeyStatus = KeyStatus - 32 : NumStatus = 1
IF KeyStatus > 15 THEN KeyStatus = KeyStatus - 16 : ScrollStatus = 1
IF KeyStatus > 7 THEN KeyStatus = KeyStatus - 8 : altstatus = 1
IF KeyStatus > 3 THEN KeyStatus = KeyStatus - 4 : CtrlStatus = 1
IF KeyStatus > 1 THEN KeyStatus = KeyStatus - 2 : RShiftStatus = 1
IF KeyStatus = 1 THEN KeyStatus = KeyStatus - 1 : LShiftStatus = 1
DEF SEG
 
 

Answer 11
~~~~~~~~~
[ from the QB-FAQ 1 of the Microsoft Knowledge Base at
http://www.microsoft.com ]
Question:
Can you give an example of key trapping?
 

Response:
Pressing any key in combination with CTRL, SHIFT, ALT, CAPS LOCK, or NUM LOCK changes the keyboard scan code. To trap combinations of keys, the KEY statement requires adding together the values of the keyboard flags as shown in the code example below.
The following is a code example:

CONST alt = &H8
CONST noflag = &H0
CONST leftshift = &H1
CONST rightshift = &H2
CONST ctrl = &H4
CONST numlock = &H20
CONST capslock = &H40
CONST extendedkeyboard = &H80
CONST left = &H4B
CONST right = &H4D
CONST up = &H48
CONST down = &H50
CONST C = &H2E
CONST scrolllock = &H46
'
KEY 15, CHR$(extendedkeyboard + numlock) + CHR$(left)
KEY 16, CHR$(extendedkeyboard + numlock) + CHR$(right)
KEY 17, CHR$(extendedkeyboard + numlock) + CHR$(up)
KEY 18, CHR$(extendedkeyboard + numlock) + CHR$(down)
KEY 19, CHR$(ctrl + capslock) + CHR$(C)
KEY 20, CHR$(extendedkeyboard + ctrl + numlock) + CHR$(scrolllock)
'
ON KEY(15) GOSUB Keyleft
ON KEY(16) GOSUB Keyright
ON KEY(17) GOSUB Keyup
ON KEY(18) GOSUB Keydown
ON KEY(19) GOSUB Keybreak
ON KEY(20) GOSUB Keybreak
'
KEY(15) ON
KEY(16) ON
KEY(17) ON
KEY(18) ON
KEY(19) ON
KEY(20) ON
'
WHILE UCASE$(INKEY$) <> UCASE$("q")
WEND
END
'
Keyleft:
PRINT "left"
RETURN
'
Keyright:
PRINT "right"
RETURN
'
Keyup:
PRINT "up"
RETURN
'
Keydown:
PRINT "down"
RETURN
'
Keybreak:
PRINT "break"
RETURN
 
 

Answer 12
~~~~~~~~~~~~
Seems like I remember something about INP(&H60)... I think that's what I used on a GW-Basic Space Invaders clone that I made. I'm sure that Neo would know.
 
probably not what you want... but this was on Google at
http://polacka.xepher.net/simplified/qbgamedev_simple(6).html
 
 
' Z-Keyboard Handler
'
' By Exopsed Dreams
'
' A simple demo program!
' If you get pissed off with this
' demo, (we did!) then feel free to
' make a new one! We will publish it
' for u on our site!
'
' Oh and by the way if this test prog is
' slow in any way then it is cause to QB's
' very bad graphics routines and not ZKBH
'
'------This Code is required for the KBhandler to work------
'
DECLARE SUB LoadAsm ()
DECLARE SUB Zkbon ()
DECLARE SUB Zkboff ()
'
DIM SHARED Zkey%(127), Zkbh$(2), kbonflag%, olkbseg%, olkboff%
'
'-------------------------------------------------------------
'
LoadAsm 'load asm routines
Zkbon 'turn on the ZKBH
'
x% = 160: y% = 100 'sprite placement vars
SCREEN 7, , 1, 0 'Screen 7
'
DO 'Start a loop
CLS
PRINT "Z-keyboard" 'Draw a stupid
CIRCLE (x%, y%), 9, 10 'little circle thingy ;-)
'
IF Zkey%(72) THEN y% = y% - 2
IF Zkey%(80) THEN y% = y% + 2
IF Zkey%(77) THEN x% = x% + 2
IF Zkey%(75) THEN x% = x% - 2
'
WAIT &H3DA, 8 'a little delay
WAIT &H3DA, 8, 8 '.............
PCOPY 1, 0 'display them page and
LOOP UNTIL Zkey%(1) 'loop back until ESC
'
Zkboff 'turn off the ZKBH
'
SUB LoadAsm
Zkbh$(0) = ""
Zkbh$(0) = Zkbh$(0) + CHR$(&H55)
Zkbh$(0) = Zkbh$(0) + CHR$(&H89) + CHR$(&HE5)
Zkbh$(0) = Zkbh$(0) + CHR$(&HB8) + CHR$(&H9) + CHR$(&H35)
Zkbh$(0) = Zkbh$(0) + CHR$(&HCD) + CHR$(&H21)
Zkbh$(0) = Zkbh$(0) + CHR$(&H31) + CHR$(&HC0)
Zkbh$(0) = Zkbh$(0) + CHR$(&H89) + CHR$(&HD8)
Zkbh$(0) = Zkbh$(0) + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H6)
Zkbh$(0) = Zkbh$(0) + CHR$(&H89) + CHR$(&H7)
Zkbh$(0) = Zkbh$(0) + CHR$(&H8C) + CHR$(&HC0)
Zkbh$(0) = Zkbh$(0) + CHR$(&H8B) + CHR$(&H5E) + CHR$(&H8)
Zkbh$(0) = Zkbh$(0) + CHR$(&H89) + CHR$(&H7)
Zkbh$(0) = Zkbh$(0) + CHR$(&H5D)
Zkbh$(0) = Zkbh$(0) + CHR$(&HCA) + CHR$(&H4) + CHR$(&H0)
'
Zkbh$(1) = ""
Zkbh$(1) = Zkbh$(1) + CHR$(&H55)
Zkbh$(1) = Zkbh$(1) + CHR$(&H1E)
Zkbh$(1) = Zkbh$(1) + CHR$(&H89) + CHR$(&HE5)
Zkbh$(1) = Zkbh$(1) + CHR$(&H8B) + CHR$(&H46) + CHR$(&HA)
Zkbh$(1) = Zkbh$(1) + CHR$(&H8E) + CHR$(&HD8)
Zkbh$(1) = Zkbh$(1) + CHR$(&H8B) + CHR$(&H56) + CHR$(&H8)
Zkbh$(1) = Zkbh$(1) + CHR$(&HB8) + CHR$(&H9) + CHR$(&H25)
Zkbh$(1) = Zkbh$(1) + CHR$(&HCD) + CHR$(&H21)
Zkbh$(1) = Zkbh$(1) + CHR$(&H1F)
Zkbh$(1) = Zkbh$(1) + CHR$(&H5D)
Zkbh$(1) = Zkbh$(1) + CHR$(&HCA) + CHR$(&H4) + CHR$(&H0)
'
Zkbh$(2) = ""
Zkbh$(2) = Zkbh$(2) + CHR$(&H50)
Zkbh$(2) = Zkbh$(2) + CHR$(&H53)
Zkbh$(2) = Zkbh$(2) + CHR$(&H1E)
Zkbh$(2) = Zkbh$(2) + CHR$(&HFB)
Zkbh$(2) = Zkbh$(2) + CHR$(&HB8) + MKI$(VARSEG(Zkey%(0)))
Zkbh$(2) = Zkbh$(2) + CHR$(&H31) + CHR$(&HDB)
Zkbh$(2) = Zkbh$(2) + CHR$(&H8E) + CHR$(&HD8)
Zkbh$(2) = Zkbh$(2) + CHR$(&HE4) + CHR$(&H60)
Zkbh$(2) = Zkbh$(2) + CHR$(&HD0) + CHR$(&HD0)
Zkbh$(2) = Zkbh$(2) + CHR$(&H88) + CHR$(&HC3)
Zkbh$(2) = Zkbh$(2) + CHR$(&HF) + CHR$(&H93) + CHR$(&HC0)
Zkbh$(2) = Zkbh$(2) + CHR$(&H81) + CHR$(&HC3) + MKI$(VARPTR(Zkey%(0)))
Zkbh$(2) = Zkbh$(2) + CHR$(&H88) + CHR$(&H7)
Zkbh$(2) = Zkbh$(2) + CHR$(&HE4) + CHR$(&H61)
Zkbh$(2) = Zkbh$(2) + CHR$(&H80) + CHR$(&HCC) + CHR$(&H82)
Zkbh$(2) = Zkbh$(2) + CHR$(&HE6) + CHR$(&H61)
Zkbh$(2) = Zkbh$(2) + CHR$(&H24) + CHR$(&H7F)
Zkbh$(2) = Zkbh$(2) + CHR$(&HE6) + CHR$(&H61)
Zkbh$(2) = Zkbh$(2) + CHR$(&HB0) + CHR$(&H20)
Zkbh$(2) = Zkbh$(2) + CHR$(&HE6) + CHR$(&H20)
Zkbh$(2) = Zkbh$(2) + CHR$(&H1F)
Zkbh$(2) = Zkbh$(2) + CHR$(&H5B)
Zkbh$(2) = Zkbh$(2) + CHR$(&H58)
Zkbh$(2) = Zkbh$(2) + CHR$(&HCF)
END SUB
'
SUB Zkboff
IF NOT kbonflag% THEN EXIT SUB
DEF SEG = VARSEG(Zkbh$(1))
CALL ABSOLUTE(BYVAL olkbseg%, BYVAL olkboff%, SADD(Zkbh$(1)))
DEF SEG
END SUB
'
SUB Zkbon
IF kbonflag% THEN EXIT SUB
'
DEF SEG = VARSEG(Zkbh$(0))
CALL ABSOLUTE(seg1%, off1%, SADD(Zkbh$(0)))
DEF SEG = VARSEG(Zkbh$(1))
 
 
 
 
 
 
CALL ABSOLUTE(BYVAL VARSEG(Zkbh$(2)), BYVAL SADD(Zkbh$(2)), SADD(Zkbh$(1)))
DEF SEG
OUT &H21, (INP(&H21) AND (255 XOR 2)) 'CLEAR BIT 2 (IRQ 1)
'
olkbseg% = seg1%
olkboff% = off1%
'
kbonflag% = -1
END SUB
 
 

Answer 13
~~~~~~~~~~~~~
[ by lipha (
aliphax*hotmail.com - www.geocities.com/aliphax ) ]
 
How to detect multiple simultaneous key presses
As for your key press problem, you use INP(96). INP(96) returns the Keyboard Scan Code (in QB help file, not the ASCII Character Codes) for a key when it is pressed and the Scan Code + 128 when released.
 
So what you can do is create an array of the ~128 scan codes. Then flag an element when the key is pressed and "un-flag" it when the key is released:
DEFINT A-Z
DECLARE SUB UpdateKeys (k())
CONST TRUE = -1
CONST FALSE = 0
DIM keys(127)
'
DO
UpdateKeys keys() 'updates the keys array
LOCATE 1, 1
FOR i = 1 TO 127 'print what keys are pressed
PRINT keys(i);
NEXT i
LOOP UNTIL keys(1) 'until ESC is pressed
'
SUB UpdateKeys (k())
STATIC lastPress
press = INP(96)
'
IF press < 128 THEN 'when a key is pressed, the keyboard scan code is
k(press) = TRUE 'returned. when released, the scan code + 128 is
lastPress = press 'returned
ELSE
k(press - 128) = FALSE
IF press = 170 THEN k(lastPress) = FALSE 'if 170 is returned, then
END IF 'last key that was pressed
' 'should be released
DEF SEG = 0
POKE 1052, PEEK(1050) 'clears keyboard buffer (gets rid of beeping)
END SUB
 
The downside of this is that you have to call UpdateKeys very often to see if a key has been pressed or released. If you don't, then a key press/release could sneak by :-( If you don't want to worry about that, download a keyboard handler library, like Zip's, at the files of my site.
 
 

Answer 14
~~~~~~~~~~~~~~~
Try this code:
 
CLS
LOCATE 25, 22: PRINT "Press Esc to exit";
ReleaseKey = 128
DIM KeyState(3) AS INTEGER
DO
A$ = INKEY$
KeyPressed = INP(&H60)
IF KeyPressed = 75 THEN KeyState(0) = 1
IF KeyPressed = 77 THEN KeyState(1) = 1
IF KeyPressed = 72 THEN KeyState(2) = 1
IF KeyPressed = 80 THEN KeyState(3) = 1
IF KeyPressed = 75 + ReleaseKey THEN KeyState(0) = 0
IF KeyPressed = 77 + ReleaseKey THEN KeyState(1) = 0
IF KeyPressed = 72 + ReleaseKey THEN KeyState(2) = 0
IF KeyPressed = 80 + ReleaseKey THEN KeyState(3) = 0
LOCATE 1, 1: PRINT "L"; KeyState(0)
LOCATE 2, 1: PRINT "R"; KeyState(1)
LOCATE 3, 1: PRINT "U"; KeyState(2)
LOCATE 4, 1: PRINT "D"; KeyState(3)
LOCATE 6, 1: PRINT "KeyCode: "; KeyPressed; " "
LOOP UNTIL A$ = CHR$(27)
SYSTEM

[ The QBasic-MonsterFAQ --- Start Page: www.antonis.de/faq ]