gpt4 book ai didi

c++ - 在 MS-DOS (C/C++) 中检查某个键是否已关闭

转载 作者:IT老高 更新时间:2023-10-28 22:25:03 29 4
gpt4 key购买 nike

是的,我指的是真正的 MS-DOS,而不是 Windows 的 cmd.exe shell 控制台。

有没有办法在 MS-DOS 中检查某个键是否关闭,类似于 WinAPI 中的 GetAsyncKeyState() 函数?

目前我正在使用 kbhit()getch(),但它真的很慢,在第一个字符之后有延迟,不允许多个键同时等。

我使用的是 Turbo C++ 3.1。有人可以帮忙吗?

(顺便说一句,不要问我为什么要在这么古老的系统上编写游戏)

最佳答案

Turbo C++、MS-DOS 或 BIOS 没有提供与 Windows 函数 GetAsyncKeyState 对应的函数。 BIOS 只跟踪哪些修改键(Shift、Ctrl 或 Alt)被按住,它不跟踪任何其他键。如果你想这样做,你需要直接与键盘 Controller 对话,并监控它从键盘接收到的 make(按下键)和 break(释放键)扫描代码。

为此,您需要 Hook 键盘中断(IRQ 1,INT 0x09),从键盘 Controller 读取扫描码,然后更新您自己的键盘状态表。

这是一个简单的程序来演示如何做到这一点:

#include <conio.h>
#include <dos.h>
#include <stdio.h>

unsigned char normal_keys[0x60];
unsigned char extended_keys[0x60];

static void interrupt
keyb_int() {
static unsigned char buffer;
unsigned char rawcode;
unsigned char make_break;
int scancode;

rawcode = inp(0x60); /* read scancode from keyboard controller */
make_break = !(rawcode & 0x80); /* bit 7: 0 = make, 1 = break */
scancode = rawcode & 0x7F;

if (buffer == 0xE0) { /* second byte of an extended key */
if (scancode < 0x60) {
extended_keys[scancode] = make_break;
}
buffer = 0;
} else if (buffer >= 0xE1 && buffer <= 0xE2) {
buffer = 0; /* ingore these extended keys */
} else if (rawcode >= 0xE0 && rawcode <= 0xE2) {
buffer = rawcode; /* first byte of an extended key */
} else if (scancode < 0x60) {
normal_keys[scancode] = make_break;
}

outp(0x20, 0x20); /* must send EOI to finish interrupt */
}

static void interrupt (*old_keyb_int)();

void
hook_keyb_int(void) {
old_keyb_int = getvect(0x09);
setvect(0x09, keyb_int);
}

void
unhook_keyb_int(void) {
if (old_keyb_int != NULL) {
setvect(0x09, old_keyb_int);
old_keyb_int = NULL;
}
}

int
ctrlbrk_handler(void) {
unhook_keyb_int();
_setcursortype(_NORMALCURSOR);
return 0;
}

static
putkeys(int y, unsigned char const *keys) {
int i;
gotoxy(1, y);
for (i = 0; i < 0x30; i++) {
putch(keys[i] + '0');
}
}

void
game(void) {
_setcursortype(_NOCURSOR);
clrscr();
while(!normal_keys[1]) {
putkeys(1, normal_keys);
putkeys(2, normal_keys + 0x30);
putkeys(4, extended_keys);
putkeys(5, extended_keys + 0x30);
}
gotoxy(1, 6);
_setcursortype(_NORMALCURSOR);
}

int
main() {
ctrlbrk(ctrlbrk_handler);
hook_keyb_int();
game();
unhook_keyb_int();
return 0;
}

上面的代码已经用 Borland C++ 3.1 编译并在 DOSBox 和 MS-DOS 6.11 下运行 VirtualBox 测试。它显示了键盘的当前状态,一串 0 和 1,一个 1 表示该位置的扫描码对应的键正在被按下。按 ESC 键退出程序。

请注意,该程序不会链接原始键盘处理程序,因此当键盘中断被 Hook 时,正常的 MS-DOS 和 BIOS 键盘功能将无法工作。另请注意,它会在退出之前恢复原始键盘处理程序。这很关键,因为 MS-DOS 自己不会这样做。它还可以正确处理发送两个字节扫描码的扩展 key ,这是您在此处的答案中链接到的问题中的代码的问题。

关于c++ - 在 MS-DOS (C/C++) 中检查某个键是否已关闭,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40961527/

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