2 Stimmen

Behandeln eines Tastaturunterbrechung mit Turbo C ++ 3.0

Ich habe ein Projekt. Das ist ein einfaches Spiel, "Falling Blocks". Der Spielbereich wird als Gitter betrachtet, das eine Größe von 20x20 hat. Es werden fallende Blöcke von oben auf den Bildschirm und ein Held unten sein, der die Blöcke abschießen wird. Das Ziel des Spiels ist es, die Blöcke abzuschießen, bevor sie die untere Linie erreichen. Der Held bleibt immer an der unteren Linie. Immer wenn der Benutzer die Leertaste der Tastatur drückt, werde ich eine Kugel erzeugen und der Held bewegt sich an der unteren Linie mit den Pfeiltasten rechts und links. Ich habe keine Ahnung, wie man diese Tastaturunterbrechungen mit Turbo C++ 3.0 behandelt. Die Verwendung von "dos.h" und "int 21H" ist ebenfalls verboten. Könntest du mir Hinweise zu diesem Projekt geben?

Bearbeiten: Ich habe diese Informationen gefunden, aber ich konnte nicht verstehen, wie man sie umsetzt:

Wenn eine Taste auf der Tastatur gedrückt wird, wird ein Interrupt zusammen mit einem Scan-Code namens "make code" vom Tastaturcontroller erzeugt und wenn die Taste losgelassen wird, wird ein "break code" erzeugt. Auf einem PC wird die Tastatur von einem Chip gesteuert und den Portnummern 60h und 61h zugeordnet. Wenn eine Taste auf der Tastatur gedrückt wird, wird der Scan-Wert in den Register bei 60h gelegt. Sie können diesen Scan-Code mit dem folgenden Befehl erhalten: in al,60h Nachdem Sie den Scan-Code erhalten haben, müssen Sie die Tastatur neu starten, indem Sie das Befehlsregister des Chips bei 61h mit den folgenden Befehlen programmieren: in al,61h or al,82h out 61h,al and al,7fh out 61h,al Am Ende jedes Unterbrechungsdienstroutinen löschen Sie das PIC Service-Bit, indem Sie den Befehl End Of Interrupt (EOI) 20h an den PIC-Port an Adresse 20h senden. mov al,20h out 20h,al

3voto

Alexey Frunze Punkte 59460

Datei kbdc.c:

#include 

extern void SetNewIrq9Isr(void);
extern void RestoreOldIrq9Isr(void);

#define SCAN_BUF_SIZE 1024

extern volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
extern volatile unsigned ScanReadIdx;
extern volatile unsigned ScanWriteIdx;

const char ScanToChar[] =
  "??1234567890-=??"
  "QWERTYUIOP[]??AS"
  "DFGHJKL;\"`?\\ZXCV"
  "BNM,./??? ";

int IsScanCodeAvailable(void)
{
  return ((ScanWriteIdx - ScanReadIdx) & (SCAN_BUF_SIZE - 1)) != 0;
}

unsigned char GetScanCode(void)
{
  unsigned char code;

  while (!IsScanCodeAvailable());

  code = ScanBuf[ScanReadIdx];

  ScanReadIdx++;
  ScanReadIdx &= SCAN_BUF_SIZE - 1;

  return code;
}

int main(void)
{
  SetNewIrq9Isr();

  printf("Drücken Sie Tasten, um Scan-Codes zu sehen.\nDrücken Sie ESC zum Beenden.\n");

  for (;;)
  {
    unsigned code, symbol;

    code = GetScanCode();

    symbol = code & 0x7F;
    symbol = (symbol < sizeof(ScanToChar)) ? ScanToChar[symbol] : '?';

    printf("Scan-Code: 0x%02X, Symbol: \"%c\"\n", code, (char)symbol);

    if (code == 1)
    {
      break;
    }
  }

  RestoreOldIrq9Isr();
  return 0;
}

Datei kbda.asm:

