我正在尝试制作一个简单的游戏引擎/库来创建我自己的DOS游戏。 我目前正在努力使输入正常工作。我遇到的问题是处理 int 9(键盘输入)的自定义 ISR 锁定了我的程序。
注意:我通过使用编译器的_dos_getvect()和_dos_setvect()让它工作;但是,我不知道为什么我自己的自定义getInterruptVector()和setInterruptVector()不起作用。如果有人能解释原因,我将不胜感激。
查看"interrupt_hooker.c"以获取有问题的代码。
主.c
#include "input.h"
#include "stdio.h"
int main(int argc, char *argv[])
{
hookKeyboardISR();
unsigned char i = 0;
while(1)
{
printf("%i", 1);
//i = getKey(SCAN_ESC);
//printf("%i", i);
}
unhookKeyboardISR();
return 0;
}
输入.h
#ifndef INPUT_H_INCLUDED
#define INPUT_H_INCLUDED
#include "scan_codes.h"
void hookKeyboardISR();
void unhookKeyboardISR();
unsigned char getKey(unsigned char scan_code);
unsigned char isExtended();
#endif // INPUT_H_INCLUDED
输入.c
#include "input.h"
#include "interrupt_hooker.h"
#ifndef NULL
#define NULL ((void*)0)
#endif // NULL
unsigned char key_array[MAX_SCAN_CODES] = {0};
unsigned char extended_key = 0;
void __interrupt (*oldKeyboardISR)() = NULL;
unsigned char getKey(unsigned char scan_code)
{
return key_array[scan_code];
}
unsigned char isExtended()
{
return extended_key;
}
void __interrupt keyboardISR()
{
unsigned char scan_code = 0;
unsigned char temp = 0;
scan_code = inp(0x60);
outp(0x61,(temp = inp(0x61)) | 0x80);
outp(0x61,temp);
/*asm
{
in al, 60h //get scan code from keyboard controller
mov scan_code, al //put it in scan_code
in al, 61h
or al, 80h
out 61h, al
xor al, 80h
out 61h, al
}*/
switch(scan_code)
{
//if extended code
case 0xe0:
extended_key = 1;
break;
case 0xe1:
break;
default:
//check if break code
if(scan_code & 0x80){
scan_code &= 0x7f;
//set key to released
key_array[scan_code] = 0;
}
else{
//set key to pressed
key_array[scan_code] = 1;
}
extended_key = 0;
break;
}
//send EOI
outp(0x20, 0x20);
/*asm
{
sti
mov al, 20h
out 20h, al
}*/
}
void hookKeyboardISR()
{
if(oldKeyboardISR == NULL){
getInterruptVector(0x09, oldKeyboardISR);
setInterruptVector(0x09, keyboardISR);
}
}
void unhookKeyboardISR()
{
if(oldKeyboardISR != NULL){
setInterruptVector(0x09, oldKeyboardISR);
oldKeyboardISR = NULL;
}
}
interrupt_hooker.h
#ifndef INTERRUPT_HOOKER_H_INCLUDED
#define INTERRUPT_HOOKER_H_INCLUDED
void getInterruptVector(unsigned char int_number, void __interrupt (*isr)());
void setInterruptVector(unsigned char int_number, void __interrupt (*isr)());
#endif // INTERRUPT_HOOKER_H_INCLUDED
interrupt_hooker.c
void getInterruptVector(unsigned char int_number, void __interrupt (*isr)())
{
asm
{
cli
mov al, int_number
mov ah, 35h
int 21h
mov word ptr [isr], bx
mov word ptr [isr+2], es
sti
}
}
void setInterruptVector(unsigned char int_number, void __interrupt (*isr)())
{
asm
{
cli
mov dx, word ptr [isr+2]
mov ds, dx
mov dx, word ptr [isr]
mov al, int_number
mov ah, 25h
int 21h
sti
}
}
mov dx, word ptr [isr]
可能会尝试使用您刚刚破坏的ds
,除非isr
被解析为bp+offset
在这种情况下它将使用ss
,这应该很好。另外,我想编译器不会很高兴你破坏了ds
.
更安全的代码可能是:
cli
push ds
mov al, int_number
mov ah, 25h
mov dx, word ptr [isr]
mov ds, word ptr [isr+2]
int 21h
pop ds
sti
您的getInterruptVector
被破坏,因为它缺少间接级别 - 您只是在修改 C 中按值传递的参数。你必须getInterruptVector(0x09, &oldKeyboardISR);
调用它(注意&
),当然在你的函数中取消引用它,比如:
mov al, int_number
mov ah, 35h
int 21h
mov di, word ptr [isr]
mov [di], bx
mov [di+2], es
(这是假设有一个 16 位的近指针,不确定你的内存模型是什么。