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

16位NASM汇编PS/2鼠标驱动在VGA模式0x12下覆盖屏幕内容问题

解决VGA模式0x12下PS/2鼠标光标覆盖屏幕背景的问题

我正在为运行于VGA模式0x12(640x480,16色)的自定义操作系统开发16位NASM汇编的PS/2鼠标驱动。驱动已实现鼠标初始化、事件处理,并用位图掩码(mousebmp)绘制8×11像素的光标。光标移动功能正常,但会覆盖屏幕原有内容,无法保留背景。

光标覆盖背景的截图

问题原因

当前HideCursor函数直接用黑色(0x00)覆盖原光标位置,这会清除该区域的原有背景内容。正确的逻辑应该是先保存光标覆盖区域的背景像素,隐藏光标时恢复这些像素,而非用固定颜色覆盖。

解决方案

添加背景缓冲区保存光标区域的像素数据,修改DrawCursor和HideCursor函数的逻辑,实现背景的保存与恢复:

1. 添加背景缓冲区

在.data段中新增用于存储光标背景的缓冲区:

section .data
MOUSEFAIL db "An unexpected error happened!", 0
MOUSEINITOK db "Mouse initialized!", 0x0F, 0
ButtonStatus dw 0
MouseX dw 0
MouseY dw 0
; 新增:保存光标背景的缓冲区,8*11=88字节
cursorBackground times WCURSOR*HCURSOR db 0
mousebmp:
    db 0b10000000
    db 0b11000000
    db 0b11100000
    db 0b11110000
    db 0b11111000
    db 0b11111100
    db 0b11111110
    db 0b11111000
    db 0b11011100
    db 0b10001110
    db 0b00000110

2. 修改DrawCursor函数

先保存光标区域的背景像素,再绘制光标:

DrawCursor:
    pusha
    mov cx, [MouseX]
    mov dx, [MouseY]
    mov si, mousebmp
    mov di, cursorBackground ; 指向背景缓冲区

    ; 第一步:保存光标区域的背景
.saveLoopY:
    mov bp, WCURSOR
    add bp, cx
    mov bx, cx
.saveLoopX:
    mov ah, 0x0D ; BIOS功能:读取指定位置的像素
    int 0x10
    mov [di], al ; 将读取的像素存入缓冲区
    inc bx
    inc di
    cmp bx, bp
    jb .saveLoopX
    inc dx
    inc si
    mov bp, HCURSOR
    add bp, [MouseY]
    cmp dx, bp
    jb .saveLoopY

    ; 第二步:绘制光标
    mov cx, [MouseX]
    mov dx, [MouseY]
    mov si, mousebmp
    mov ah, 0x0C ; BIOS功能:写入像素

.drawLoopY:
    mov bp, WCURSOR
    add bp, cx
    mov bx, cx
    mov al, 0x0F ; 光标颜色
.drawLoopX:
    test byte [si], 0x80 ; 检查当前位图位是否为1(需要绘制)
    jz .skipDraw
    int 0x10 ; 绘制像素
.skipDraw:
    inc bx
    shl byte [si], 1 ; 移位处理下一位
    cmp bx, bp
    jb .drawLoopX
    inc dx
    inc si
    mov bp, HCURSOR
    add bp, [MouseY]
    cmp dx, bp
    jb .drawLoopY

.end:
    popa
    ret

3. 修改HideCursor函数

从缓冲区读取保存的背景像素,恢复原屏幕内容:

HideCursor:
    pusha
    mov cx, [MouseX]
    mov dx, [MouseY]
    mov di, cursorBackground ; 指向背景缓冲区
    mov ah, 0x0C ; BIOS功能:写入像素

.restoreLoopY:
    mov bp, WCURSOR
    add bp, cx
    mov bx, cx
.restoreLoopX:
    mov al, [di] ; 取出保存的背景像素
    int 0x10 ; 恢复像素到屏幕
    inc bx
    inc di
    cmp bx, bp
    jb .restoreLoopX
    inc dx
    mov bp, HCURSOR
    add bp, [MouseY]
    cmp dx, bp
    jb .restoreLoopY

.end:
    popa
    ret

代码说明

  • cursorBackground缓冲区:存储光标覆盖区域的88个像素值(8×11),确保每次绘制光标前都能保存当前背景
  • DrawCursor函数:先调用BIOS 0x10的0x0D功能读取像素保存到缓冲区,再执行原有的光标绘制逻辑
  • HideCursor函数:不再用固定颜色覆盖,而是从缓冲区读取保存的像素,调用BIOS 0x10的0x0C功能恢复原背景内容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 16:45:57