检测/在DOS下同时接收多个键盘presses? [英] Detect/receive multiple key-presses at the same time in DOS?

查看:193
本文介绍了检测/在DOS下同时接收多个键盘presses?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写TASM空气曲棍球的中间,我遇到一个问题,就是如何得到两个键/点击一次,因为我需要同时获得点击一次在一个时间和Im移动双方球员尝试了很多,但我不认为我有办法这样做。
听说我需要从缓冲区目录阅读和看键有什么和独立阅读每一个,但我真的不知道如何做到这一点。

I'm in the middle of writing air hockey in tasm and I have encounter a problem which is how I get two keys/clicks at once because I need to get both click at once to move both players in one time and Im trying a lot but I don't think I have a way to doing it. I heard that I need to read from the buffer directory and see what keys are there and read each one individually but I don't really know how to do this.

推荐答案

你介意与扫描codeS工作?

Do you mind working with scancodes?

我知道这不是简单的,投递,解决你要找的,但我恐怕是没有的。结果
所以,我的希望,如果不是你,其他的一些困扰codeR可以找到一些有用的东西写这个。

I know this is not the simple, drop-in, solution you were looking for but I'm afraid there is none.
So I'm writing this in the hope that, if not you, some other troubled coder can find something useful.

我也知道你写TASM,但我忘了,并开始与NASM,但转换应该是很容易(只添加段声明,从支架取出段寄存器和添加的 PTR 的)

I also know you write for TASM but I forgot that and started with NASM, converting however should be very easy (just add segments declarations, take out the segment register from the brackets and add PTR).

看来,从硬件角度看键盘重复只有在最后pressed键 1 ,所以如果两个球员是pressing两个密钥,只有一个是实际由键盘发送。结果
然而,软件处理多个键一次无处不在,的他们是如何做到的?

It seems that from an hardware perspective the keyboard repeats only the last pressed key1, so if two players are pressing two keys, only one is actually sent by the keyboard.
However the software handle multiple keys at once everywhere, how do they do it?

诀窍是,键盘发出的双codeS 扫描codeS 的)时,关键是pressed:一是当钥匙进入(和其他许多人当它存下来),一个当它的发布。结果
因此,该软件可以告诉当一个键被按下不从键盘 2

The trick is that the keyboard sends two codes (scancodes) when a key is pressed: one when the key goes down (and many others while it is kept down) and one when it is released.
The software can thus tell when a key is down without further notice from the keyboard2.

我找不到任何中断服务,处理关键的上下活动

唯一的解决办法是处理扫描code直接。

虽然 8042芯片是非常简单的,没有需要弄脏与IO指令。结果
没有解释如何8259A和IRQ映射的作品,这足以说,中断 15小时/ AH = 4FH 被调用,在扫描code AL 时,关键是pressed /发表。

While the 8042 chip is very simple, there is not need to get dirty with IO instruction.
Without explaining how the 8259A and the IRQ mapping works, it's enough to say that the interrupt 15h/AH=4fh is called with the scancode in AL when a key is pressed/released.

我们可以拦截中断,并检查扫描code是一个键或向下的关键了。结果
发布扫描codeS拥有的第7位的设置。结果
我们可以有128个字节,每个任何可能的扫描code值的阵列( bit0-6 的) 3 中的每个元素和存储 0FFH 如果扫描code表示一个preSS或 00H 如果它表示一个版本。

We can intercept that interrupt and check if the scancode is for a key down or a key up.
Release scancodes have bit7 set.
We can have an array of 128 bytes, each for any possible scancode value (bit0-6)3 and store in each element 0ffh if the scancode indicates a press or 00h if it indicates a release.

也是很有保留处理扫描codeS的计数,所以一个程序可以等待新的扫描codeS琐碎的算术。

It is also useful keep a count of the processed scancodes, so a program can wait for new scancodes with trivial arithmetic.

现在,我想你还是一头雾水。结果
我写了一个演示。

Now, I imagine you are still confused.
I have written a demo.

下面的程序,对于NASM,等待您preSS的两个 的和的 D 的键退出。结果
警告由于我们使用扫描codeS,这是键盘布局依赖!

The program below, for NASM, waits for you to press both a and d keys to exit.
Warning Since we are using scancodes, this is keyboard layout dependent!

BITS 16
ORG 100h        ;COM

 ;Setup ISR for the scancode 
 call init 

 ;Clear screen
 mov ax, 03h
 int 10h 

 ;Print command
 mov ah, 09h 
 mov dx, strCommand
 int 21h 

_main:
 ;Wait for a change in the scancode tables
 call wait_for_scancode
 ;Remove unused keystrokes
 call remove_keystrokes

 ;Check if a is pressed 
 mov al, 1eh           ;a
 call is_scancode_pressed
 jz _main 

 ;Check if 'd' is pressed 
 mov al, 20h           ;d 
 call is_scancode_pressed
 jz _main 

 ;Both are pressed, print bye and ...
 mov ah, 09h 
 mov dx, strDone
 int 21h 

 ;... restore the ISR and ...
 call dispose 

 ;... exit
 mov ax, 4c00h
 int 21h

 strCommand db "Press 'a' and 'd' to exit", 13, 10, 24h 
 strDone    db "Bye",13,10,13,10,24h 

 ;Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  L  
 ;  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll
 ;Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  Ll  L

 ;S C A N C O D E   F U N C T I O N S

 ;Set the ISR 