GLOBAL _SetNewIrq9Isr, _RestoreOldIrq9Isr
GLOBAL _ScanBuf, _ScanReadIdx, _ScanWriteIdx

SEGMENT _TEXT PUBLIC CLASS=CODE USE16

; void SetNewIrq9Isr(void);
_SetNewIrq9Isr:
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, [es:bx]
        mov     [_pOldIrq9Isr], ax
        mov     word [es:bx], _NewIrq9Isr

        mov     ax, [es:bx + 2]
        mov     [_pOldIrq9Isr + 2], ax
        mov     [es:bx + 2], cs

        sti

        pop     es
        pop     bx
        ret

; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr:
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, [_pOldIrq9Isr]
        mov     [es:bx], ax

        mov     ax, [_pOldIrq9Isr + 2]
        mov     [es:bx + 2], ax

        sti

        pop     es
        pop     bx
        ret

_NewIrq9Isr:
        pusha
        push    ds

        mov     ax, _DATA
        mov     ds, ax

        in      al, 60h
        push    ax

        in      al, 061h
        mov     ah, al
        or      al, 080h
        out     061h, al
        mov     al, ah
        out     061h, al

        pop     ax

        ; ScanBuf[ScanWriteIdx] = scan code;
        ; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
        mov     bx, [_ScanWriteIdx]
        mov     [_ScanBuf + bx], al
        inc     bx
        and     bx, 1023
        mov     [_ScanWriteIdx], bx

        mov     al, 20h
        out     20h, al

        pop     ds
        popa
        iret

SEGMENT _DATA PUBLIC CLASS=DATA

_pOldIrq9Isr      resd    1

; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf          resb    1024
_ScanReadIdx      dw      0
_ScanWriteIdx     dw      0

Ausgabe:

Drücken Sie Tasten, um Scan-Codes zu sehen.
Drücken Sie ESC zum Beenden.
Scan-Code: 0x10, Symbol: "Q"
Scan-Code: 0x90, Symbol: "Q"
Scan-Code: 0x11, Symbol: "W"
Scan-Code: 0x91, Symbol: "W"
Scan-Code: 0x12, Symbol: "E"
Scan-Code: 0x92, Symbol: "E"
Scan-Code: 0x02, Symbol: "1"
Scan-Code: 0x82, Symbol: "1"
Scan-Code: 0x03, Symbol: "2"
Scan-Code: 0x83, Symbol: "2"
Scan-Code: 0x04, Symbol: "3"
Scan-Code: 0x84, Symbol: "3"
Scan-Code: 0x01, Symbol: "?"

Jetzt einige Worte zur Kompilierung:

Kompilieren Sie die Assemblerdatei mit NASM using nasm.exe -f obj kbda.asm. Es wird kbda.obj erzeugt. Erstellen Sie ein Projekt in der Borland/Turbo C/C++ IDE, fügen Sie kbdc.c und kbda.obj hinzu. Stellen Sie sicher, dass der Code im kleinen oder winzigen Speichermodell kompiliert wird (wir müssen im Grunde sicherstellen, dass SetNewIrq9Isr() und RestoreOldIrq9Isr() als Near-Funktionen aufgerufen werden). Kompilieren Sie es.

Es gibt ein paar Einschränkungen.

Erstens werden keine der Funktionen getc(), gets(), scanf(), etc. funktionieren, wenn sie zwischen SetNewIrq9Isr() und RestoreOldIrq9Isr() aufgerufen werden. Sie werden das Programm zum Absturz bringen.

Zweitens hält der Code den Status der Tasten shift, control und alt nicht fest. Das bedeutet, dass, wenn Sie dieses Programm von der IDE aus ausführen, indem Sie strg+F9 drücken, die IDE wahrscheinlich denkt, dass strg immer noch gedrückt ist, wenn das Programm endet. Um die Tastatur zu "entsperren", müssen Sie strg drücken und loslassen. Das Gleiche gilt möglicherweise für andere ähnliche Tasten, wenn sie gedrückt sind, wenn dieses Programm startet. Sie können zusätzlichen Code einfügen, um zu warten, bis alle Tasten shift, control und alt losgelassen sind. Ich glaube, Sie können ihren aktuellen Status im BIOS-Datenbereich finden.

