我们早已研究了如何通过21H或16H中断调用来取得按键的信息,但我们对这些信息究竟是如何产生的还一无所知,这一节我们就要更细致地讨论这个问题。那么首先我们把上一节留下的问题解决掉。
我们在前面编制过一个"TESTKEY"程序,下面这个程序是"TESTKEY"的一个升级版本:
TESTKEY2 .ASM
ESC_KEY equ 01h ;一个与ESC键有关的常量
code segment
assume cs:code
org 100h
main proc far
jmp continue ;跳过数据区
ascii db '0123456789ABCDEF' ;十六进制数对应的ASCII码
continue:
push cs ;通过堆栈将CS寄存器送入DS寄存器
pop ds
waitkey:
mov ah,0 ;等待键盘输入
int 16h
call out_ax ;调用OUT_AX子过程输出AX寄存器的值
cmp ah,ESC_KEY ;输入的是ESC键吗?
jnz waitkey ;不是ESC键则转WAITKEY继续
mov ah,4ch ;结束程序
int 21h
main endp
out_ax proc near ;OUT_AX子过程
push ax ;暂存AX寄存器
mov bx,offset ascii ;BX寄存器指向ASCII表
mov cx,0404h ;设置循环计数与移位计数
outloop:
rol ax,cl ;将AX寄存器的高4位移至低4位
mov dx,ax ;用DX寄存器暂存移位后的结果
and ax,000fh ;保留AX低4位(实际是移位前的高4位)
xlat ascii ;取得对应的ASCII码
mov ah,0eh ;利用10H中断的0EH功能
int 10h ;输出一个数字
mov ax,dx ;取回DX寄存器中的移位结果
dec ch ;循环计数减1
jnz outloop ;循环至OUTLOOP继续输出下一个数位
mov ax,0e0dh ;输出回车符
int 10h
mov al,0ah ;输出换行符
int 10h
pop ax ;恢复AX寄存器
ret ;返回
out_ax endp
code ends
end main
这个程序不仅可以显示出按键的ASCII码,还可以显示出16H中断的0号功能在AH寄存器中返回的数据。运行这个程序,会发现AH寄存器中的数据与所按键的ASCII码好象并无关系,比如按下打字键盘上的数字"1"键,可以看到AX寄存器返回的数据是0231H,其中31H是按键的ASCII码;如果按住Shift键再按下数字"1"键,此时AX寄存器返回0221H,21H是"!"的ASCII码,而AH寄存器中的数据竟然没变;如果按下右边数字小键盘上的"1",就会看到AX寄存器中返回4F31H,31H仍是"1"的ASCII码,而AH寄存器中的数据却变成了4FH。
如果我们暂时给AH寄存器中的数据命名为"幻码"的话那么我们现在就可以总结出这样两条规律:
(1)Shift键可以改变同一按键的ASCII码,但同一键的"幻码"固定不变;
(2)分在不同键区的同名键具有相同的ASCII码,但具有不同的"幻码"。这个规律是否绝对,我们可以按下其它的键来检验,最后我们可以发现这个规律对于大多数键来讲是正确的,个别的一些键无此规律。
那么就"幻码"本身而言,各个键所对应的"幻码"有没有什么规律呢?我们再次运行这个程序,然后由"1"至"0"顺次按下打字键区中的数字键,再由左至右顺次按下第一行字母键,看看是否得到了下面的结果:
