📄 int9.asm
字号:
.model small
.386
.stack
.data
;scan code(base=0) 1 2 3 4 5 6 7 8 9 0 - = \t q w e r t y u i o p [ ] \n a s d f g h j k l ; ' ` \ z x c v b n m , . /
scan_tab_dn db ?,?,49,50,51,52,53,54,55,56,57,48,45,61,?,9,113,119,101,114,116,121,117,105,111,112,91,93, 13,?,97,115,100,102,103,104,106,107,108,59,39,96,? ,92, 122,120,99,118,98,110,109,44,46,47
scan_tab_up db ?,?,33,64,35,36,37,94,38,42,40,41,95,43,?,9,81 ,87, 69, 82, 84, 89, 85, 73, 79, 80,123,125,13,?,65,83, 68, 70, 71, 72, 74, 75, 76, 58,34,126,?,124,90, 88, 67, 86,66,78, 77 ,60,62,63
.code
main proc far
start:
mov ax,@data
mov ds,ax
;save old interrupt vector
mov al,9
mov ah,35h
int 21h
push es
push bx
push ds
;set new interrupt vector
mov dx,offset myint9
mov ax,seg myint9
mov ds,ax
mov al,9
mov ah,25h
int 21h
;restore ds and set mask code
pop ds
in al,21h
and al,11111101b
out 21h,al
;open interrupt
sti
;clear key-board buffer
call mem_clr
waitint9:
;两套测试方案
; mov ah,0
; int 16h
; mov dl,al
; mov ah,2
; int 21h
mov ah,7
int 21h
mov dl,al
mov ah,2
int 21h
jmp waitint9
;restore old interrupt vector
pop dx
pop ds
mov al,9h
mov ah,25h
int 21h
;exit
mov ax,4c00h
int 21h
main endp
;===================================================
myint9 proc near
;保存寄存器
cli
push ax
push bx
push cx
push dx
push si
push di
push es
xor cx,cx
;等待数据输入,超时则退出
waitdata:
;if outport code ready
;读键盘状态接口
in al,64h
;检测是否数据已放入缓冲区
test al,01b
;not ready,wait for a moment
loopz waitdata
;not ready and time out,quit interrupt procedure
jz _quit1
jnz next1
_quit1:
jmp quitint9
next1:
;由8042芯片的60端口接收数据
in al,60h
;if code error,quit int-procedure
;相等说明错误,推出程序
cmp al,0ffh
jz _quit2
jnz next2
_quit2:
jmp quitint9
next2:
;make es:[si] point to 40:17h unit
mov si,17h
mov bx,40h
mov es,bx
;code valid
;相等说明是右shift键按下,并对其处理
cmp al,36h
jnz not_rshiftdn
or byte ptr es:[si],00000001b
not_rshiftdn:
;相等说明是右shift键弹起,并对其处理
cmp al,0b6h
jnz not_rshiftup
and byte ptr es:[si],11111110b
not_rshiftup:
;相等说明是左shift键按下,并对其处理
cmp al,2ah
jnz not_lshiftdn
or byte ptr es:[si],00000010b
not_lshiftdn:
;相等说明是左shift键弹起,并对其处理
cmp al,0aah
jnz not_lshiftup
and byte ptr es:[si],11111101b
not_lshiftup:
;相等说明是ctrl按下,并对其处理
cmp al,1dh
jnz not_ctrldn
or byte ptr es:[si],00000100b
not_ctrldn:
;相等说明是ctrl键弹起,并对其处理
cmp al,9dh
jnz not_ctrlup
and byte ptr es:[si],11111011b
not_ctrlup:
;相等说明是alt键按下,并对其处理
cmp al,38h
jnz not_altdn
or byte ptr es:[si],00001000b
not_altdn:
;相等说明是alt键弹起,并对其处理
cmp al,0b8h
jnz not_altup
and byte ptr es:[si],11110111b
not_altup:
;相等说明是scroll键,并对其处理
cmp al,46h
jnz not_scroll
xor byte ptr es:[si],00010000b
not_scroll:
;相等说明是num lock键,并对其处理
cmp al,45h
jnz not_numlock
xor byte ptr es:[si],00100000b
not_numlock:
;相等说明是caps lock键,并对其处理
cmp al,3ah
jnz not_capslock
xor byte ptr es:[si],01000000b
not_capslock:
;相等说明是insert键,并对其处理
cmp al,52h
jnz not_insert
xor byte ptr es:[si],10000000b
not_insert:
;相等说明是esc键
cmp al,01h
jnz not_esc
;留做地esc键的处理
not_esc:
;如果比35h小,可能是asc码,否则不是
cmp al,35h
ja not_asc
;将si指向buffer头,di指向buffer尾
mov si,es:[1ah]
mov di,es:[1ch]
;将扫描码转化为asc码,扫描码放于ah,转化后的asc码放入al
call scan_to_asc
;将ax存入缓冲区,根据zf的值可以知道存储是否成功
call store_code
jmp quitint9
not_asc:
;在这里留做扩展,填加代码对更多的键进行处理
jmp quitint9
quitint9:
;准备结束硬中断的指令
cli
mov al,20h
out 20h,al
;恢复原寄存器内容,准备推出中断
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret
myint9 endp
;---------------------------------------
;清空键盘缓冲区
mem_clr proc near
pusha
;将首尾指针指向初始位置
mov bx,40h
mov es,bx
mov word ptr es:[1ah],001eh
mov word ptr es:[1ch],001eh
;预备处理bx值
mov bx,1eh
mov cx,24h
dec bx
;将键盘缓冲区内容全清为0
again1:
inc bx
mov byte ptr es:[bx],0
cmp bx,3dh
jl again1
popa
ret
mem_clr endp
;---------------------------------------
;将扫描码转换成asc码,参数在al中,结果在ax中,ah为扫描码,al为字符码
scan_to_asc proc near
;保存寄存器内容
push bx
push cx
push dx
push ds
;设置es,ds值
;;;;;;;;;;;;;;;;;;;;;
;;;mov ax,@data;;;
;;;mov ds,ax;;;;;;
;;;;;;;;;;;;;;;;;;;;;
mov bx,seg scan_tab_up
mov ds,bx
mov bx,40h
mov es,bx
;比35小,则可以转化成asc码,否则不可以,跳出子程序
cmp al,35h
jg pre_quit
jmp pre_xlat
pre_quit:
;将结果制为全1,以显示不可以转化成asc码
mov al,0ffh
jmp quit_xlate
pre_xlat:
;转化部分代码
;将扫描码放入ah
mov ah,al
;将键盘状态字存入cl
;mov bx,17h
mov cl,es:[17h]
;测试是否caps lock键按下奇数次
test cl,01000000b
jnz caps_lock
;测试是否右shift键按下
test cl,00000001b
jnz shift_down
;测试是否左shift键按下
test cl,00000010b
jnz shift_down
;程序运行到这里,说明转化的目标asc码是下档键,结果放入al
mov bx,offset scan_tab_dn
xlat
jmp quit_xlate
shift_down:
;程序运行到这里说明shift键已按下,转化目标为上档键,结果放入al
mov bx,offset scan_tab_up
xlat
jmp quit_xlate
caps_lock:
;程序运行到这里说明caps lock键已按下奇数次
test cl,00000001b
jnz caps_shift
;看是否同时又有shift键按下
test cl,00000010b
jnz caps_shift
;目标为上档键
mov bx,offset scan_tab_up
xlat
jmp quit_xlate
caps_shift:
;目标为下档键
mov bx,offset scan_tab_dn
xlat
quit_xlate:
;预备跳出,恢复寄存器
pop ds
pop dx
pop cx
pop bx
ret
scan_to_asc endp
;---------------------------------------
;the code to be stored is in ax,zf=1 failed,zf=0,succeed
store_code proc near
;关中断,使过程不能被可屏蔽中断中断
cli
;保存寄存器内容
push bx
push cx
push dx
;首指针预加2
add di,2
;看是否指向地址已经超出缓冲区
cmp di,3dh
;超出后,将其指向头部
ja to_head
;否则,直接将内容存入缓冲区
mov es:[di-2],ax
;置zf为 0
mov cx,0
cmp cx,1
jmp quit_store
to_head:
;新加入的内容放入头部
sub di,20h
mov es:[3ch],ax
;set zf=0
mov cx,0
cmp cx,1
jmp quit_store
quit_store:
;准备跳出
cli
;将新的尾指针写回原空间
mov es:[1ch],di
;call memshow
pop dx
pop cx
pop bx
ret
store_code endp
;---------------------------------------
;输出寄存器dl的内容,以16进制显示
displaydl proc near
;save registors
push ax
push bx
push cx
push dx
;save dl into bl
mov bl,dl
;output the higer 4-bit
and dl,11110000b
mov cl,4
rol dl,cl
cmp dl,1001b
jg char1 ;between a and f
add dl,48 ;between 0 and 9
jmp show1
char1:
;output code between a and f
add dl,55
show1:
;output code between 0 and 9
mov ah,2
int 21h
;output the lower 4-bit
mov dl,bl
and dl,00001111b
cmp dl,1001b
jg char2 ;between a and f
add dl,48 ;between 0 and 9
jmp show2
char2:
;output code between a and f
add dl,55
show2:
;output code between 0 and 9
mov ah,2
int 21h
;output a blank space
mov dl,' '
mov ah,2
int 21h
;restore registors
pop dx
pop cx
pop bx
pop ax
ret
displaydl endp
;---------------------------------------
;display the content of keyboad buffer(40:1e--40:3d),including head(40:1a) and tai(40:1c)
memshow proc near
;save registors
pusha
;set es be the base address of the buffer(40)
mov bx,40h
mov es,bx
mov bx,1ah
;prepration for the loop below
mov cx,24h
sub bx,1
again:
;display the buffer
inc bx
mov dl,es:[bx]
call displaydl
cmp bx,3dh
jl again
;restore the registors
popa
ret
memshow endp
end start
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -