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

Emu8086中X86汇编菜单文本左键点击功能失效问题排查

修复Emu8086中鼠标点击菜单退出功能失效的问题

以下是针对你代码中问题的分析和修复方案:

核心问题分析

1. 鼠标按键判断逻辑颠倒

在buttonStatus过程中,int 33h ax=03h返回的bx寄存器中,bit0为1表示左键按下,但当前代码按下左键时会跳去noClick,不记录坐标,导致点击事件根本没被捕获:

test bx,01h
jnz noClick  ; 这里逻辑反了!按下左键时应该记录坐标,而不是跳过

2. 等待点击的条件无效

waitForClick循环中的jnc waitForClick没有依据,因为buttonStatus过程从未设置CF标志位,导致循环无法正确响应点击事件。

3. 坐标单位不匹配+寄存器使用错误

  • 菜单的X/Y是文本模式的列/行号(每个字符占8x16像素),而鼠标返回的是像素坐标,直接比较数值完全不匹配。
  • 鼠标坐标变量clickX/clickY是16位的dw,但代码中用8位寄存器cl/dl读取,导致坐标值被截断。

修复后的完整代码

multi-segment executable file template.
data segment
    
    votar db "Votar",13,10,"$"
    gerir db "Gerir",13,10,"$"
    creditos db "Creditos",13,10,"$"
    sair db "Sair",13,10,"$"
    teste db "Teste",13,10,"$"
    
    ; 菜单的文本列/行号(从0开始)
    votarCol db 38
    votarRow db 04
    gerirCol db 38
    gerirRow db 08
    creditosCol db 38
    creditosRow db 12 
    sairCol db 38
    sairRow db 16
    
    ; 鼠标像素坐标(16位)
    clickX dw 00
    clickY dw 00
    
ends

stack segment
    dw   128  dup(0)
ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov es, ax

    ; 打印菜单
    call printVotar
    call printGerir
    call printCreditos
    call printSair
       
    call initMouse
    
waitForClick:
    call buttonStatus
    jz waitForClick  ; 未点击则继续等待
    call clickLocation
    jmp waitForClick
    
exitOS:
    mov ax, 4c00h ; 退出到操作系统
    int 21h
    
;****FUNCTIONS****

printf proc
    mov ah,09h
    int 21h
    ret
endp

moveCursor proc
    mov ah,02h
    mov bh, 0
    int 10h
    ret
endp

printVotar proc
    mov dl,votarCol
    mov dh,votarRow
    call moveCursor
    mov dx,offset votar
    call printf
    ret
endp

printGerir proc
    mov dl,gerirCol
    mov dh,gerirRow
    call moveCursor
    mov dx,offset gerir
    call printf
    ret
endp

printCreditos proc
    mov dl,creditosCol
    mov dh,creditosRow
    call moveCursor
    mov dx,offset creditos
    call printf
    ret
endp

printSair proc
    mov dl,sairCol
    mov dh,sairRow
    call moveCursor
    mov dx,offset sair
    call printf
    ret
endp

initMouse proc
    mov ax,00h
    int 33h
    cmp ax,0FFFFh
    je showMouse
    ; 鼠标初始化失败则直接退出
    jmp exitOS
    
showMouse:
    mov ax,01h
    int 33h ; 显示鼠标指针
    ret
endp

buttonStatus proc
    mov ax,03h
    int 33h ; 获取鼠标状态和坐标
    test bx,01h
    jz noClick ; 左键未按下则返回
    ; 保存鼠标像素坐标
    mov clickX,cx
    mov clickY,dx
    stc ; 设置CF表示有点击
    ret
    
noClick:
    clc ; 清除CF表示无点击
    ret
endp 

clickLocation proc
    push cx
    push dx 
    
    mov cx,clickX
    mov dx,clickY
    
    ; 转换鼠标像素坐标为文本列/行号(80x25模式:8像素/列,16像素/行)
    mov ax,dx
    mov bl,16
    div bl ; al = 行号(dh对应的数值),ah = 剩余像素
    mov dl,al ; 鼠标所在文本行
    
    mov ax,cx
    mov bl,8
    div bl ; al = 列号(dl对应的数值),ah = 剩余像素
    mov cl,al ; 鼠标所在文本列

; 检查Votar选项
checkVotar:
    cmp dl,votarRow
    jne checkGerir
    cmp cl,votarCol
    jl checkGerir
    mov al,votarCol
    add al,5 ; "Votar"长度5
    cmp cl,al
    jg checkGerir
    mov dx,offset teste
    call printf
    jmp endLocation

; 检查Gerir选项
checkGerir:
    cmp dl,gerirRow
    jne checkCreditos
    cmp cl,gerirCol
    jl checkCreditos
    mov al,gerirCol
    add al,5 ; "Gerir"长度5
    cmp cl,al
    jg checkCreditos
    mov dx,offset teste
    call printf
    jmp endLocation

; 检查Creditos选项
checkCreditos:
    cmp dl,creditosRow
    jne checkSair
    cmp cl,creditosCol
    jl checkSair
    mov al,creditosCol
    add al,8 ; "Creditos"长度8
    cmp cl,al
    jg checkSair
    mov dx,offset teste
    call printf
    jmp endLocation

; 检查Sair选项
checkSair:
    cmp dl,sairRow
    jne endLocation
    cmp cl,sairCol
    jl endLocation
    mov al,sairCol
    add al,4 ; "Sair"长度4
    cmp cl,al
    jg endLocation
    ; 点击Sair,退出程序
    mov ax, 4c00h
    int 21h

endLocation:
    pop dx
    pop cx
    ret
endp    

ends

end start ; set entry point and stop the assembler.

关键修复点说明

  1. 修正鼠标按键判断:

    • 在buttonStatus中,左键按下时保存坐标并设置CF,未按下时清除CF,waitForClick用jz waitForClick判断(无点击则循环)。
  2. 坐标单位转换:

    • 将鼠标像素坐标转换为文本模式的列/行号(80x25模式下,每列8像素,每行16像素),这样才能和菜单的列/行号正确比较。
  3. 修正字符串长度判断:

    • 每个菜单文本的长度不同,比如"Sair"是4个字符,所以列范围是[sairCol, sairCol+4),确保点击区域准确覆盖文本。
  4. 简化鼠标初始化逻辑:

    • 如果鼠标初始化失败(返回ax=0),直接退出程序,避免后续错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:59:51