You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键优化点(解决原代码崩溃问题)

  1. 独立栈空间:显式分配4KB栈段,避免默认栈过小导致溢出
  2. 完整寄存器保护:用pusha/popa保存所有通用寄存器,防止破坏系统运行环境
  3. 正确发送EOI:处理完中断后向PIC发送结束信号,避免中断被永久屏蔽
  4. 调用原中断程序:保留系统默认键盘处理逻辑,不会破坏BIOS键盘缓冲区
  5. 清晰的状态管理:单独维护按键状态数组和特殊键标志,方便组合键检测(如右键+Ctrl)

使用说明

  • 编译命令:nasm -f bin int9_keyboard.asm -o int9_keyboard.com(生成COM格式可执行文件)
  • 组合键检测示例:右键扫描码为0x34,当ctrl_pressed为1且key_state+0x34为1时,说明右键+Ctrl组合键处于按下状态
  • 游戏整合时,可将中断安装逻辑放在游戏初始化阶段,卸载逻辑放在游戏退出阶段

内容的提问来源于stack exchange,提问作者RoelsRule

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:23:18