程序集x86 - 鼠标光标隐藏绘制的像素

时间:2015-05-10 07:38:27

标签: assembly

我目前正在asm x86中创建类似Windows的绘画。

我有一个在两点之间创建一条线的程序。输入是鼠标左键单击的位置。

问题是,每当我画线时,都会删除位于所示光标下方的像素。

我该如何解决?

代码:

IDEAL
MODEL small
STACK 100h
DATASEG
input db 6 dup (0)
FirstPointX dw ?
FirstPointY dw ?
CurrentPointX dw ?
CurrentPointY dw ?
LineDown    db  13,10,'$'

CODESEG
y           equ [word bp+16]
x           equ [word bp+14]
StepVal     equ [word bp+12]
deltaY      equ [word bp+10]
deltaX      equ [word bp+8]
x2          equ [word bp+6]
y2          equ [word bp+4]


proc FreePolygon
    push bp
    mov di,1h

        MouseLP:
        mov ax,3h
        int 33h
        and bx,1h
        cmp bx, 1h ; check left mouse click
        jne MouseLP
        WaitForMouseRelease:

        int 33h
        cmp bx,1h
        je WaitForMouseRelease
        shr cx,1 ; adjust cx to range 0-319, to fit screen
        sub dx, 1 ; move one pixel, so the pixel will not be hidden by mouse
        mov bh,0h
        mov al,4
        mov ah,0Ch
        int 10h
        cmp di,1h
        jne notFirstPoint
        mov [FirstPointX],cx
        mov [FirstPointY],dx
        mov [CurrentPointX],cx
        mov [CurrentPointY],dx
        notFirstPoint:
        push cx
        push dx
        dec di

        call Line
        ;mov ax,02h
        ;int 33h
        mov [CurrentPointX],cx
        mov [CurrentPointY],dx
        jmp MouseLP
    EndFreePolygon:
    push cx
    push dx
    mov ax,[FirstPointX]
    mov [CurrentPointX],ax
    mov ax,[FirstPointY]
    mov [CurrentPointY],ax
    call Line
    pop dx
    pop cx
    pop bp
    ret
endp FreePolygon


proc Line

    push bp
    mov bp,sp
    mov ax,[CurrentPointX]
    cmp ax,x2
    jng StartLine
    mov ax,x2
    mov bx,[CurrentPointX]
    mov x2,bx
    mov [CurrentPointX],ax
    mov ax,y2
    mov bx,[CurrentPointY]
    mov [CurrentPointY],ax
    mov y2,bx
    StartLine:
    mov StepVal,0
    mov ax,y2
    sub ax,[CurrentPointY]
    mov deltaY,0
    add deltaY,ax
    mov ax,x2
    sub ax,[CurrentPointX]
    mov deltaX,0
    add deltaX,ax
    cmp ax,deltaY
    jg above
    jmp less
    above:
        mov ax,[CurrentPointY]
        cmp ax,y2
        jng PosAbove
        NegAbove:
            mov ax,[CurrentPointY]
            mov y,ax
            mov ax,[CurrentPointX]
            mov x,ax
            forAboveX:
            mov ax,deltaY
            sub StepVal,ax
            mov ax,StepVal
            cmp ax,deltaX
            jl lessDeltaX
            dec y
            mov ax,deltaX
            sub StepVal,ax
            lessDeltaX:
            xor bl,bl
            push cx
            push dx
            mov cx,x
            mov dx,y
            mov ax,0c04h
            int 10h
            pop dx
            pop cx
            mov ax,x
            cmp ax,x2
            jg endLineNegAbove
            inc x
            jmp forAboveX
            endLineNegAbove:
            pop bp
            ret
        PosAbove:
            mov ax,[CurrentPointY]
            mov y,ax
            mov ax,[CurrentPointX]
            mov x,ax
            forAboveX2:
            mov ax,deltaY
            add StepVal,ax
            mov ax,StepVal
            cmp ax,deltaX
            jl lessDeltaX2
            inc y
            mov ax,deltaX
            sub StepVal,ax
            lessDeltaX2:
            xor bl,bl
            push cx
            push dx
            mov cx,x
            mov dx,y
            mov ax,0c04h
            int 10h
            pop dx
            pop cx
            mov ax,x
            cmp ax,x2
            endLine2:
            jg endLinePosAbove
            inc x
            jmp forAboveX2
            endLinePosAbove:
            pop bp
            ret
    less:
        mov ax,[CurrentPointY]
        cmp ax,y2
        jng PosLess
        NegLess:
            mov ax,[CurrentPointX]
            mov x,ax
            mov ax,[CurrentPointY]
            mov y,ax
            forLessX:
            mov ax,deltaX
            add StepVal,ax
            mov ax,StepVal
            cmp ax,deltaY
            jl lessDeltaY
            inc x
            mov ax,deltaY
            add StepVal,ax
            lessDeltaY2:
            xor bl,bl
            push cx
            push dx
            mov cx,x
            mov dx,y
            mov ax,0c04h
            int 10h
            pop dx
            pop cx
            mov ax,y
            cmp ax,y2
            endLine3:
            jg endLineNegLess
            inc y
            jmp forLessX
            endLineNegLess:
            pop bp
            ret
        PosLess:
            mov ax,[CurrentPointX]
            mov x,ax
            mov ax,[CurrentPointY]
            mov y,ax
            forLessX2:
            mov ax,deltaX
            add StepVal,ax
            mov ax,StepVal
            cmp ax,deltaY
            jl lessDeltaY
            inc x
            mov ax,deltaY
            sub StepVal,ax
            lessDeltaY:
            xor bl,bl
            push cx
            push dx
            mov cx,x
            mov dx,y
            mov ax,0c04h
            int 10h
            pop dx
            pop cx
            mov ax,y
            cmp ax,y2
            jg endLinePosLess
            inc y
            jmp forLessX2
            endLinePosLess:
            pop bp
            ret
