⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 1024full.asm

📁 DOS下鼠标驱动程序
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;NAME PS.ASM
;此程序用来驱动ps/2鼠标
;通过使用扩展BIOS中断INT15 C200功能
;现在此程序支持 1024X768X16M(必须使用VBE v1.2版本BIOS)
.486
code segment use16
	assume cs:code
	org 100h
begin:
	mov ax,cs       ;使cs=ds=es
	mov ds,ax
	mov es,ax

	;清屏功能 INT10,AL=0,AH=6
	mov al,0
	mov bh,7
	mov ch,0
	mov cl,0
	mov dh,24
	mov dl,79
	mov ah,6
	int 10h

	;设置光标位置到左上角 INT10, AH =2
	mov bh,0
	mov dh,0
	mov dl,0
	mov ah,2
	int 10h


	;设定为1024x768x65535色AX=4f02h, BX=118yh
	mov mode, 118h
	mov ax,4f02h
	mov bx,118h
	int 10h
	cld

	;显示一行提示文字
	mov bp,offset tip
	mov cx,tiplen
	mov dh,0
	mov dl,45
	mov bh,0
	mov al,0
	mov bl,7
	mov ah,13h
	int 10h
	mov bp,offset explainstr
	mov cx,explainstrlen
	mov dh,1
	mov dl,30
	mov bh,0
	mov al,0
	mov bl,7
	mov ah,13h
	int 10h


	;在屏幕上画一个鼠标外形
	pusha
	mov lineend1x,360
	mov lineend1y,250
	mov lineend2x,600
	mov lineend2y,250
	mov linecolor,0ffffffh
	call drawhorline

	mov lineend1x,600
	mov lineend1y,250
	mov lineend2x,600
	mov lineend2y,600
	call drawverline

	mov lineend1x,360
	mov lineend1y,600
	mov lineend2x,600
	mov lineend2y,600
	call drawhorline

	mov lineend1x,360
	mov lineend1y,250
	mov lineend2x,360
	mov lineend2y,600
	call drawverline

	mov rectcolor,0ffffffh
	call drawleftbutton
	call drawrightbutton
	popa

	;重置鼠标 sample rate=100hz,res=4/m,scale=1:1
	mov ax,0c201h
	int 15h


	;鼠标程序的设备句柄 
	;handler 程序是 ps/2鼠标的 中断处理程序
	;当安装这个handler后,即使此程序退出,handler程序仍然可发挥作用
	mov ax,seg handler
	mov es,ax
	mov ax,0c207h         ;c207功能是安装handler的功能
	mov bx,offset handler ;handler函数的地址
	int 15h
	
	jc err_1              ;如果 CF=1, c207功能调用失败
	jmp c1                
err_1:  jmp error_end
	
c1:     mov ax,0c200h         ;c200功能是打开ps/2鼠标
	mov bh,1
	int 15h
	jc err_2              ;如果CF=1,则c200功能调用失败 
	jmp c2
err_2:  jmp error_end
c2:     call save_mouse
	;再等待敲键退出
scan1:  mov ah,1
	int 16h
	jz scan1

	;清理安装的handler (use nullhandler procedure)
	mov ax,seg nullhandler
	mov es,ax
	mov bx,offset nullhandler
	mov ax,0c207h
	int 15h

	
	mov ax,0c201h
	int 15h
	
	mov bx,0                ;调用int10h换页映射
	mov dx,0         
	mov ax,4f05h
	int 10h

	jmp return

error_end:
	call showerror

return:        
	mov al,02               ;restore screen
	mov ah,0
	int 10h

	mov ah,4ch
	int 21h

nullhandler proc far
	ret
nullhandler endp


;***************************************************************************
;系统调用功能system call this function 
;一旦ps/2鼠标有所动作,系统将调用这个函数三次
;第一次将鼠标的 状态放到函数的堆栈SP+10处
;第二次将X轴方向的移动量放到堆栈的SP+10处
;第三次将Y轴方向的移动量放到堆栈的SP+10处
;这个函数必须是FAR PROC类型,也就是说必须返回地址xxxx:xxxx
;不要将堆栈弹出,否则会死机
handler proc far
	push cs         ;DS=CS
	pop ds

	mov ax,ss
	mov es,ax
	mov bx,sp
	add bx,10       ; 获得系统传递进来的值,其位置在SP+10处
	mov dx,es:[bx]  ; DX用来保存该值

	;为了区分依次传递进来的
	;使用了全局变量count来进行分辨
	cmp count ,0
	jz first        ;是第一个参数 -- mouse statue
	cmp count, 1
	jz second       ;第二个参数-- mouse x movement
	cmp count,2
	jz third        ;第三个参数 -- mouse y movement

first:  add count ,1    
	mov state, dl   ;鼠标的状态保存到state字节中

	;保存老的鼠标的X,Y坐标信息 save old xcord and ycord
	;保存上一次鼠标中断发生时鼠标的位置save last mouse interrupt occur mouse's postion
	mov ax,xcord            
	mov xcordold,ax
	mov ax,ycord
	mov ycordold,ax

	test dx,1       
	jz lnd          ;为1时表示鼠标左键按下状态 -- Left button is down
	
	;左键按下处理
	;将左键按钮变红
	mov rectcolor,0ff0000h        
	call drawleftbutton
	jmp n
	;鼠标左键没有按下
