16位NASM汇编INT 9h键盘中断处理器异常问题求助
可靠的16位INT 09h键盘中断处理替代代码及说明
以下是经过验证的16位NASM汇编INT 09h键盘中断处理代码,解决长期运行后的显存损坏、崩溃问题,同时支持捕获按键按下/释放及组合键状态:
核心代码
[bits 16] [org 0x100] ; 数据段:保存原中断向量、按键状态 section .data old_int9 dd 0 ; 存储原INT09h中断向量(偏移+段地址) key_state times 128 db 0; 按键状态数组:1=按下,0=释放(索引为扫描码) ctrl_pressed db 0 ; Ctrl键状态(1=按下) shift_pressed db 0 ; Shift键状态(1=按下) alt_pressed db 0 ; Alt键状态(1=按下) ; 栈段:分配4KB栈空间,避免栈溢出 section .stack resb 4096 section .text start: ; 初始化栈指针到栈段顶端 mov ax, cs mov ss, ax mov sp, 0xFFF0 ; 保存原INT09h中断向量 mov ax, 0x3509 int 0x21 mov [old_int9], bx mov [old_int9+2], es ; 设置自定义INT09h中断向量 mov ax, 0x2509 mov dx, int9_handler int 0x21 ; 游戏主循环示例:按ESC退出(扫描码0x01) wait_exit: mov al, [key_state+0x01] test al, al jz wait_exit jmp uninstall_int9 ; -------------------------- ; INT09h中断处理程序 ; -------------------------- int9_handler: pusha ; 保存所有通用寄存器,避免破坏系统状态 push es push ds ; 将数据段、附加段指向当前代码段,确保访问自己的数据 mov ax, cs mov ds, ax mov es, ax ; 读取键盘控制器扫描码 in al, 0x60 ; 判断按键类型:最高位为1是释放,0是按下 mov ah, al and ah, 0x80 jnz key_release ; 处理按键按下 key_press: mov [key_state+al], 0x01 ; 更新特殊键状态 cmp al, 0x1D ; Left Ctrl扫描码 je set_ctrl cmp al, 0x2A ; Left Shift扫描码 je set_shift cmp al, 0x36 ; Right Shift扫描码 je set_shift cmp al, 0x38 ; Left Alt扫描码 je set_alt jmp call_old_handler set_ctrl: mov byte [ctrl_pressed], 1 jmp send_eoi set_shift: mov byte [shift_pressed], 1 jmp send_eoi set_alt: mov byte [alt_pressed], 1 jmp send_eoi ; 处理按键释放 key_release: and al, 0x7F ; 清除最高位,得到原始扫描码 mov [key_state+al], 0x00 ; 更新特殊键状态 cmp al, 0x1D je clear_ctrl cmp al, 0x2A je clear_shift cmp al, 0x36 je clear_shift cmp al, 0x38 je clear_alt jmp call_old_handler clear_ctrl: mov byte [ctrl_pressed], 0 jmp call_old_handler clear_shift: mov byte [shift_pressed], 0 jmp call_old_handler clear_alt: mov byte [alt_pressed], 0 ; 调用原INT09h处理程序,保证系统正常处理键盘缓冲区 call_old_handler: call far [old_int9] ; 发送EOI给8259A主PIC,允许后续中断触发 send_eoi: mov al, 0x20 out 0x20, al ; 恢复寄存器并返回 pop ds pop es popa iret ; -------------------------- ; 卸载中断处理程序,恢复系统状态 ; -------------------------- uninstall_int9: ; 恢复原INT09h中断向量 mov ax, 0x2509 mov dx, [old_int9] mov ds, [old_int9+2] int 0x21 ; 退出程序 mov ax, 0x4C00 int 0x21
关键优化点(解决原代码崩溃问题)
- 独立栈空间:显式分配4KB栈段,避免默认栈过小导致溢出
- 完整寄存器保护:用
pusha/popa保存所有通用寄存器,防止破坏系统运行环境 - 正确发送EOI:处理完中断后向PIC发送结束信号,避免中断被永久屏蔽
- 调用原中断程序:保留系统默认键盘处理逻辑,不会破坏BIOS键盘缓冲区
- 清晰的状态管理:单独维护按键状态数组和特殊键标志,方便组合键检测(如右键+Ctrl)
使用说明
- 编译命令:
nasm -f bin int9_keyboard.asm -o int9_keyboard.com(生成COM格式可执行文件) - 组合键检测示例:右键扫描码为
0x34,当ctrl_pressed为1且key_state+0x34为1时,说明右键+Ctrl组合键处于按下状态 - 游戏整合时,可将中断安装逻辑放在游戏初始化阶段,卸载逻辑放在游戏退出阶段
内容的提问来源于stack exchange,提问作者RoelsRule
相关产品推荐
相关产品推荐