init:
  push ax  

  mov ax, cs
  mov WORD [old_isr_15 + 02h], ax          
  ;old_isr_15 is now a far pointer to new_isr_15

  call swap_isr_15          ;Swap the current isr15 with the one in old_isr_15

  pop ax 
  ret

  ;Restore the original ISR 
dispose:
  call swap_isr_15          ;Swap the current isr15 with the one in old_isr_15                  

  ret  

  ;Swap the pointer in the IVT for int 15h with the pointer in old_isr_15
swap_isr_15:
  push eax
  push es 

  xor ax, ax 
  mov es, ax 

  cli

  mov eax, DWORD [es: 15h*4]
  xchg eax, DWORD [old_isr_15]
  mov DWORD [es: 15h*4], eax 

  sti

  pop es 
  pop eax

  ret  

  ;Wait for a change in the scancode table
wait_for_scancode:
 cli                           ;Prevent the ISR from messing things up 

 ;At least one scancode processed?
 cmp WORD [new_scancode], 0 
 jne _wfs_found                ;Yes

 ;No, restore interrupt so the CPU can process the prending ones
 sti
jmp wait_for_scancode

 ;New scancode, decrement the count and restore interrupts
_wfs_found:
 dec WORD [new_scancode]
 sti 

 ret

  ;THe BIOS is still saving keystrokes, we need to remove them or they 
  ;will fill the buffer up (should not be a big deal in theory).
remove_keystrokes:
 push ax

 ;Check if there are keystrokes to read.
 ;Release scancodes don't generate keystrokes 
_rk_try:
 mov ah, 01h 
 int 16h
 jz _rk_end      ;No keystrokes present, done 

 ;Some keystroke present, read it (won't block)
 xor ah, ah 
 int 16h
jmp _rk_try

_rk_end:
 pop ax 
 ret 

 ;Tell if a scancode is pressed
 ;
 ;al = scancode  
 ;ZF clear is pressed 
is_scancode_pressed:
  push bx

  movzx bx, al 
  cmp BYTE [scancode_status + bx], 0 

  pop bx 
  ret 

 ;AL = scancode 
new_isr_15:
 ;Check for right function
 cmp ah, 4fh
 jne _ni15_legacy

 ;Save used regs
 push bx
 push ax


 movzx bx, al            ;BX = scancode 
 and bl, 7fh             ;BX = scancode value

 sar al, 07h             ;AL = 0ffh if scancode has bit7 set (release), 00h otherwise
 not al                  ;AL = 00h if scancode has bit7 set (release), 0ffh otherwise

 ;Save the scancode status
 mov BYTE [cs:bx + scancode_status], al 
 ;Increment the count
 inc WORD [cs:new_scancode]

 pop ax
 pop bx 

_ni15_legacy:   
 ;This is a far jump, in NASM is simply jmp FAR [cs:old_isr_15]
 ;Ended up this way for debug
 push WORD [cs: old_isr_15 + 02h] 
 push WORD [cs: old_isr_15] 
 retf

 ;Original ISR
old_isr_15                      dw new_isr_15, 0  

 ;Scan code status table
scancode_status     TIMES 128   db 0
 ;Scan code count 
new_scancode                    dw 0

所有你需要使用的是:


  • 的init 来设置扫描code Snooping功能。

  • 处理推倒扫描code Snooping功能。

  • is_scan code_ pressed 来知道,如果一个键被按下。

  • init to set up the scancode snooping.
  • dispose to tear down the scancode snooping.
  • is_scancode_pressed to know if a key is being held down.

其他的一切,包括 wait_for_scan code remove_keystrokes 的配件,在那里只是为了让你的程序表现得非常好。

Everything else, including wait_for_scancode and remove_keystrokes is accessory and is there just to make your program behave very nice.

如果你想找到一个键关联的扫描code,可以使用这个其他程序这个节目你用$ p $表pssed扫描codeS(preSS的 ESC 的退出)。结果
例如,如果我preSS的 A D 的我得到在演示中使用的值

If you want to find the scancode associated with a key, you can use this other program that show you a table with the pressed scancodes (press ESC to exit).
For example, if I press a and d I get the values used in the demo

我pressing'a'和'D'

这仅仅是一个上面演示的变种。

It is just a variant of the demo above.

1 创建引导程序(用于NASM)来测试我的假​​设,至少在我的硬件。

1I create this boot program (intended for NASM) to test my hypothesis, at least in my hardware.

2 讲有效的重复功能仅在打字软件是有用的,其他所有的应用程序,如游戏,明确检查按键的状态并不需要它。

2 Effectively speaking the repeat feature is useful only in typing software, every other application, like games, that explicitly check for keys status don't need it.

3 其实有扩展(多字节扫描code),但他们在这里被忽略。坚持用普通钥匙!

3 There are actually extended (multi byte scancode) but they are ignored here. Stick with plain keys!

这篇关于检测/在DOS下同时接收多个键盘presses?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