
























在8086汇编中,鼠标中断通常通过int 33h(鼠标BIOS中断)实现,其功能包括初始化鼠标、获取鼠标位置、处理按键等。下面我们学习一个模拟int 33h核心功能的自定义鼠标中断程序,支持鼠标初始化、位置获取、按键检测。
; 常量定义
MOUSE_DATA_PORT equ 03f8h ; 鼠标数据端口(COM1)
MOUSE_CTRL_PORT equ 03f9h ; 鼠标控制端口
MOUSE_PACKET_LEN equ 3 ; 鼠标数据包长度(3字节)
code segment
assume cs:code, ds:data
; 自定义鼠标中断服务程序(入口:AX=功能号)
; 功能:
; AX=0000h:初始化鼠标(返回BX=0表示成功)
; AX=0003h:获取鼠标状态(BX=按键状态,CX=X偏移,DX=Y偏移)
; AX=000Bh:设置鼠标显示(CX=X坐标,DX=Y坐标,显示鼠标指针)
mouse_int proc far
push ax
push bx
push cx
push dx
push si
push di
push es
push ds ; 保存所有寄存器
push bp
mov bp, sp
; 根据功能号跳转处理
cmp ax, 0000h
je mouse_init ; 初始化鼠标
cmp ax, 0003h
je get_status ; 获取鼠标状态
cmp ax, 000Bh
je show_cursor ; 显示鼠标指针
jmp int_end ; 不支持的功能
; 功能0000h:初始化鼠标
; 返回:BX=0(成功),BX≠0(失败)
mouse_init:
; 向鼠标控制器发送初始化命令(实际硬件需按协议操作)
mov dx, MOUSE_CTRL_PORT
mov al, 0Ah ; 复位命令
out dx, al
; 等待鼠标响应(简化:假设初始化成功)
mov bx, 0 ; BX=0表示成功
mov [mouse_ready], 1 ; 标记鼠标就绪
jmp int_end
; 功能0003h:获取鼠标状态
; 返回:BX=按键状态(bit0=左键,bit1=右键),CX=X偏移,DX=Y偏移
get_status:
cmp [mouse_ready], 0
je int_end ; 鼠标未初始化,直接返回
; 读取鼠标数据包(3字节:状态字节+X偏移+Y偏移)
mov si, offset mouse_packet ; SI指向数据包缓冲区
mov cx, MOUSE_PACKET_LEN
read_packet:
mov dx, MOUSE_DATA_PORT
in al, dx ; 从数据端口读取1字节
mov [si], al
inc si
loop read_packet
; 解析数据包:第1字节=状态,第2字节=X偏移,第3字节=Y偏移
mov al, [mouse_packet] ; 状态字节
mov bl, 0
test al, 01h ; 检测左键(bit0=1表示按下)
jz no_left
or bl, 01h
no_left:
test al, 02h ; 检测右键(bit1=1表示按下)
jz no_right
or bl, 02h
no_right:
mov bx, bl ; BX=按键状态
mov cl, [mouse_packet+1] ; CX=X偏移
mov ch, 0
mov cx, cx
mov dl, [mouse_packet+2] ; DX=Y偏移(注意Y方向通常与屏幕相反)
mov dh, 0
neg dx ; 反转Y偏移(适应屏幕坐标系)
jmp int_end
; 功能000Bh:显示鼠标指针(简化为在指定位置画字符)
; 入口:CX=X坐标,DX=Y坐标
show_cursor:
; 保存当前光标位置
push dx
push cx
; 转换坐标为文本模式行列(假设80x25文本模式,每个字符8x16像素)
mov ax, dx ; AX=Y坐标
mov bl, 16
div bl ; AL=行号(Y/16)
mov dh, al
mov ax, cx ; AX=X坐标
mov bl, 8
div bl ; AL=列号(X/8)
mov dl, al
; 在计算出的行列位置显示鼠标指针(用'#'表示)
mov ah, 02h ; 设置光标位置
int 10h
mov ah, 09h ; 显示字符
mov al, '#'
mov bl, 0Ch ; 红色属性
mov cx, 1
int 10h
; 恢复光标位置
pop cx
pop dx
jmp int_end
; 中断结束:恢复寄存器并返回
int_end:
pop bp
pop ds
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret ; 中断返回
mouse_int endp
; 安装自定义鼠标中断向量(替换int 33h)
install proc
cli ; 关中断
mov ax, 0
mov es, ax ; ES指向中断向量表(0段)
mov di, 33h*4 ; int 33h向量地址:33h×4=0000:00D4
mov ax, offset mouse_int ; 中断服务程序偏移
stosw
mov ax, cs ; 中断服务程序段地址
stosw
sti ; 开中断
ret
install endp
; 主程序:初始化并测试鼠标中断
main:
mov ax, data
mov ds, ax ; 初始化数据段
call install ; 安装自定义鼠标中断
; 测试1:初始化鼠标
mov ax, 0000h
int 33h ; 调用自定义中断
cmp bx, 0
jne exit ; 初始化失败则退出
; 测试2:循环获取鼠标状态并更新指针
loop_test:
mov ax, 0003h ; 获取鼠标状态
int 33h
; BX=按键状态,CX=X偏移,DX=Y偏移
; 更新鼠标绝对坐标(累加偏移)
add [mouse_x], cx
add [mouse_y], dx
; 限制坐标在屏幕范围内(320x200为例)
cmp [mouse_x], 320
jl x_ok
mov [mouse_x], 320
x_ok:
cmp [mouse_x], 0
jge y_ok
mov [mouse_x], 0
y_ok:
cmp [mouse_y], 200
jl y_ok2
mov [mouse_y], 200
y_ok2:
cmp [mouse_y], 0
jge show
mov [mouse_y], 0
show:
; 显示鼠标指针
mov ax, 000Bh
mov cx, [mouse_x] ; X坐标
mov dx, [mouse_y] ; Y坐标
int 33h
; 检测左键按下,按左键退出
test bx, 01h
jz loop_test
exit:
mov ah, 4Ch
int 21h ; 程序退出
code ends
; 数据段:保存鼠标状态和缓冲区
data segment
mouse_ready db 0 ; 鼠标就绪标记(1=就绪)
mouse_packet db 3 dup(0) ; 鼠标数据包缓冲区(3字节)
mouse_x dw 160 ; 鼠标X坐标(初始中心)
mouse_y dw 100 ; 鼠标Y坐标(初始中心)
data ends
end main代码说明
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。