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
相关产品推荐
相关产品推荐

