我目前正在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
答案 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