gpt4 book ai didi

c - 使用 Turbo C++ 3.0 处理键盘中断

转载 作者:行者123 更新时间:2023-12-04 06:05:53 26 4
gpt4 key购买 nike

我有一个项目。那是一个简单的游戏,“落块”。游戏区域被视为一个网格,其大小为 20x20。屏幕顶部会有掉落的方块,底部会有一个英雄,他会射击方块。游戏的目的是在他们到达底线之前射击块。他永远守在底线。每当用户按下键盘的空格键时,我会生成一个子弹,英雄通过左右箭头键移动到底线。我不知道用 Turbo C++ 3.0 处理这些键盘中断。也禁止使用“dos.h”和“int 21H”。你能给我一些关于这些项目的提示吗?

编辑:我找到了这个信息,但我不明白如何实现它:

当在键盘上按下一个键时,会产生一个中断以及一个名为“make code”的扫描代码,当释放键时,键盘 Controller 会产生一个“break code”。在 PC 上,键盘由芯片控制并分配给端口号 60h 和 61h。当在键盘上按下一个键时,扫描值被放入寄存器 60h。您可以使用以下命令获取此扫描码:
在 al,60h
得到扫描码后,必须复位键盘编程芯片的命令寄存器在 61h 使用以下命令:
在 al,61h
或 al,82h
出 61h,al
和al,7fh
出 61h,al
在每个中断服务程序结束时,您清除 PIC 服务位,发送中断结束 (EOI) 命令,20h 到地址 20h 的 PIC 端口。
移动 20 小时
出 20h,al

最佳答案

文件 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.asm 使用 NASM 编译程序集文件。它会产生 kbda.obj 。在 Borland/Turbo C/C++ IDE 中创建一个项目,在其中包含 kbdc.ckbda.obj 。确保代码将在小型或微型内存模型中编译(基本上,我们需要确保 SetNewIrq9Isr()RestoreOldIrq9Isr() 将作为近函数调用)。编译它。

有一些注意事项。

首先,如果在 getc()gets() 之间调用, scanf()SetNewIrq9Isr()RestoreOldIrq9Isr() 等函数都不起作用。他们将挂起程序。

其次,代码不会跟踪 shiftcontrolalt 键。这对您来说意味着,如果您通过按 ctrl+F9 从 IDE 中运行此程序,当程序完成时,IDE 很可能会认为 ctrl 仍在被按住。要“解锁”键盘,您必须按下并释放 ctrl 。如果在此程序启动时按住它们,则同样适用于其他类似的键。您可以包含额外的代码以等待所有 shiftcontrolalt 发布。相信您可以在 BIOS 数据区中找到它们的当前状态。

当然,您可以将汇编文件从 NASM 语法转换为 TASM 语法并使用 TASM 进行编译。我只是使用免费工具,Turbo C++ 1.01 和 NASM。

更新 :这是 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 编译它。其余的都是一样的。

关于c - 使用 Turbo C++ 3.0 处理键盘中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8362168/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com