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

x86汇编程序无法修改字符颜色求助(DOSBox环境,INTEL语法)

x86汇编鼠标颜色修改问题修复

主要问题出在这几个地方:

  • 视频内存访问位置错误:DOS文本模式里,每个字符占2字节,顺序是「ASCII码(低字节)+ 属性(高字节)」。你之前直接读es:[di]拿的是ASCII码(比如NUL的0),要改颜色得操作es:[di+1]这个属性字节,不管是选颜色还是改颜色都得这么弄。
  • 第一行判断逻辑错误:你用cmp di,80来判断是不是第一行,这会把第一行里列数超过40的地方当成其他行。直接看鼠标转成的行号dx就行,第一行的dx是0(因为shr dx,3后,Y坐标除以8得到行号)。
  • 鼠标事件监听范围不当:你设cx=11b是同时监听移动和左键按下,其实只需要监听左键按下,改成cx=0002b(二进制10)就行,避免不必要的触发。
  • 默认颜色未初始化:style变量一开始是随机值,第一次点其他行颜色会乱,给它整个默认值比如0fh(白字黑底)就好。

改好的完整代码如下:

.386
Data segment use16
    ColorOne db 2fh
    ColorMain db 0fh
    sym db 100
    style db 0fh  ; 初始化默认选中色为白字黑底
Data ends

Code segment use16
assume cs:Code, ds:Data
start:
    mov ax, DATA
    mov ds, ax
    mov ax, 0B800h
    mov es, ax

    mov ax, 3           ; 设置80x25文本模式(原3是80x25,不是35)
    int 10h 

    mov bx, 0
    xor di, di

    ; 填充第一行16个带不同背景的NUL字符
loop1:
    mov di, bx
    imul di, 2          ; 计算第一行偏移:列号bx*2
    mov ah, ColorOne        
    mov al, 0
    stosw

    add ColorOne, 10h   ; 背景色+1(属性字节高4位是背景)
    inc bx
    cmp bx, 16
    jl loop1

    mov bx, 1

loop2:
    mov cx, 0
    loop3:
        mov di, bx
        imul di, 80
        add di, cx
        imul di, 2      ; 计算偏移:行号bx*80*2 + 列号cx*2
        mov ah, ColorMain       
        mov al, sym

        stosw

        inc cx
        cmp cx, 80
        jl loop3
        
    inc bx
    inc sym
    cmp bx, 25          ; 填充第1到24行(共24行)
    jl loop2
;---------------------------------------------------------
    mov ax, 1           ; 显示鼠标光标
    int 33h

    mov ax, 0ch
    mov cx, 0002b       ; 仅监听左键按下事件(二进制10)
    push es             
    push cs
    pop  es
    lea dx, prmaus      ; 注册鼠标事件处理程序
    int 33h             
    pop es

    mov ah, 01h         ; 等待按键(避免程序直接退出)
    int 21h             

    xor cx,cx           ; 取消鼠标事件注册
    mov ax,0ch      
    int 33h

    mov ax, 3           ; 清屏
    int 10h

    mov ax, 4c00h       ; 程序退出
    int 21h 
;----------------------------------------------------------
prmaus proc far
    push ds
    push es
    pusha
    push 0b800h
    pop es  
    push Data
    pop ds

to_left_mouse:
    cmp ax, 0001h       ; 判断是否为左键按下事件(ax=1对应左键按下)
    jne to_end

    mov ax, 2           ; 隐藏鼠标光标
    int 33h

    shr  cx, 3          ; 鼠标X坐标转列号(每个字符占8像素)
    shr  dx, 3          ; 鼠标Y坐标转行号
    
    mov  di, dx
    imul di, 160        ; 行偏移:行号*160(每行80字符*2字节)
    add  di, cx
    add  di, cx         ; 列偏移:列号*2 → 总偏移di=dx*160 + cx*2

    cmp  dx, 0          ; 判断是否点击第一行
    jne  another_row
first_row:
    ; 获取第一行对应位置的属性字节(es:[di+1]是属性)
    mov  al, es:[di+1]  
    mov  style, al      ; 保存选中的颜色
    jmp  to_end         
another_row:
    ; 将选中的颜色设置到对应位置的属性字节
    mov  al, style
    mov  es:[di+1], al  
to_end:
    mov ax, 1           ; 恢复显示鼠标光标
    int 33h

    popa
    pop es
    pop ds
    retf
prmaus  endp
Code ends
end start

额外提一句:原代码里mov ax,3是设置80x25文本模式,不是80x35,如果要80x35的话可以用ax=12h(VGA模式),但得确保DOSBox支持。另外鼠标事件里,ax=1才是左键按下,之前你写的cmp ax,10b(也就是ax=2)是右键按下的判断,这也得改过来。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:44:56