endp Line

start:
mov ax, @data
mov ds, ax
mov ax, 13h
int 10h
;Graphic mode

mov ax,0h
int 33h
; Show mouse
mov ax,1h
int 33h




    call FreePolygon


    ;Wait for key press
    mov ah,00h
    int 16h
    ;Return to text mode



    mov ah, 0
    mov al, 2
    int 10h
    ; Return to text mode
exit:
mov ax, 4c00h
int 21h
END start

2 个答案:

答案 0 :(得分:3)

旧图形模式的鼠标驱动程序不像现有模式那样先进。它们复制鼠标指针下方的区域,在顶部绘制鼠标,当您移动鼠标时,旧区域被复制回来;然后,对新位置重复该过程。这发生在中断内部,因此您无法确定何时重新绘制鼠标并且(很快)不可见。

解决方案是在访问屏幕(写入读取)之前隐藏鼠标并在完成后再次显示。来自Ralf Brown's Interrupt list

; Hide mouse:
mov ax, 2
int 33h
.. your line drawing code here ..
; Show mouse:
mov ax, 1
int 33h

您可以自行决定何时隐藏和显示鼠标:在调用您自己的低级绘图例程之前,或在每个例程中。你甚至可以为了安全起见。多次隐藏鼠标指针不是问题,因为它保留了一个计数器,你需要相同数量的"显示"在再次绘制之前调用。

答案 1 :(得分:0)

另一种方法是使用自己的PS2鼠标处理程序自我绘制我们自己的鼠标指针到屏幕,如Cutemouse驱动程序。 http://cutemouse.sourceforge.net/

下面的IRQhandler需要添加一些函数来将运动/点击存储到已知的内存位置,我们的主程序必须绘制鼠标指针并复制屏幕的旧区域,以便我们自己的鼠标形状指针可以具有所使用的视频模式的任何大小,形式和颜色(例如,它也可以用于具有宽屏分辨率的32位真彩色视频模块,使用线性帧缓冲器和VESA-VBE-Bios:来自vesa.org的vbe3.pdf )。

(使用USB鼠标的提示:在主板BIOS内启用“USB legacy”,这会将USB鼠标的USB数据重定向到键盘控制器,因此可以像PS2鼠标一样使用。 )

checkPS2:
int 11h         ; get equipment list
test    al, 3
jz  noPS2       ; jump if PS/2-Mouse not indicated
mov bh,3
mov     ax, 0C205h
int 15h             ; initialize mouse, bh=datasize
jc noPS2
mov bh,3
mov     ax, 0C203h
int 15h             ; set mouse resolution bh
jc noPS2
mov     ax, cs
mov     es, ax
mov bx, OFFSET PS2dummy
mov     ax, 0C207h
int 15h             ; mouse, es:bx=ptr to handler
jc noPS2
xor     bx, bx
mov     es, bx      ; mouse, es:bx=ptr to handler
mov     ax, 0C207h
int 15h
ret

noPS2:
stc
ret

PS2dummy:
retf
;---------------------------------------------------------
enablePS2:
call disablePS2
mov    ax, cs
mov    es, ax
mov    bx, OFFSET IRQhandler
mov    ax, 0C207h   ; es:bx=ptr to handler
int 15h
mov bh,1        ; set mouse on
mov     ax, 0C200h
int 15h
ret
;-------------------------------
disablePS2:
xor bx, bx      ; set mouse off
mov ax, 0C200h
int 15h
xor     bx, bx
mov     es, bx
mov     ax, 0C207h  ; es:bx=ptr to handler
int 15h
ret
;---------------------------------------------------------------------------
IRQhandler:
    assume  ds:nothing,es:nothing
cld
push   ds
push   es
pusha
mov     ax, cs
mov     ds, ax
mov     bp, sp
mov     al, [bp+24+6] ; buttons
mov     bl, al
shl     al, 3         ; CF=Y sign bit
sbb     ch, ch        ; signed extension 9->16 bit
cbw                   ; extend X sign bit
mov     al, [bp+24+4] ; AX=X movement
mov     cl, [bp+24+2] ; CX=Y movement
xchg    bx, ax
neg     cx            ; reverse Y movement
popa
pop     es
pop     ds
retf