Domanda

Ho un progetto. Questo è un gioco semplice, "Falling Blocks". L'area di gioco è considerata una griglia, che ha una dimensione 20x20. Ci saranno blocchi che cadono dalla parte superiore dello schermo e un eroe in fondo, che spareranno i blocchi. Lo scopo del gioco è sparare blocchi prima di raggiungere i profitti. Rimane sempre in fondo. Ogni volta che l'utente premi il pulsante Spazio della tastiera genererò un proiettile e l'eroe si sposta sulla linea di fondo con i tasti freccia destro e sinistro. Non ho idea di gestire questi interrupt della tastiera con Turbo C ++ 3.0. È vietato anche che usando "dos.h" e "int 21h". Potresti darmi suggerimenti su questi progetti?

EDIT: ho trovato queste informazioni ma non riuscivo a capire come implementarle:

Quando viene premuto un tasto sulla tastiera, viene prodotto un interrupt insieme a un codice di scansione chiamato "Make Code" e quando il tasto rilascia un "codice di interruzione" viene prodotto dal controller della tastiera. Su un PC, la tastiera è controllata da un chip e assegnata ai numeri di porta 60H e 61H. Quando viene premuto un tasto sulla tastiera, il valore di scansione viene inserito nel registro a 60H. È possibile ottenere questo codice di scansione con il seguente comando: In AL, 60H Dopo aver ottenuto il codice di scansione, è necessario ripristinare la programmazione della tastiera il registro dei comandi del chip a 61 ore con i seguenti comandi: in AL, 61H o AL, 82H 61H , Al e Al, 7fh out 61h, Al alla fine di ogni routine di servizio di interruzione, cancella il bit di servizio PIC, inviando comando End of Interrupt (EOI), 20H alla porta Pic all'indirizzo 20h. mov al, 20h out 20h, al

È stato utile?

Soluzione

File kbdc.c:

#include <stdio.h>

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("Press keys to see scan codes.\nPress ESC to exit.\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;
}

File 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

Produzione:

Press keys to see scan codes.
Press ESC to exit.
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: "?"

Ora, alcune parole su come compilare questo.

Compilare il file di assemblaggio con Nasm usando nasm.exe -f obj kbda.asm. Produrrà kbda.obj. Crea un progetto in Borland/Turbo C/C ++ IDE, includi in esso kbdc.c e kbda.obj. Assicurati che il codice venga compilato nel modello di memoria piccolo o minuscolo (fondamentalmente, dobbiamo assicurarci SetNewIrq9Isr() e RestoreOldIrq9Isr() verranno chiamati come funzioni vicine). Compilalo.

Ci sono alcuni avvertimenti.

Innanzitutto, nessuno dei getc(), gets(), scanf(), ecc. Le funzioni funzionano se chiamate tra SetNewIrq9Isr() e RestoreOldIrq9Isr(). Appenderanno il programma.

Secondo, il codice non tiene traccia del shift, control e alt chiavi. Ciò che significa per te è che, se esegui questo programma dall'IDE premendo ctrl+F9, quando il programma termina, l'IDE molto probabilmente penserà ctrl viene ancora trattenuto. Per "sbloccare" la tastiera dovrai premere e rilasciare ctrl. Lo stesso può applicarsi ad altre chiavi simili se vengono trattenuti quando inizia questo programma. Puoi includere codice extra per aspettare fino a tutti shift, control e alt sono rilasciati. Credo che tu possa trovare il loro stato attuale nell'area dati del BIOS.

Ovviamente è possibile convertire il file di assemblaggio dalla sintassi NASM alla sintassi del tasmo e compilarlo con tasmo. Sto semplicemente usando strumenti gratuiti, Turbo C ++ 1.01 e NASM.

AGGIORNARE: Ecco il file ASM per 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

Lo compili usando tasm.exe /ml kbda.asm. Il riposo è lo stesso.

Altri suggerimenti

Ho anche seguito un corso simile ai tempi. Fondamentalmente quello che devi fare è catturare l'interruzione della tastiera prima di gestire il gestore dell'interrupt della tastiera del sistema. Devi creare il tuo gestore di interrupt e il legarlo all'interrupt della tastiera. Una volta che hai finito con il tuo lavoro, chiama il gestore di interrupt della tastiera del sistema originale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top