lnd:        
	mov rectcolor,0ffffffh  ;左键按钮变白
	call drawleftbutton
n:        
	test dx,2       
	jnz rd          ;为2时表示鼠标右键按下状态 
	mov rectcolor,0ffffffh          ;右键没有按下,右键按钮画白色
	call drawrightbutton
	jmp over

	;右键按下
rd:
	mov rectcolor,0ff0000h          ;右键按钮画红色
	call drawrightbutton

	jmp over

;X位移处理函数,只改变xcord的值,不绘制鼠标形状,绘制等待到ycord处理时进行 
second:
	add count,1
	cmp dx,0
	jnz movedx          ;有x方向的移动
	jmp over            ;没有x方向移动则 jump over
movedx:
	test state,10h      ;为00010000表示负方向移动
	jnz  xnegative
	add xcord, dx

	;判断屏幕模式,从而得到屏幕界限
	;防止鼠标移出屏幕
	cmp xcord,1023
	jnb big1024
	jmp over
big1024:
	mov xcord, 1023
	jmp over
xnegative:
	neg dl                 ;负方向位移处理 ,neg it,Exp: neg(ffff) = 1;
	sub xcord,dx           ;sub the '1'
	cmp xcord,0            ;设置最小为 0
	jl xless0
	jmp over
xless0:
	mov xcord,0
	jmp over

;Y位移处理过程 
third:
	mov count,0
	cmp dx,0
	jnz movedy
	jmp complete    
;坐标系的设定是x轴正方向:左->右
;Y轴正方向:上->下
;但是鼠标y轴方向设定刚好与此相反,即:向上移动为负位移,向下为正
movedy:
	test state,20h
	jnz ynegative   
	
	;如果非负就直接
	sub ycord,dx
	cmp ycord,0
	jl yless0
	jmp complete
yless0:
	mov ycord,0
	jmp complete
	
;如果为负,就neg,然后再相加
ynegative:
	neg dl
	add ycord,dx
	cmp ycord,767
	jnb big768
	jmp complete
big768:
	mov ycord,767
	jmp complete

complete:        
	;将savenew复制到saveold缓冲,savenew接收新值
	push cs
	pop ax
	mov es,ax
	mov ds,ax
	mov si,offset savenew
	mov di,offset saveold
	mov cx,mousetypelen*2
	cld
	rep movsb

	;使用saveold恢复原屏幕值
	call restore

	;保存新鼠标位置的屏幕值到savenew缓冲中
	call save_mouse
	
showms:        
	call show_mouse                 ;画鼠标

	;显示鼠标坐标x=xxxxx,y=yyyyy
	pusha
	mov ax,xcord
	mov bx,offset showbuffer1
	call btoasc
	mov ax,ycord
	mov bx,offset showbuffer2
	call btoasc
	mov ax,seg showbuffer1
	mov es,ax
	mov bp,offset show1
	mov cx,7
	mov dh,4
	mov dl,50
	mov bh,0
	mov al,0
	mov bl,7
	mov ah,13h
	int 10h
	mov bp,offset show2
	mov cx,7
	mov dh,4
	mov dl,60
	mov bh,0
	mov al,0
	mov bl,7
	mov ah,13h
	int 10h
	popa

over:   ret
handler endp


;功能:将输入的(x,y)坐标位置映射到显存中的地址
;入口:EDX:y坐标, EBX:x坐标
;出口: segindex:显存地址页号,segoffset:显存地址偏移
mapmemory proc far
	pusha
	mov eax,edx             ;将y坐标放置到EAX中
	;下面是1024x768x16M(真彩)的映射方式
	;真彩一个点占4个字节(RGB各占一个,空一个不用)
	mov ecx,4096
	shl ebx,2             ;  ;一个像素占4个字节,所以x坐标要乘4(左移2位)
	mul ecx                 ;ecx中放置一行的点数,EAX*ECX=y*一行的点数
	add eax,ebx             ;address = x+y*一行的点数
	mov cl,16               
	mov ebx,eax
	shr ebx,cl              ;地址中的页号:右移16位 page num
	mov segindex,bx         
	and eax,0ffffh          ;地址偏移offset
	mov segoffset,ax

	cmp segindexold,bx      ;比较与上一个点是否在同一个页面上,是则不要换页(不需要调用Int10h)
	jz  insamepage          

	mov segindexold,bx
	mov bx,0                ;调用int10h换页映射
	mov dx,segindex         
	mov ax,4f05h
	int 10h

insamepage:        
	popa
	ret
mapmemory endp

;功能:恢复老鼠标位置屏幕
;入口:xcordold,ycordold
restore proc far
	pushad
	mov ebx,0
	mov edx,0
	mov ecx,0
	mov eax,0
	
	mov ax,mousetypelen
	shr ax,1                ;count/2 (DW)
	mov mousetypecounter,ax  ;mousetypecounter = mousetypelen/2
	mov di,0
	mov si,0
restorepixel:
	mov bx, xcordold        ;将前一个鼠标位置x坐标放到BX中
	mov ax,mousetype[di]    ;将鼠标中的一个点放到AX中
	push ax
	mov cl,8                
	shr ax,cl               
	and ax,0ffh            ;make ax = 00XXh获得该点相对于基准点的坐标偏移
	add bx,ax              ;获得该点的实际坐标x 

	pop ax
	mov dx, ycordold

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -