8086汇编语言,INT 16,2

4

我遇到了一个问题,我想知道是否按下了右移键,因此我有了这段汇编代码:

mov ah,2
int 16h           ;calling INT 16,2 - Read Keyboard Flags interrupt      
mov ah,10000000b
shl al,7 
and al,10000000b
cmp al,ah         ;check if first bit is 1
je rshift 
jmp final


rshift:
mov ah,9
lea dx,rsh  ;rsh is a string that says that "right shift button has been pressed"
int 21h
jmp final  

final:             ; quit program
mov ax,4c00h
int 21h

为什么它不起作用?我认为问题在于 int 16,2 没有正常工作,如果是这样的话,为什么会这样呢?下面是 INT 16,2 应该做的事情:

AH = 02
on return:
AL = BIOS keyboard flags (located in BIOS Data Area 40:17)

|7|6|5|4|3|2|1|0|  AL or BIOS Data Area 40:17
| | | | | | | `---- right shift key depressed
| | | | | | `----- left shift key depressed
| | | | | `------ CTRL key depressed
| | | | `------- ALT key depressed
| | | `-------- scroll-lock is active
| | `--------- num-lock is active
| `---------- caps-lock is active
`----------- insert is active

我没有看到消息,我在调试中查看了AL寄存器,在我调用INT 16,2之后它似乎没有改变。我正在运行Win 7操作系统的x86架构上,并且正在使用tasm工具。

3个回答

2

你是如何测试这个的?

出于好奇,我写了一个简单的程序(代码如下)。当在Windows控制台下运行时,它可以检测到左移操作(结果:2),但从未检测到右移操作(期望的是结果:1,但只得到了结果:0)。

当在纯DOS环境下运行(在VMWare中),它可以正确地显示所有组合(从0到3)。

因此,这似乎是NTVDM(Windows DOS模拟器)的一个副作用,尽管我没有任何来源可以引用。

我的代码:

.model small

.code

start:
    mov ax, seg msg
    mov ds, ax

    mov ah, 2
    int 16h

    and al,3        ; get two lower bits - both SHIFTs
    add digit, al   ; convert to decimal

    lea dx, msg
    mov ah, 9
    int 21h

    mov ax, 4c00h
    int 21h

.data

msg     db  'Result: '
digit   db  '0'
        db  13,10,'$',0

.stack
        db  16384 dup(?)

end start

这个程序应该怎么工作?我需要在运行程序之前按Shift键吗?我已经测试过了,结果总是显示为零。我正在运行Win 7 x86,并且我已经使用tasm进行了测试。 - John Retallack
是的,你必须提前按下shift键,因为代码中没有延迟(虽然添加延迟或将此代码包装成循环并不难)。在Windows下,您还可以这样做:ping -n 5 localhost && test.exe(假设test.exe是上面的程序),并且有5秒钟的时间来按下(并保持)所需的键。 - atzz
我已经开始思考循环...在Windows命令行中运行以下命令,您将能够“交互式”地观察结果的变化 :) for /L %I in (1,1,10000) do ( ping -n 2 localhost > nul & test.exe ) (抱歉,我此刻身边没有Windows,所以上面的代码未经测试) - atzz

1

你应该能够通过以下方式清理你的检查:

test al,1
jnz rshift

我还是应该在al中移位吗? - John Retallack
我明白了,如果我想检查第二位,那么我需要向右移动一位,对吗? - John Retallack
中断代码和测试看起来都很好。如果你想在帖子的最后编辑你的最终代码,有人可能会看到问题...从哪个方面来说它不起作用?你是否看到了这条消息?你总是看到这条消息吗?你知道需要在程序启动时按下键吗? - Ruben Bartelink
听起来你在这方面没问题。只是为了再次确认一下...你知道它是当前的异步状态,而不是例如.NET中的ModifierKeys的魔法,如http://www.arl.wustl.edu/~lockwood/class/ece291/books/CH13/CH13-3.html#HEADING3-131所述。 - Ruben Bartelink
在你给我的链接中,它说我必须清空类型预读缓冲区,我该怎么做? - John Retallack
显示剩余8条评论

0

我无法解释为什么你的代码不起作用,但你可以替换

mov ah,10000000b
shl al,7 
and al,10000000b
cmp al,ah         ;check if first bit is 1

test al, 1

如果汇编语言中有习惯用法的话,那么下面这个代码会更符合习惯,并且实现的功能相同。

编辑: 正如Michael在下面的评论中指出的那样,如果使用test指令,则需要反转条件跳转。 test al,C仅在al和C按位与的结果为零时设置ZF。


1
正如Ruben的回答间接暗示的那样,如果您使用测试指令(ZF=1表示掩码中的任何位匹配,而je测试ZF=0),则需要使用jnz而不是je。 - Michael Madsen
现在你让我感到困惑了。我认为你是正确的,需要反转条件跳转,但我认为你评论中的括号部分完全颠倒了。如果没有任何位匹配,ZF=1,而je测试的是ZF=1,对吗? - Pascal Cuoq
嗯,当然 - 我错了,这就是在漫长的一天后熬夜的后果。 - Michael Madsen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接