思考
- 需要1个安装程序
- 安装新int9
- 老int9入口备份
- 新int9入口注册
- 需要重写1个新int9,并在其中模拟调用老int9以处理硬件信息
- 按键A的处理
- 如果松开A,就显示满屏幕A:端口60h接收到的是断码9Eh (计算方法,通用1Eh+80h=8Eh)
- 还要考虑到是大写的A,因为只对al接收到的信息与8Eh比较,将对小a的输入也会做出同A一样的响应,而题目要求只对大写A响应。CapsLock键属于控制键,它的状态位于0040:17单元中的第6位,也需要单独判断
- 如果没有松开,则按普通键盘处理
- 非按键A的处理
代码
;任务:安装新的int9中断例程
;功能:在DOS下,按下‘A’后,除非不再松开,如果松开,就显示满屏的‘A’,其他的键照常处理
;安装程序
assume cs:code
stack segment
db 128 dup(0)
stack ends
code segment
start: ;先实际关联寄存器
mov ax,stack
mov ss,ax
mov sp,128
push cs;或 code
pop ds
mov ax,0
mov es,ax
;将 新int9 安装到目标位置
mov si,offset int9
mov di,204h
mov cx,offset int9end - offset int9
cld
rep movsb
;备份 老int9 入口
push es:[4*9]
pop es:[200h]
push es:[4*9+2]
pop es:[202h]
;在中断向量表中注册 新int9 入口
cli;更改过程不能被打断
mov ax,204h
mov es:[4*9],ax
push es
pop es:[4*9+2]
sti
mov ax,4c00h
int 21h
;----搭载 新int9----
int9: push ax
push bx
push cx
push es
in al,60h
;只调用1次,因为不论任何键盘字符输入,都需要调用
pushf
call dword ptr cs:[200h];因int9中的结尾iret包含着popf,所以需要在开头模拟pushf
;判断是否键盘的是A或a,二者扫描码都是1Eh
cmp al,1Eh+80h;A扫描码为1Eh,断码为1Eh+80h=9Eh
jne int9ret
;判断CapsLock是否按下,避免对小写a也做出同样响应
mov bx,40h;用bx是因为al承担着从端口60h接收信息的任务,不能被覆盖
mov es,bx
mov bl,es:[17h]
and bl,01000000b;将第6位之外的所有位,清零。本语句不对第6位造成修改,0表示小写,1表示大写
cmp bl,0
je int9ret
looseA: ;对按键A响应,将A写满屏
mov bx,0b800h
mov es,bx
mov bx,0
mov cx,2000
s: mov byte ptr es:[bx],'A'
add bx,2
loop s
int9ret:pop es
pop cx
pop bx
pop ax
iret
int9end:nop
code ends
end start