我正在尝试通过DOS中的汇编程序x86学习一些深度编程,因为它启用了实际的地址模式。但是在我尝试这样做时,我试图制作一个打印出来的程序,用户已经按下了一个控制键; CTRL,CAPS LOCK或SCROLL LOCK但问题是该程序不打印出来。感觉缺乏某种基本知识,所以我想这里有人知道我的程序有什么问题。它没有写出任何东西,但是如果我按q(如退出)就可以关闭?...谢谢
;reads the key and prints out whether a control key has been entered
; (CTRL, CAPS LOCK or SCROLL LOCK)
[BITS 16]
SEGMENT data
ctrlmsg db 'ctrl has been pressed', '$'
capslockmsg db 'caps lock has been pressed', '$'
scrollmsg db 'scroll lock has been pressed', '$'
SEGMENT code
..start:
mov ax, pile
mov ss, ax
mov ax, topofstack
mov sp, ax
mov ax, data
mov ds, ax
mov ax, ctrlmsg
WAITER:
mov ah, 00h
int 16h
cmp al, 71h ; user pressed q, and wants to end program
je END
mov ah, 02h ; wait until user press keyboard and return keyboard flag in AL
int 16h
add al, 71h ; add 71h back to al, so it goes unchanged in other comparisons
cmp al, 02h ; if key board flag is 02h then I expect user to have pressed CTRL
je CTRL ; then jump to CTRL label, in the same way it goes...
add al, 02h
cmp al, 04h
je SCROLLOCK
add al, 04h
cmp al, 06h
je CAPSLOCK
jmp WAITER
END:
mov ax, 04c00h ; ends program
int 21h
WRITESTRING:
mov ah, 13h ; 13h of int 10 is print string
mov al, 00h ; write mode 0 (no attributes)
mov bh, 0h ; video page number
mov bl, 07h ; foreground color
mov cx, 05h ; string length
mov dh, 25 ; row
mov dl, 80 ; col
int 10h
ret
CTRL: ; the other labels CAPS LOCK and SCROLL LOCK are quite similar why I haven't included them in the codesnippet
push ds ; save ds for subroutine
pop es ; pop it in es
push bp
move bp, ctrlmsg ; base pointer point to string
call WRITESTRING
pop bs
jmp waiter ; loop
答案 0 :(得分:1)
我对int 16h
BIOS调用的确切行为的记忆是模糊的,但我认为切换(capslock / numlock / scrollock)或修改器(shift / ctrl / alt)键不会自己返回任何内容全部来自int 16h
。一旦用户按下非修改键,这些键用于修改实际 返回的内容。
要按下实际击键,你可能需要为IRQ 9编写一个ISR(我很确定这是键盘硬件中断的编号)。此时,您可以获得键盘上每个键的原始“make”和“break”扫描码,并采取您想要的任何操作。 (当然,在ISR中,该操作可能应限于将按键信息存储在缓冲区中,以便以后在ISR之外进行处理。)
此外,我注意到您在程序开始时设置了ss
和sp
,但DOS会自动为您设置堆栈。通常你根本不需要这样做。但是,如果这样做,则应始终使用cli
和sti
在修改寄存器期间禁用中断。如果在您更改ss
但尚未sp
时发生中断,则ISR将覆盖您可能不想要的内容。
答案 1 :(得分:1)
segment pile stack ; the "stack" is important!
resw 100h ; should be enough for anybody
segment pile stack ; the "stack" is important!
resw 100h ; should be enough for anybody
你必须像你一样加载ds。我也会这样做,而不是留到“CTRL:”。你的“Writestring”取决于它。 (奇怪的中断,10h / 13h!)
int 16h,ah = 0对于旧的83键键盘是正确的。它将“几乎”所有键击,但它错过了一些。我对那个人非常困惑! (很久以前,但我还记得它!)现代键盘使用啊= 10h。无论哪种方式,你检查'q'并退出。到目前为止一切都很好!
然后你得到int 16h / 2的标志。在那之后你的逻辑逃避了我!你在键盘标志上加了71h?然后将它与2进行比较?我不认为你的任何条件跳跃。这可以解释为什么没有打印出来! :)(你也打印到第25行,第80列,这看起来很奇怪)
我认为你想用...(等待它)测试标志“test”指令。由于这些条件中不止一个可能是真的,可能是......
test al, 4 ; bit 2 - control key
jnz notctrl
call print_control
notctrl:
test al, 16 ; bit 4 - scrollock active
jnz not_scrl
call print_scroll
notscrl:
test al, 64 ; bit 6 - capslock active
; etc...
显然,您必须在子程序中保留al。 Greg也是正确的,如果您为键盘编写自己的int 9(irq 1)处理程序,则将此信息保存在缓冲区中。现有的处理程序就是这样做的。在Bios数据区,段40h ......我忘了偏移...你会发现这些标志。这是int 16h / 2发现它们的地方,我很确定。您可以自己访问它们,但BIOS中断可能更容易(也许可以尝试它作为练习?)。
最后但并非最不重要的是,wtf是“pop bs”? BS不是段寄存器。 Nasm不会没有BS! CPU不会没有BS! :)
最佳, 弗兰克