惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - Franky
N
Netflix TechBlog - Medium
Google Online Security Blog
Google Online Security Blog
月光博客
月光博客
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
V
V2EX
腾讯CDC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
M
MIT News - Artificial intelligence
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
aimingoo的专栏
aimingoo的专栏
博客园 - 三生石上(FineUI控件)
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
F
Full Disclosure
G
Google Developers Blog
罗磊的独立博客
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
J
Java Code Geeks
A
About on SuperTechFans
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
有赞技术团队
有赞技术团队
GbyAI
GbyAI
雷峰网
雷峰网
T
The Blog of Author Tim Ferriss
The Register - Security
The Register - Security
U
Unit 42
D
Docker
Martin Fowler
Martin Fowler
L
LINUX DO - 热门话题
NISL@THU
NISL@THU
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
博客园_首页
Google DeepMind News
Google DeepMind News

faryou的博客

5月月考 - faryou的博客 - 日记 faryou的博客-五一回老家 【汇编 - 功能】中断安装中断实现 【汇编&硬件】时钟中断的具体实现 faryou的博客-这些年,我不再看《熊出没》 【汇编&硬件】关机中断的具体实现 【汇编&硬件】网络连接相关中断的具体实现 faryou的博客-年初小记 【汇编&硬件】声音输出中断的具体实现 【汇编&硬件】屏幕输出中断的具体实现 【汇编&硬件】磁盘读取中断的具体实现 【汇编&硬件】键盘读取中断的具体实现 【汇编】汇编环境的搭建及Debug的使用教程 【汇编】漫谈:学习汇编后的一些思考 faryou的博客-关于本站即日起实行“一站三体”运营制度 【汇编基础教程】完结篇 写在最后:前言 【汇编基础教程】使用BIOS的中断实现键盘输入及磁盘I/O 【汇编基础教程】中断 【汇编基础教程】端口 【汇编基础教程】标志寄存器 【汇编基础教程】再谈栈 【汇编基础教程】段 【汇编基础教程】来存一些数据! 【汇编基础教程】寄存器和内存&一些基本命令的说明 【汇编基础教程】来写个“函数” 【汇编基础教程】更灵活的定位内存 【汇编基础教程】理解一下[bx]和loop指令 【汇编基础教程】跳一跳! faryou的博客-我的竞赛经历&对人生的一些思考 faryou的博客-关于现在中小学计算机课的一些想法及思考 faryou的博客-2025年度总结 faryou的博客-临平山下十五年 faryou的博客-Windows 10即将停止支持,谈谈自己从小到大用电脑的感受 faryou的博客-谈谈一名10后的怀旧情怀 【汇编基础教程】8086CPU工作原理 【C语言】指针的理解与应用 【算法教程】【C/C++】DP(动态规划):区间DP——程序设计思路与代码实现 【算法教程】【C/C++】BFS(广度优先搜索)——程序设计思路与代码实现 【算法教程】【C/C++】DFS(深度优先搜索)——程序设计思路与代码实现 【算法教程】【C/C++】单源最短路径——程序设计思路与代码实现 【算法教程】【C/C++】最小生成树——程序设计思路与代码实现 【算法教程】【C/C++】并查集——程序设计思路与代码实现 【算法教程】【C/C++】DP(动态规划):背包DP——程序设计思路与代码实现 【算法教程】【C/C++】DP(动态规划):简单动规问题——程序设计思路与代码实现 【算法教程】【C/C++】递推——程序设计思路与代码实现 【算法教程】【C/C++】三分算法——程序设计思路与代码实现 【算法教程】【C/C++】二分答案——程序设计思路与代码实现 【算法教程】【C/C++】二分查找——程序设计思路与代码实现 【算法教程】【C/C++】贪心算法——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:快排——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:快速幂——程序设计思路与代码实现 【算法教程】【C/C++】基础数学:进制转换——程序设计思路与代码实现 一文弄懂C++中的自定义函数 faryou的博客-2024年度总结
【汇编&硬件】鼠标控制中断的具体实现
作者: faryou · 2026-03-14 · via faryou的博客

前言

在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

代码说明

  1. 中断功能设计:模拟int 33h的核心功能,包括鼠标初始化(检测鼠标是否存在)、状态获取(按键和移动偏移)、指针显示(在指定坐标画字符模拟指针)。
  2. 鼠标数据处理:a.鼠标通过串行端口(如COM1,端口03f8h)通信,数据包为3字节(状态字节+X偏移+Y偏移)。b.状态字节的bit0表示左键按下,bit1表示右键按下;X/Y偏移表示相对移动量。
  3. 指针显示:简化为在文本模式下,将鼠标坐标转换为行列位置,显示字符 # 作为指针(实际图形模式需绘制鼠标形状)。
  4. 中断安装:修改中断向量表中int 33h的入口地址,指向自定义服务程序,安装时关中断以避免冲突。