如何使用Ah 02h,INT 16h中断检查三个控制键?

时间:2013-12-02 14:45:17

标签: assembly x86 dos bios

我想编写一个程序,按三个键结束:大写锁定,nom锁定和左移。我可以使用AH = 02h,INT 16h来检查它们是否被压在一起? 我可以使用哪些其他中断? 好奇:)

这是我的代码,但我不同意这个中断是如何工作的:

TITLE 'PressKeys' ;key program

;-----------------------------------------------------------------------------------

;DATA SEGMENT
DASEG SEGMENT PARA PUBLIC 'data'

  CHECK DB 01100010b;The number which is used to check the control keys
                    ;in the INT 16H (caps lock,nom lock,left shoft)

  MESG DB 'FINISH $';Massage to say finish                      

DASEG ENDS

;--------------------------------------------------------------------------------------

;CODE SEGMENT
COSEG SEGMENT PARA PUBLIC 'code'

  ASSUME CS:COSEG, DS:DASEG, ES:NOTHING, SS:NOTHING


MAIN:

 MOV AX,DASEG

 MOV DS,AX

 ;Check if the caps and nom and left shift keys has been pressed
KLOOP:
MOV AH,02H

  INT 16H 

  TEST AL,CHECK

  Jnz PRESSED ;If the keys has been pressed finish the programm

  JMP KLOOP

PRESSED:;PRINT MESSAGE

    LEA DX,MESG

    MOV AH,09H

    INT 21H           


 ;GET BACK TO OS
 MOV AX,4C00H
 INT 21H    


COSEG ENDS  

;------------------------------------------------------------------------------

;END OF PROGRAMM

END MAIN

2 个答案:

答案 0 :(得分:1)

int 16h / 2检查BIOS数据区中的一个字节 - 40h:17h(我必须检查RBIL以记住该地址)。您可以自己检查该字节,但中断可能更容易。

test指令通常仅在第二个操作数中设置一个位。如果你正在做test多个比特,如果设置了三个比特中的任何一个,你就会得到NZ。使用test三次 - 一次一位,或and al使用您的值,然后cmp使用精确值来查看是否已设置所有三位。

编辑:更多信息:当按下某个键时,再次释放该键时,会生成一个IRQ。这由中断服务程序处理,通常是int 9.在大多数情况下,忽略“释放”中断。在少数情况下,我们需要“记住”按键已被按下而未被释放(“转换”是最明显的)。这是通过在BDA中设置(或清除)几个字节中的位来完成的。 (80键键盘只有1个字节 - 来自博物馆)

int 16h - “键盘中断” - 实际上不靠近键盘控制器(由int 9处理)但与BDA中的某些字节相互作用 - “移位标记”你'感兴趣的是,“键盘缓冲区”和几个字节 - “头指针”和“尾指针”进入缓冲区(如果它们相同,没有密钥可用)。

所以int 16h/2将返回40h时字节中设置的内容:17h - 使用`int 16h / 12h得到“扩展移位标志” - 两个字节 - 如果你需要它们。在你给出的例子中 - 01011001是吗? (我无法从“编辑模式”看到你的评论) - 我认为有些位表示“活跃”而不是“按下”,所以它可能不会做你想要的。请注意,只有“某些键”保存了其按下/释放状态。

你通过中断做得很好,但是如果按下任何一个键,你使用test指令的方式将指示“按下”。我知道你要检查“全部三个”。见上文。

拉尔夫·布朗的中断名单 - RBIL - 拥有所有这些信息。如果你下载整个混乱,而不是咨询在线版本,有“ports.lst”,“memory.lst”和一堆其他信息。我强烈建议你明白......如果你要浪费时间使用16位代码。 :)

答案 1 :(得分:0)

我认为你最好写这个:

...
OR AL, 10011101B
CMP AL, 11111111B
JC KLOOP
...

无论按下这三个键中有多少个键,您的代码都可以跳转到PRESSED。按下至少一个键会导致成功,这显然不是你的意图。 看看结果如何受JNZ影响,因此导致跳转到PRESSED,这是不正确的:

TEST AL, 01100010B
AL = 01000000 -> Result NOT Zero
AL = 00100000 -> Result NOT Zero
AL = 00000010 -> Result NOT Zero

重要的是,AND,OR和TEST指令是逐位的,即它们是逐位AND和OR两个操作数。所以在上面的例子中,整个结果仍然大于零。 然而,你使用TEST而不是AND有助于保留AL中的原始值,并且是一个很好的习惯。