2011-12-02 28 views
1

我有一個項目。這是一個簡單的遊戲,「下降塊」。遊戲區域被視爲網格,其大小爲20x20。屏幕頂部將會出現墜落的積木,底部會出現一個英雄,他們會射擊這些積木。遊戲的目標是在他們到達底線之前拍攝積木。他總是處於底線。只要用戶按下鍵盤上的空格按鈕,我就會生成一個子彈,而英雄用右鍵和左鍵在底線上移動。我對使用Turbo C++ 3.0處理這些鍵盤中斷沒有任何想法。禁止使用「dos.h」和「int 21H」。你能否給我這些項目的提示?用Turbo C++ 3.0處理鍵盤中斷

編輯:我發現這個信息,但我不明白如何實現它:

當一個鍵被按下鍵盤上的,名爲「使代碼」掃描代碼一起中斷產生當鍵發佈了「break code」是由鍵盤控制器產生的。在PC上,鍵盤由芯片控制並分配給端口號60h和61h。當鍵盤上的按鍵被按下時,掃描值將在60h進入寄存器。你可以用下面的命令得到這個掃描碼: in al,60h 得到掃描碼之後,必須在61h用以下命令重置鍵盤編程芯片的命令寄存器: in al,61h 或al ,82h out 61h,al 和al,7fh out 61h,al 在每個中斷服務程序結束時,清除PIC服務位,發送中斷結束(EOI)命令20h到地址爲20h的PIC端口。 mov al,20h out 20h,al

+3

爲什麼使用Turbo C++ 3.0?它已經20歲了;自那時起,語言已經有了很大的改進。 – Joe

+0

:)你是對的,但它是一個功課:( – Jemo

+0

嘗試getch()。光標字符是00 + another_byte – DrNoone

回答

2

文件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; 
} 

文件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 

輸出:

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: "?" 

現在,關於如何編譯這個有些話。

使用nasm.exe -f obj kbda.asmNASM編譯彙編文件。它會產生kbda.obj。在Borland/Turbo C/C++ IDE中創建一個項目,其中包含kbdc.ckbda.obj。確保代碼將被編譯爲小型或微型內存模型(基本上,我們需要確保SetNewIrq9Isr()RestoreOldIrq9Isr()將被稱爲近函數)。編譯它。

有幾點注意事項。

首先,沒有一個getc()gets()scanf()等功能將好象叫SetNewIrq9Isr()RestoreOldIrq9Isr()之間的合作。他們將掛起該程序。

其次,代碼不會跟蹤shift,controlalt鍵。這對您意味着,如果您通過按ctrl+F9從IDE內部運行此程序,那麼在程序結束時,IDE很可能認爲ctrl仍然處於按住狀態。要「解鎖」鍵盤,您必須按下並釋放ctrl。如果在此程序啓動時按住其他類似按鍵,也可能會出現這種情況。您可以包含額外的代碼,以等待發布shiftcontrolalt。我相信你可以在BIOS數據區找到它們的當前狀態。

當然,您可以將程序集文件從NASM語法轉換爲TASM語法並使用TASM進行編譯。我只是使用免費工具,Turbo C++ 1.01和NASM。

UPDATE:這裏是ASM文件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 

您使用tasm.exe /ml kbda.asm編譯。其餘的都是一樣的。

+0

當然,它是INT 9,IRQ 1,而不是IRQ 9。 t就是這個名字。 –

0

我在日子裏也回來了類似的課程。基本上你需要做的是在系統鍵盤中斷處理程序處理之前捕捉鍵盤中斷。 您需要創建自己的中斷處理程序,並將其綁定到鍵盤中斷。一旦完成工作,請調用原始系統鍵盤中斷處理程序。