我有一个项目。这是一个简单的游戏,“坠落的积木”。游戏区域被认为是一个大小为20x20的网格。将会有从屏幕顶部坠落的积木和底部的英雄,他将拍摄这些积木。游戏的目标是在积木到达底线之前投篮。他总是守口如瓶。每当用户按下键盘的空格键时,我就会生成一个子弹,英雄就会用左右箭头键在底线上移动。我不知道如何用Turbo ++ 3.0来处理这些键盘中断。也禁止使用“do.h”和"int 21H“。你能给我一些关于这些项目的提示吗?
编辑:我已经找到了这个信息,但我不明白如何实现它:
当键盘上的一个键被按下时,一个中断连同一个名为“make code”的扫描码被产生,当这个键被释放时,键盘控制器产生一个“break code”。在PC上,键盘由芯片控制,并分配给端口号60h和61h。当键盘上的一个键被按下时,扫描值在60h被放入寄存器。你可以用下面的命令得到这个扫描码: in al,60h在获得扫描码后,你必须用以下命令在61h重置键盘编程芯片的命令寄存器: in al,61h或al,82h out 61h,al and al,7fh out 61h,al在每个中断服务例程结束时,你清除PIC服务位,发送中断结束(EOI)命令,20h到地址20h的PIC端口。mov,20H out 20h,al
发布于 2011-12-03 21:38:34
文件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输出:
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.asm使用NASM编译程序集文件。它将生成kbda.obj。在Borland/Turbo C/C++ IDE中创建一个项目,其中包含kbdc.c和kbda.obj。确保代码将在小内存或微内存模型中编译(基本上,我们需要确保SetNewIrq9Isr()和RestoreOldIrq9Isr()将被作为邻近函数调用)。编译它。
这里有几个警告。
首先,如果在SetNewIrq9Isr()和RestoreOldIrq9Isr()之间调用,则getc()、gets()、scanf()等函数都不会工作。他们会挂起这个程序。
其次,代码没有跟踪shift、control和alt键。这对您来说意味着,如果您在集成开发环境中通过按ctrl+F9键运行此程序,当程序完成时,集成开发环境很可能会认为ctrl仍被按住。要“解锁”键盘,您必须按下并松开ctrl。如果在此程序启动时按住其他类似的键,也可以使用相同的方法。您可以包含额外的代码来等待所有shift、control和alt的发布。我相信您可以在BIOS数据区中找到它们的当前状态。
当然,您可以将程序集文件从NASM语法转换为TASM语法,并使用TASM对其进行编译。我只是在使用免费的工具,TurboNASM1.01和C++。
更新:以下是TASM的asm文件:
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编译它。其余的都是一样的。
https://stackoverflow.com/questions/8362168
复制相似问题