【问题标题】:How Can I use the Ah 02h , INT 16h interrupt to check three control keys?如何使用 Ah 02h , INT 16h 中断检查三个控制键?
【发布时间】:2013-12-02 14:45:17
【问题描述】:

我想编写一个程序,它通过按三个键结束:大写锁定、标称锁定和左移。我可以使用 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

【问题讨论】:

  • “但我不分享这个中断是如何工作的”
  • 你可以查找任何中断here
  • @DanielKamilKozar:应该说“当然”。

标签: assembly x86 dos bios


【解决方案1】:

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

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

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

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

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

通过中断你做得很好,但是如果按下任何一个键,你使用test 指令的方式将指示“按下”。我了解您想检查“所有三个”。见上文。

Ralf Brown 的中断列表 - RBIL - 包含所有这些信息。如果你下载整个混乱,而不是查阅在线版本,那里有“ports.lst”、“memory.lst”和一堆其他信息。我强烈建议您获得它...如果您打算在 16 位代码上浪费时间。 :)

【讨论】:

  • 所以这个中断也同时作用于多个键?我的意思是,例如,如果我按下这样的四个键: 01011001 ,它会理解并设置每个位吗?或者它只识别一个键?
  • 可以用IN代替中断吗?我该如何使用它来解决这个问题?
  • 是的...您可以编写自己的 int 9 处理程序。不是一个好的初学者项目。
【解决方案2】:

我认为你最好写这个:

...
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 中的原始值,并且是一个保持的好习惯。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-31
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 2019-09-20
    • 2021-04-01
    • 2015-07-23
    • 2017-09-14
    相关资源
    最近更新 更多