Sie können natürlich die Assemblerdatei von NASM-Syntax in TASM-Syntax konvertieren und sie mit TASM kompilieren. Ich verwende einfach kostenlose Tools, Turbo C++ 1.01 und NASM.

Aktualisierung: Hier ist die asm-Datei für TASM:

PUBLIC _SetNewIrq9Isr, _RestoreOldIrq9Isr
PUBLIC _ScanBuf, _ScanReadIdx, _ScanWriteIdx

        .386

_TEXT SEGMENT PUBLIC 'CODE' USE16
        ASSUME CS:_TEXT, DS:_DATA

; void SetNewIrq9Isr(void);
_SetNewIrq9Isr PROC NEAR
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, es:[bx]
        mov     _pOldIrq9IsrOfs, ax
        mov     word ptr es:[bx], offset _NewIrq9Isr

        mov     ax, es:[bx + 2]
        mov     _pOldIrq9IsrSeg, ax
        mov     es:[bx + 2], cs

        sti

        pop     es
        pop     bx
        ret
_SetNewIrq9Isr ENDP

; void RestoreOldIrq9Isr(void);
_RestoreOldIrq9Isr PROC NEAR
        push    bx
        push    es

        mov     bx, 9 * 4
        mov     ax, 0
        mov     es, ax

        cli

        mov     ax, _pOldIrq9IsrOfs
        mov     es:[bx], ax

        mov     ax, _pOldIrq9IsrSeg
        mov     es:[bx + 2], ax

        sti

        pop     es
        pop     bx
        ret
_RestoreOldIrq9Isr ENDP

_NewIrq9Isr PROC NEAR
        pusha
        push    ds

        mov     ax, _DATA
        mov     ds, ax

        in      al, 60h
        push    ax

        in      al, 061h
        mov     ah, al
        or      al, 080h
        out     061h, al
        mov     al, ah
        out     061h, al

        pop     ax

        ; ScanBuf[ScanWriteIdx] = scan code;
        ; ScanWriteIdx = (ScanWriteIdx + 1) & (SCAN_BUF_SIZE - 1);
        mov     bx, _ScanWriteIdx
        mov     _ScanBuf[bx], al
        inc     bx
        and     bx, 1023
        mov     _ScanWriteIdx, bx

        mov     al, 20h
        out     20h, al

        pop     ds
        popa
        iret
_NewIrq9Isr ENDP

_TEXT ENDS

_DATA SEGMENT PUBLIC 'DATA' USE16

_pOldIrq9IsrOfs   dw      ?
_pOldIrq9IsrSeg   dw      ?

; #define SCAN_BUF_SIZE 1024
; volatile unsigned char ScanBuf[SCAN_BUF_SIZE];
; volatile unsigned ScanReadIdx = 0;
; volatile unsigned ScanWriteIdx = 0;
_ScanBuf          db      1024 dup (?)
_ScanReadIdx      dw      0
_ScanWriteIdx     dw      0

_DATA ENDS

END

Kompilieren Sie es mit tasm.exe /ml kbda.asm. Der Rest ist gleich.

0voto

stdcall Punkte 25702

Ich habe auch damals einen ähnlichen Kurs besucht. Im Grunde musst du einfach die Tastaturunterbrechung abfangen, bevor sie vom System-Tastaturunterbrechungshandler bearbeitet wird. Du musst deinen eigenen Unterbrechungshandler erstellen und ihn an die Tastaturunterbrechung binden. Wenn du mit deiner Arbeit fertig bist, rufe den ursprünglichen System-Tastaturunterbrechungshandler auf.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X