comment ^
included by video.asm
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Mouse Driver v1.32
by : Peter Quiring
date: April 10,96
updated: May 1,96
updated: Oct 18,96
updated: Dec 5,96 (added support for text modes - easy)
(added mouse_setcursor_text(color) )
updated: Mar 12,97 (supports text modes properly)
Generic mouse handler. (for 24/16/8 bit modes and Text modes)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!^
.data
m_paws db 0 ;special printing mouse thingy
m_pp dd offset v_pp ;are switched to v_?p2 when using _v_buffer
m_gp dd offset v_gp
maxsiz equ 64 ;maximum size of cursor (x and y) must be a power of 2
moved db 0
cursor_color db 0 ;used in text mode only
backbuf db (maxsiz*maxsiz) dup (0) ;temp buffer
dd ? ;very important!!
cbb dd offset backbuf ;current backbuf
oldbank db 0 ;backup of vesa_current_bank
oldplane_wr db 0 ;backup of modex_plane_wr
oldplane_rd db 0 ;backup of modex_plane_rd
align 4
prevx dw 0
prevy dw 0
inited db 0
align 4
xpos dw 0
ypos dw 0
default_cur dd 01010101h ;just in case!
cur dd offset default_cur
userproc dd 0 ;callback routine
userproc_s dd 0 ;callback routine
curx db 1 ;size x
cury db 1 ;size y
hpx dw 0 ;hot point x
hpy dw 0 ;hot point y
mouse_con dw 0 ;cursor on?
but dw 0 ;button states
minx dw 0
miny dw 0
maxx dw (319) ;These are absolute min that maxx,maxy could be
maxy dw (199)
mx dw 0 ;the x after ratio shift
my dw 0 ;the y after ratio shift
once db 0 ;set the 1st time mouse_hand is used
xratio db 1
yratio db 1
.code
mouse_hand proto
mouse_init proc
pushad
mov ax,0
int 33h
cmp ax,0
jnz @f
popad
mov eax,ERROR
ret
@@:
.if inited
popad
mov eax,ERROR
ret
.endif
mov inited,1
push cs
pop es
mov edx,offset mouse_hand
mov cx,0ffh ;all movement & buttons cause a callback
mov ax,0ch
int 33h ;PMODE/W extender INT
mov es,seldata
;setup self-uninit
callp atexit,offset mouse_uninit
;setup X/Y
mov ax,wptr[_v_x]
dec ax
mov maxx,ax
mov ax,wptr[_v_y]
dec ax
mov maxy,ax
popad
xor eax,eax
ret
mouse_init endp
mouse_uninit proc ;will self-uninit during atexit procedure
pushad
;disable callback thingy
push dptr 0 ;32bit !!!
pop es
xor edx,edx
xor ecx,ecx ;no movement & buttons cause a callback
mov ax,0ch
int 33h
mov es,seldata
mov inited,0
popad
ret
mouse_uninit endp
;mask for callbacks
; CX = : bit # : cause because...
; 0 cursor moved
; 1 left pressed
; 2 left released
; 3 right pressed
; 4 right released
; 5-15 not used
;5,6=middle button (if 3 button)
align 4
mouse_setcursor proc uses ebx,_cur:dword
;ONLY called when mouse is off or from the callback
mov ebx,_cur
mov cur,ebx
add cur,sizeof g_mousehead
xor eax,eax
mov ax,[ebx].g_mousehead.x
cmp al,maxsiz ;FIX : v2.03 Beta #4 : this was 'and'?
jbe @f
mov al,maxsiz
@@:
mov curx,al
mov ax,[ebx].g_mousehead.y
cmp al,maxsiz ;FIX : v2.03 Beta #4 : this was 'and'?
jbe @f
mov al,maxsiz
@@:
mov cury,al
mov ax,[ebx].g_mousehead.hx
mov hpx,ax
mov ax,[ebx].g_mousehead.hy
mov hpy,ax
xor eax,eax
ret
mouse_setcursor endp
mouse_setcursor_text proc,_color:byte
mov al,_color
mov cursor_color,al
ret
mouse_setcursor_text endp
; NOTE : all functions that do clipping are not complete clipping
; : the image must still have at least 1 pixel on screen (like a mouse ptr)
; : these clipping puts/gets are for mouse functions only!
;clipping
;this is used by the mouse functions
align 4
put0c proc private,x:dword,xl:dword,y:dword,yl:dword ;uses delta method of cords
local sadd:dword ;src add
local oxl:dword ;old x length
.if curmode==G_VESA && (banking)
mov al,vesa_current_bank
mov oldbank,al
.elseif curmode==G_MODEX
mov al,modex_plane_wr
mov oldplane_wr,al
.endif
mov eax,xl
mov oxl,eax
mov sadd,0
mov esi,cur ;source is the cursor
;do clipping
.if x&080000000h
neg x
mov eax,x
sub xl,eax
add sadd,eax
mul _v_bypp
add esi,eax
mov x,0
.endif
.if y&080000000h
neg y
mov eax,y
sub yl,eax
mul oxl
mul _v_bypp
add esi,eax
mov y,0
.endif
mov eax,x
add eax,xl
cmp eax,_v_x
jbe @f
sub eax,_v_x ;ax=overflow
sub xl,eax
add sadd,eax
@@:
mov eax,y
add eax,yl
cmp eax,_v_y
jbe @f
sub eax,_v_y
sub yl,eax
@@:
;start calc's
mov ecx,xl
mov eax,sadd
mul _v_bypp
mov edx,eax ;=sadd
mov ebx,x
put0_1:
cmp byte ptr[esi],0 ;BUG: gotta check all bytes! (test w/ masks?)
jz @f
callp m_pp,x,y,dword ptr[esi] ;EAX gone...
@@:
inc x
add esi,_v_bypp
dec ecx
jnz put0_1
put0_3:
add esi,edx
mov ecx,xl
mov x,ebx
inc y
dec yl
jnz put0_1 ;loop
.if curmode==G_VESA && banking
callp vesa_setbank,oldbank
.elseif curmode==G_MODEX
mov ah,oldplane_wr
mov al,2
mov dx,vga_SC_INDEX
mov modex_plane_wr,ah
out dx,ax ;must restore plane #
.endif
ret
put0c endp
;put clipping
;used by mouse support
align 4
putc proc private,x:dword,xl:dword,y:dword,yl:dword
local sadd:dword
local oxl:dword
.if curmode==G_VESA && banking
mov al,vesa_current_bank
mov oldbank,al
.elseif curmode==G_MODEX
mov al,modex_plane_wr
mov oldplane_wr,al
.endif
mov eax,xl
mov oxl,eax
mov sadd,0
mov esi,cbb
;do clipping
.if x&080000000h
neg x
mov eax,x
sub xl,eax
add sadd,eax
mul _v_bypp
add esi,eax
mov x,0
.endif
.if y&080000000h
neg y
mov eax,y
sub yl,eax
mul oxl
mul _v_bypp
add esi,eax
mov y,0
.endif
mov eax,x
add eax,xl
cmp eax,_v_x
jbe @f
sub eax,_v_x
sub xl,eax
add sadd,eax
@@:
mov eax,y
add eax,yl
cmp eax,_v_y
jbe @f
sub eax,_v_y
sub yl,eax
@@:
mov ecx,xl
mov eax,sadd
mul _v_bypp
mov edx,eax
mov ebx,x
putc_1:
callp m_pp,x,y,dword ptr[esi] ;EAX destroyed
add esi,_v_bypp
inc x
dec ecx
jnz putc_1
mov x,ebx
inc y
add esi,edx
mov ecx,xl
dec yl
jnz putc_1 ;loop
.if curmode==G_VESA && banking
callp vesa_setbank,oldbank
.elseif curmode==G_MODEX
mov ah,oldplane_wr
mov al,2
mov dx,vga_SC_INDEX
mov modex_plane_wr,ah
out dx,ax ;must restore plane #
.endif
ret
putc endp
;clipping!
;this is used by the mouse functions
align 4
getc proc private,x:dword,xl:dword,y:dword,yl:dword
local dadd:dword
local oxl:dword
.if curmode==G_VESA && banking
mov al,vesa_current_bank
mov oldbank,al
.elseif curmode==G_MODEX
mov al,modex_plane_rd
mov oldplane_rd,al
.endif
mov eax,xl
mov oxl,eax
mov dadd,0
mov edi,cbb
;do clipping
.if x&080000000h
neg x
mov eax,x
sub xl,eax
add dadd,eax
mul _v_bypp
add edi,eax
mov x,0
.endif
.if y&080000000h
neg y
mov eax,y
sub yl,eax
mul oxl
mul _v_bypp
add edi,eax
mov y,0
.endif
mov eax,x
add eax,xl
cmp eax,_v_x
jbe @f
sub eax,_v_x
sub xl,eax
add dadd,eax
@@:
mov eax,y
add eax,yl
cmp eax,_v_y
jbe @f
sub eax,_v_y
sub yl,eax
@@:
mov ecx,xl
mov eax,dadd
mul _v_bypp
mov edx,eax
mov ebx,x
@@:
callp m_gp,x,y
mov [edi],eax
add edi,_v_bypp
inc x
dec ecx
jnz @b
add edi,edx
mov ecx,xl
mov x,ebx
inc y
dec yl
jnz @b ;loop
.if curmode==G_VESA && banking
callp vesa_setbank,oldbank
.elseif curmode==G_MODEX
mov ah,oldplane_rd
mov al,4
mov dx,vga_GC_INDEX
mov modex_plane_rd,ah
out dx,ax ;must restore plane #
.endif
ret
getc endp
;prints mouse cursor
align 4
_print proc private
local tx:word,ty:word
.if curmode==G_TEXT
mov eax,_v_x
xor ebx,ebx
mov bx,my
shr bx,3 ;/8
shl bx,1 ;*2
mul ebx
mov bx,mx
shr bx,3 ;/8 *2
shl bx,1 ;*2
add eax,ebx
add eax,_v_linear ;0b8000h!
inc eax
mov bl,cursor_color
xor [eax],bl
ret
.endif
mov ax,mx
sub ax,hpx
mov tx,ax
mov ax,my
sub ax,hpy
mov ty,ax
.if m_paws
mov m_pp,v_pp2
mov m_gp,v_gp2
callp getc,tx,curx,ty,cury
callp put0c,tx,curx,ty,cury
mov m_pp,v_pp
mov m_gp,v_gp
callp put0c,tx,curx,ty,cury
.else
callp getc,tx,curx,ty,cury
callp put0c,tx,curx,ty,cury
.endif
ret
_print endp
align 4
erase proc private,one:byte
local tx:word,ty:word
.if curmode==G_TEXT
mov eax,_v_x
xor ebx,ebx
mov bx,my
shr bx,3
shl bx,1
mul ebx
mov bx,mx
shr bx,3
shl bx,1
add eax,ebx
add eax,_v_linear ;0b8000h!
inc eax
mov bl,cursor_color
xor [eax],bl
ret
.endif
mov ax,mx
sub ax,hpx
mov tx,ax
mov ax,my
sub ax,hpy
mov ty,ax
.if m_paws
mov m_pp,v_pp2
mov m_gp,v_gp2
callp putc,tx,curx,ty,cury
mov m_pp,v_pp
mov m_gp,v_gp
.if !one
callp putc,tx,curx,ty,cury
.endif
.else
callp putc,tx,curx,ty,cury
.endif
ret
erase endp
align 4
mouse_setpos proc,x:dword,y:dword
pushad
push mouse_con
call mouse_off
mov eax,x
mov cl,xratio
sal eax,cl ;signed shift left
mov xpos,ax
mov eax,y
mov cl,yratio
sal eax,cl
mov ypos,ax
call update
pop ax
.if ax==1
call mouse_on
.endif
popad
ret
mouse_setpos endp
align 4
mouse_hand proc private
;entry : ax=mask w/ condtion that cause this call
; : bx=buttons (bit 0=left,bit 1=right)
; : cx=horz pos (I ignore)
; : dx=vert pos (")
; : si=horz counts (mickeys)
; : di=vert " (")
pushad
pushf
push ds
push es
push fs
push gs
mov ds,cs:seldata
mov es,seldata
mov fs,seldata
mov gs,selzero
cld
; mov mask1,ax
; FIX : Ver 1.1 : Ignore ax cause Win95 does not return it properly!!!
; instead use BX which is easier anyways!
mov but,bx
.if once
mov ax,prevx
mov prevx,si
sub si,ax
mov ax,prevy
mov prevy,di
sub di,ax
.else
mov prevx,si
mov prevy,di
xor si,si
xor di,di
mov once,1
.endif
test mouse_con,1
jz @f
.if (si!=0) || (di!=0)
pushad
callp erase,0
popad
mov moved,1 ;it moved!
.else
@@:
mov moved,0
.endif
;change X/Y values
add xpos,si
add ypos,di
call update
done:
.if userproc
mov edi,userproc_s
mov ax,mx
mov [edi].mouse_user.x,ax
mov ax,my
mov [edi].mouse_user.y,ax
mov ax,but
mov [edi].mouse_user.but,ax
call [userproc] ;this is good for changing the cursor shape for new areas
.endif
.if (mouse_con)&&(moved)
call _print
.endif
exit_hand:
pop gs
pop fs
pop es
pop ds
popf
popad
retf
mouse_hand endp
align 4
mouse_setspd proc,xr:byte,yr:byte ; (1-4 , 1-4)
local x:word,y:word
pushad
push mouse_con
call mouse_off
mov ax,xpos
mov cl,xratio
sar ax,cl ;signed shift
mov x,ax
mov ax,ypos
mov cl,yratio
sar ax,cl
mov y,ax
mov al,xr
dec al
and al,3
;al=0-3
mov xratio,al
mov al,yr
dec al
and al,3
;al=0-3
mov yratio,al
mov ax,x
mov cl,xratio
sal ax,cl ;signed shift
mov xpos,ax
mov ax,y
mov cl,yratio
sal ax,cl
mov ypos,ax
call update
pop ax
.if ax==1
call mouse_on
.endif
popad
ret
mouse_setspd endp
align 4
mouse_setwin proc,x1:dword,y1:dword,x2:dword,y2:dword
pushad
push mouse_con
call mouse_off
;x
mov eax,x1
mov minx,ax
mov eax,x2
mov maxx,ax
;y
mov eax,y1
mov miny,ax
mov eax,y2
mov maxy,ax
call update
pop ax
.if ax==1
call mouse_on
.endif
popad
ret
mouse_setwin endp
;update x/y with maxx/maxy and ratios
align 4
update proc private
mov ax,xpos
mov cl,xratio
sar ax,cl
cmp ax,minx
jge @f
mov ax,minx
sal ax,cl
mov xpos,ax
sar ax,cl
@@:
cmp ax,maxx
jle @f
mov ax,maxx
sal ax,cl
mov xpos,ax
sar ax,cl
@@:
mov mx,ax
mov ax,ypos
mov cl,yratio
sar ax,cl
cmp ax,miny
jge @f
mov ax,miny
sal ax,cl
mov ypos,ax
sar ax,cl
@@:
cmp ax,maxy
jle @f
mov ax,maxy
sal ax,cl
mov ypos,ax
sar ax,cl
@@:
mov my,ax
ret
update endp
align 4
mouse_on proc
.if !curx || !cury ;mouse ptr not setup???
mov eax,ERROR
ret
.endif
pushad
cli
.if mouse_con==0
.if userproc
mov edi,userproc_s
mov ax,mx
mov [edi].mouse_user.x,ax
mov ax,my
mov [edi].mouse_user.y,ax
mov ax,but
mov [edi].mouse_user.but,ax
call [userproc]
.endif
call _print
mov mouse_con,1
.endif
sti
popad
ret
mouse_on endp
align 4
mouse_off proc
pushad
cli
.if mouse_con==1
mov mouse_con,0
callp erase,0
.endif
sti
popad
ret
mouse_off endp
align 4
mouse_setuser proc,func:dword,us:dword
push eax
.if (func==NULLPROC) || (func==0)
mov userproc,0
.else
mov eax,func ;may be 0
mov userproc,eax
mov eax,us
mov userproc_s,eax
.endif
pop eax
xor eax,eax
ret
mouse_setuser endp
align 4
v_pp proc private,x:dword,y:dword,col:dword
pushad
mov edi,_v_linear
mov eax,y
mul _v_bpsl
mov ebx,eax
mov eax,x
mul _v_bypp
add eax,ebx
.if curmode==G_MODEX
mov dx,vga_SC_INDEX
mov ebx,eax
and eax,3
mov cl,al
inc ah ;ah=1
shl ah,cl
mov al,02h
mov modex_plane_wr,ah
out dx,ax ; enable writes to plane ah
shr ebx,2
add edi,ebx
mov al,bptr[col]
mov [edi],al
popad
ret
.endif
.if curmode==G_VESA && banking
xor edx,edx
mov ebx,64*1024
div ebx ;OPT! : this div could be replaced w/ faster code
; al=bank # required
; edx=offset required (remainder)
.if al!=vesa_current_bank
callp vesa_setbank,al
.endif
add edi,edx
.else
add edi,eax
.endif
.if _v_bypp==1
mov al,bptr[col]
stosb
popad
ret
.endif
.if _v_bypp==2
mov ax,wptr[col]
stosw
popad
ret
.endif
.if _v_bypp==3
mov al,bptr[col]
stosb
mov al,bptr[col+1]
stosb
mov al,bptr[col+2]
stosb
popad
ret
.endif
;_v_bypp=4
mov eax,col
stosd
popad
ret ;FIX v 2.00: This was not here before!
v_pp endp
align 4
v_gp proc private,x:dword,y:dword
pushad
mov esi,_v_linear
mov eax,y
mul _v_bpsl
mov ebx,eax
mov eax,x
mul _v_bypp
add eax,ebx
.if curmode==G_MODEX
mov dx,vga_GC_INDEX
mov ebx,eax
and eax,3
mov ah,al
mov al,4
mov modex_plane_rd,ah
out dx,ax ; enable reads to plane ah
shr ebx,2
add esi,ebx
xor eax,eax
mov al,[esi]
mov [esp+7*4],eax
popad
ret
.endif
.if curmode==G_VESA && banking
xor edx,edx
mov ebx,64*1024
div ebx
; al=bank # required
; edx=offset required (remainder)
.if al!=vesa_current_bank
callp vesa_setbank,al
.endif
add esi,edx
.else
add esi,eax
.endif
.if _v_bypp==1
lodsb
mov [esp+7*4],eax
popad
ret
.endif
.if _v_bypp==2
lodsw
mov [esp+7*4],eax
popad
ret
.endif
.if _v_bypp==3
xor eax,eax
lodsw
shl eax,8
lodsb
mov [esp+7*4],eax
popad
ret
.endif
;_v_bypp=4
lodsd
mov [esp+7*4],eax
popad
ret
v_gp endp
;The next 2 use _v_buffer instead of using _v_linear
align 4
v_pp2 proc private,x:dword,y:dword,col:dword
pushad
mov edi,_v_buffer
mov eax,y
mul _v_xb
add edi,eax
mov eax,x
mul _v_bypp
add edi,eax
.if _v_bypp==1
mov al,bptr[col]
stosb
popad
ret
.endif
.if _v_bypp==2
mov ax,wptr[col]
stosw
popad
ret
.endif
.if _v_bypp==3
mov al,bptr[col]
stosb
mov al,bptr[col+1]
stosb
mov al,bptr[col+2]
stosb
popad
ret
.endif
;_v_bypp=4
mov eax,[col]
stosd
popad
ret
v_pp2 endp
align 4
v_gp2 proc private,x:dword,y:dword
pushad
mov esi,_v_buffer
mov eax,y
mul _v_xb
add esi,eax
mov eax,x
mul _v_bypp
add esi,eax
.if _v_bypp==1
lodsb
mov [esp+7*4],eax
popad
ret
.endif
.if _v_bypp==2
lodsw
mov [esp+7*4],eax
popad
ret
.endif
.if _v_bypp==3
lodsw
shl eax,8
lodsb
mov [esp+7*4],eax
popad
ret
.endif
;_v_bypp=4
lodsd
mov [esp+7*4],eax
popad
ret
v_gp2 endp
.data
ptrtmp db (sizeof g_mousehead) dup (?)
.code
align 4
mouse_loadcursor proc,nam:dword
local h:word
local buf:dword
mov buf,0
pushad
callp open,nam,0
cmp eax,ERROR
jnz @f
popad
mov eax,ERROR
ret
@@:
mov h,ax
callp read,ax,offset ptrtmp,sizeof g_mousehead
.if eax!=sizeof g_mousehead
bad:
callp free,buf
callp close,h
popad
mov eax,ERROR
ret
.endif
mov esi,offset ptrtmp
cmp dptr[esi],01a525450h ;PTR,27
jnz bad
movzx eax,[esi].g_mousehead.x
movzx ebx,[esi].g_mousehead.y
movzx ecx,[esi].g_mousehead.bypp
mov dl,[esi].g_mousehead.flg
.if dl
jmp bad
.endif
mul ebx
mul ecx
mov ebx,eax
add eax,sizeof g_mousehead
callp malloc,eax
.if eax==ERROR
jmp bad
.endif
mov buf,eax
mov esi,offset ptrtmp
mov edi,eax
mov ecx,sizeof g_mousehead
rep movsb
mov ecx,eax
add ecx,sizeof g_mousehead
callp read,h,ecx,ebx
cmp eax,ebx
jnz bad
callp close,h
popad
mov eax,buf
ret
mouse_loadcursor endp