C语言 Dos 中断处理程序锁定程序



我正在尝试制作一个简单的游戏引擎/库来创建我自己的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 位的近指针,不确定你的内存模型是什么。

最新更新