Werbung

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

[x86 Real] Mehrere tastendrücke gleichzeitig

Dieses Thema im Forum "Assembler (ASM)" wurde erstellt von hexagon, 31. Oktober 2012.

  1. hexagon

    hexagon Member

    Hallo liebes CB,

    ich Habe gestern ein Pong spiel in asm Programiert,
    um tasten drücke zu erhalten utze ich das entspechende bios interrupt,
    doch leider stoße ich hierbei auf das problem, das wen eine taste gedrückt ist und eine zweit taste gedrückt wirt die erste "Loßgelassen" wir.

    das ist ja sogar noch halbwegs akzeptabel, dan mus man die taste halt merfach drücken,
    doch komsicherweise wird bei extrem schnellen drücken auf zwei tasten nur eine dieser zweien wargenommen . . .

    ich hoffe nun, das jemand von euch das problem kent und vileicht eine extrem kleine lösung hat,
    da das pong in einen bootsektor passen soll und ich eigentich schon keinen platz mehr übrig habe . . .

    Mit freundlichen Grüßen

    hexagon
  2. coding-board

    coding-board Member

    Werbung
  3. gargyle

    gargyle Well-Known Member c-b Experte

    Setzt mal die Parameter der Tastatur für Waren und wiederholen.
    ->

    INT 16,3 - Set Keyboard Typematic Rate (AT+)


    AH = 03
    AL = 00 set typematic rate to default
    01 increase initial delay
    02 slow typematic rate by 1/2
    04 turn off typematic chars
    05 set typematic rate/delay

    BH = repeat delay (AL=5)
    0 = 250ms 2 = 750ms
    1 = 500ms 3 = 1000ms
    BL = typematic rate, one of the following (AL=5)

    00 - 30.0 01 - 26.7 02 - 24.0 03 - 21.8
    04 - 20.0 05 - 18.5 06 - 17.1 07 - 16.0
    08 - 15.0 09 - 13.3 0A - 12.0 0B - 10.9
    0C - 10.0 0D - 9.2 0E - 8.6 0F - 8.0
    10 - 7.5 11 - 6.7 12 - 6.0 13 - 5.5
    14 - 5.0 15 - 4.6 16 - 4.3 17 - 4.0
    18 - 3.7 19 - 3.3 1A - 3.0 1B - 2.7
    1C - 2.5 1D - 2.3 1E - 2.1 1F - 2.0

    returns nothing

    http://stanislavs.org/helppc/int_16-3.html
  4. hexagon

    hexagon Member

    das hat leider nicht funtioniert,
    sovern ich das richtig verstanden habe ändert es nur die rate mit der tasten wiederholt werden sollen,
    hatt es vileicht etwas damit zu tu das ich die zeichen alle 250 ms abhole ?
    und der buffer bei seeehr schnellen tippen dan schon überfüllt ist und nichts weiteres mehr aufnehmen kan ?
    kan man vileicht einstellen, das eine taste nur 1 mahl in 250 ms wahrgenommen weren kan oder sowas ?

    hexagon
  5. gargyle

    gargyle Well-Known Member c-b Experte

  6. Xpyder

    Xpyder Active Member c-b Experte

    Es geht anders - und einfacher. So mach ich das immer, wenn ich Spiele programmiere.
    Und zwar: MERKEN, welche Tasten gerade gedrückt sind. Das passiert so:
    Die Tastatur sendet an den Port $60 (oder für C-Programmierer: 0x60) nämlich immer einen sogenannten Scancode (der NICHT von der Tastaturbelegung oder dem Treiber abhängt, sondern nur von der Stelle, an der die Taste auf der Tastatur angebracht ist).
    Dieser Scancode ist 8bit, wobei die untersten 7 Bit die Nummer der Taste darstellen und das oberste Bit bestimmt, ob die Taste gedrückt oder losgelassen wurde. Für Tasten wird immer nur EIN "Loslaßcode" gesendet. Der "Gedrückt"-Code wird einmal gesendet und - je nach Einstellung der Tastenwiederholrate und Zeit bis zur ersten Wiederholung - dann öfter nochmal. Das macht aber nichts (erkläre später, wieso).
    Hinweis:
    Es gibt einige Tasten, die ZWEI Codes senden, dies sind die CURSORTASTEN, der Block EINFG/ENTF/POS1/ENDE/BILDAUF/BILDAB, die ENTER-Taste auf dem Ziffernblock und die RECHTE STRG und RECHTE ALT Taste (ALTGR auf deutschen Tastaturen). So ein Doppelcode sie aus wie der einfache Code für die "äquivalente" Taste, davor immer der Wert $E0 (0xE0), sowohl für "Drück"- als auch für "Loslaß" Code.
    Äquivalente Tasten sind eben die anderen - also bei dem EINFG/ENTF/POS1/ENDE/BILDAUF/BILDAB und den CURSORTASTEN, sind die OHNE Doppelcode die auf dem Ziffernblock (die zweite - "nicht-Ziffer" Funktion, wenn). Bei ENTER und den rechten STRG/ALT dürfte klar sein, welches die Äquivalente sind. Achso, Anmerkung: Für Shift gilt das nicht, die sind beide "normal", (links $2A, rechts $36).
    Anmerkung: Wenn einem egal ist, ob jemand die Cursortasten oder den Ziffernblock, die rechte oder linke ALT-.... etc benutzt - dann einfach den Code $E0 ignorieren und fertig.

    Die Abfrage des Scancodes erfolgt NICHT durch Polling, sondern sobald an Port $60 ein Tastencode gesendet wird, wird auch der IRQ1 ausgelöst. Dieser stößt die ISR an INT $09 an. In diesen klinkt man sich nun ein und fragt den Port ab. Man kann auch, anstatt sich einzuklinken, den INT völlig übernehmen - dann muß man eben alle "normalen" Funktionen (die z.B. der Keyboardtreiber macht), nachbilden, wenn man will. Oder kann auch z.B. einige davon weglassen/umschreiben. Will sagen: Man MUß den Affengriff (STRG-ALT-ENTF) z.B. nicht supporten, wenn man nicht will.

    Ich gehe nun folgendermaßen vor: Ich lege eine Tabelle mit 256 Bits oder Bytes an (wie auch immer und wie es sich am besten codet). Wenn nun ein Drück-Code kommt, setze ich das entsprechend Bit/Byte in der Tabelle auf 1, wenn der Loslaßcode kommt, auf 0. Eigentlich bräuchte die Tabelle nur 128 Werte - ich verwende die anderen (oberen) 128 für die Tasten mit Doppelcodes, dadurch eliminiere ich im Hauptprogramm diese Abfragen und kann alles wie "Singlecodes" behandeln. Die Tastatur hat sowieso keine 128 Tasten. Achja, natürlich ist das etwas Verschwendung, weil es so wenige Tasten mit Doppelcode gibt - aber es programmiert sich leichter und außerdem gibt es z.B. Tastaturen mit so Media-Tasten - diese haben auch Doppelcodes, nämlich die, die normalerweise nicht benutzt sind. Für die normalen Scancodes gibt es übrigens Tabellen (also welcher Code welcher Taste entspricht) Leider gibt es für Mediatasten nichts derartiges, da man sich da wahrscheinlich erst wieder auf einen Standard einigen wird, wenn es in der Form keiner mehr benutzt und es etwas neues gibt - wie bei quasi ALLEN Standards der letzten 20 Jahre gesehen. Aber ich glaube, für ein paar der "generellsten" Mediatasten gibt es da schon einen proprietären Standard... - OK, ich schweife ab...

    Also, diese Tabelle ist dann das, was ich im Hauptprogramm abfrage. Sie zeigt mir immer, welche Taste gerade gedrückt und welche nicht gedrückt ist. (Wieviele und welche Tasten man gleichzeitig drücken kann, hängt übrigens von der Hardware der Tastatur ab und kann softwaremäßig leider nicht umgangen werden - es gibt sogar alte gute IBM-Keyboards, auf denen man ALLE Tasten gleichzeitig drücken kann - wenn man 102 Finger hat...) - Ansonsten wird nach einer bestimmten Anzahl gedrückter Tasten kein Code mehr für eine weitere gesendet, bevor eine andere losgelassen wird. Die "Zusatz-Hilfs-Umschalt" Tasten (Ich meine Dinge wie SHIFT, STRG, ALT...) sind übrigens meist besser geeignet, selbst bei "schlechten" Tastaturen - weil die ja mit anderen zusammen gedrückt werden MÜSSEN bei Normalbetrieb.

    Achja, die Taste PAUSE ist ein Sonderfall. Den kann ich bei Bedarf auch noch erklären. Sie sendet einen etwas komischen Code (bzw mehrere) und sie sendet bei Drücken gleichzeitig "gedrückt" und "loslaß" Codes, beim Loslassen dann garnix.

    So, nun braucht man aber für ein Spiel nicht 100 Tasten. Daher mache ich es meist so, daß ich eine ZWEITE Tabelle erstelle, die auf die ERSTE referenziert. (Auf diese Art kann ich "freie Tastenbelegung" machen oder "Mehrspieler" usw.)
    Die zweite Tabelle hat z.B. 8 Bytes (oder 12 oder 15 oder was auch immer) und die Entsprechungen sehen z.B. für 8 Bytes so aus:
    HOCH, RUNTER, LINKS, RECHTS, FEUER, SPRUNG, SPEZIAL1, SPEZIAL2.
    Die Bytes enthalten dann die Stelle in der ERSTEN Tabelle, die abgefragt/geprüft werden.
    Ich mache das nur so, weil ich diese Tastaturabfragen etc in eine generalisierte Unit getan habe. Man KANN es natürlich auch so machen, daß man gleich im Interrupt NUR DIE Tasten abfragt, die man für das Spiel braucht, für diese in einer "kleinen" Tabelle (Anzahl Tasten) ein Bit oder Byte setzt, wen gedrückt/losgelassen und die anderen Tasten ignoriert.

    Vielleicht ist Dir damit etwas geholfen.
    Achja - wie das natürlich in so ganz "modernen" OS läuft und ob so etwas wie Zugriff auf die Ports dort überhaupt erlaubt/erwünscht/möglich ist, kann ich nicht sagen. Wäre aber wirklich schade, wenn man da pollen oder den Tastaturtreiber benutzen müßte...

    Achja, noch eine kleine Abschlußbemerkung: Meist definiere ich dann für die "Spiel-Tasten" (also in der zweiten, kleinen Tabelle) ein Bitfeld. Dieses ist dann so ähnlich wie die Daten, die Joysticks usw liefern. So Bitfeld kann man als Byte oder Word auch leichter übertragen, beispielsweise, wenn man die Eingabe, die Berechnung/Steuerung und die Ausgaben eines Spiels voneinander getrennt hält. Dann ist das "Interface" zwischen Eingabe und Verarbeitung nur ein Strom aus Bytes/Words, die die jeweiligen Zustände der Spieltasten als Bitfeld übertragen oder abfragen - außerdem ist es so leichter, wenn man Spielersteuerdaten (für Multiplayer) an andere Systeme schicken will. Oder wenn man ein sich selbst spielendes Demo bauen will (dann einfach die Daten in ein File tun).

    Anmerkung:
    Ich mache es meist zusätzlich so, daß ich einen Ticker setze (IRQ0, INT 8), den z.B. auf 50 Hz oder 100 Hz oder wasauchimmer. Und der fragt dann die Spiel-Tasten für jede Figur bei jedem "Tick" ab und legt das Bitfeld in einen Ringpuffer. Das "Steuerprogramm" pollt dann, wenn es Zeit hat, aus diesem Ringpuffer die Bitfelder, wenn es sie braucht.

    Grund dafür ist, daß z.B. die Ausgabe der Spielsituation als Grafik oder die Generierung von Sound etwas Zeit beanspruchen kann und dies nicht gleichzeitig mit der Spielsteuerung passieren kann (sondern alles eben immer abwechselnd, wenn auch sehr schnell). Und diese Ringpuffer sind dazu da, wenn nicht bei voller Framerate gespielt werden kann - damit trotzdem alle Tastendrücke/loslassen erfaßt und verarbeitet werden. D.h. man durchläuft eine "Spiel-Schleife":
    * Grafik-Ausgabe
    * Sound generieren (und in Soundpuffer legen)
    * {WARTEN] - Erklärung unten
    * Steuerungs-Routinen starten.
    * Zurück zum Anfang, wenn Abbruchbedingung noch nicht erreicht

    Die Steuerungsroutine führt wird nun so viele Male ausgeführt, wieviele Ticks seit dem letzten Aufruf aufgelaufen sind - entsprechend viele Steuer-Bitmasken liegen für jede (Spieler-) Figur ja auch im Ringpuffer bereit.

    Auf die Art ist das Spiel an sich immer "gleich schnell" (nur unterschiedliche Grafik-Framerate).
    [WARTEN] erklärt sich so: Wenn trotz Grafikausgabe, Soundberechung u.ä. trotzdem seit dem letzen Aufruf der Steuer-Routinen kein weiterer TICK erfolgt ist, muß hier auf mind. einen TICK gewartet werden. Dies ist "idle"-Zeit, die kann man auch gerne irgendwelchen Zeitscheiben-Verwaltern schenken, wenn man weiß, daß die bei einem TICK wieder zurückkommen. Dieser Fall tritt auf, wenn der Computer wahnsinnig schnell ist, das Spiel wahnsinnig einfach ist und/oder der Programmierer wahnsinnig effizienten Code schreibt - oder mehrere der Dinge.

    So - das war nun vielleicht wieder etwas mehr Information als eigentlich nötig gewesen wäre. Und vielleicht wäre es für ein einfaches PONG wie mit Kanonen auf Spatzen geschossen. Such Dir einfach davon raus, was Du gebrauchen kannst.

    Ich hoffe, ich konnte helfen.
    hexagon gefällt das.
  7. freecrac

    freecrac Active Member c-b Experte

    Ich denke schon. :cool:
    Es beginnt mit dem Blick auf die Berechnung der Adress-Zeiger innerhalb unserer Tabellen und Ringpuffer, damit eine Verzahnung der zu steuernden Geschehnisse wie gewünscht erfolgen kann.

    Dirk
  8. hexagon

    hexagon Member

    Vielen dank für die ausführliche antwort, wenn ich mahl ein richtiges spiel/OS schreibe, werde ich es auf jedenfall so machen wie du beschreben hast.

    allerdings befürchte ich, das ich das bei meinem Pong nicht einsetzen kann, da es halt in 512byte passen soll und ich für die tastenabfrage nicht viel mehr als 70 bytes habe .
    ich befüchte das ich das nicht klein genug implamentiert bekommen.

    Aber vielen dank das ist wirklich ne seeh hilfreiche und ausführliche antwort gewesen.

    hexagon
  9. beepsoft

    beepsoft Well-Known Member c-b Team

    Hallo,
    wieso sollte das nicht in <70 Byte passen. Wie Xpyder doch schon gesagt hat, du brauchst ja für das Spiel keine vollständige Tabelle.
    Code (Text):
    Quelltext kopieren
    1.  
    2. tastatureingabe:
    3. in al,60h
    4. cmp al, 72
    5. je rauf
    6. cmp al, 80
    7. je runter
    8. jmp tastatureingabe
    9.  
    Nur so eine Idee.

    LG
  10. hexagon

    hexagon Member

    ich danke euch beiden, ich werde das pong entsprechent umbauen, ich wuste nur nicht das ich einen atastendruck so einfach lesen kan.

    hexagon
Die Seite wird geladen...
Ähnliche Themen - Mehrere tastendrücke gleichzeitig Forum Datum
Button mehrere Funktionen zuweisen JavaScript 5. Februar 2018
mehrere Dateien mit Hilfe von Batch umbenennen Sonstige Programmiersprachen 30. Januar 2018
Pointer auf Struct/ mehrere .c Files C/C++ 9. Januar 2018
Dropdown mit mehreren Variablen Java 25. November 2017
Frage zu DLL (mehrere Instanzen) C/C++ 7. Juli 2017