📄 1024full.asm
字号:
;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 + -