2011-12-02 73 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

我在日子里也回来了类似的课程。基本上你需要做的是在系统键盘中断处理程序处理之前捕捉键盘中断。 您需要创建自己的中断处理程序,并将其绑定到键盘中断。一旦完成工作,请调用原始系统键盘中断处理程序。