回 帖 发 新 帖 刷新版面

主题:最近做按键检测的成果

DIM keystate(0 TO 255) AS INTEGER
DIM keycheck(0 TO 9) AS INTEGER
DIM keyname(0 TO 9) AS STRING * 8
CLS
FOR i = 0 TO 9
  READ keycheck(i)
NEXT i
DATA &hc8,&hcb,&hcd,&hd0,&h2a,&h36,&h1d,&h9d,&h38,&hb8
LOCATE 7, 1
PRINT "Press [ESC] to quit..."
PRINT "Press key below, to see if it's working"
LOCATE 10, 1
FOR i = 0 TO 9
  READ keyname(i)
  PRINT keyname(i);
NEXT i
PRINT
DATA "Up      ","Left    ","Right   ","Down    ","Lshift  ","Rshift  ","LCtrl   ","RCtrl   ","LAlt    ","RAlt    "
exflag = 0
oldkey = 0
COLOR 12
DO
  DO
    oldkey = nowkey
    nowkey = INP(&H60)
  LOOP WHILE nowkey = oldkey
  IF nowkey = &HE0 THEN
    exflag = 1
  ELSE
    IF exflag = 0 THEN
      IF nowkey < &H80 THEN
        keystate(nowkey) = 1
      ELSE
        keystate(nowkey - &H80) = 0
      END IF
    ELSE
      IF nowkey < &H80 THEN
        keystate(nowkey + &H80) = 1
      ELSE
        keystate(nowkey) = 0
      END IF
      exflag = 0
    END IF
  END IF
  LOCATE 12, 1
  FOR i = 0 TO 9
    IF keystate(keycheck(i)) = 1 THEN
      PRINT keyname(i);
    ELSE
      PRINT SPC(8);
    END IF
  NEXT i
  'clear keys store in computer
  WHILE INKEY$ <> ""
  WEND
LOOP UNTIL nowkey = 1   'esc
COLOR 7
END

回复列表 (共5个回复)

沙发

对键盘的检测程序
CLS
oldkey = 0
DO
  newkey = INP(&H60)
  IF newkey <> oldkey THEN
    oldkey = newkey
    PRINT HEX$(newkey);
    IF newkey < &H80 THEN
      PRINT , HEX$(newkey + 128), TIMER
    ELSE
      PRINT , , TIMER
    END IF
  END IF
LOOP UNTIL newkey = &H81  'free esc
END

依照这个程序
测试按下一定按键时,&H60端口的值的变化

测试结果如下:
        press  free
LShift   2A     AA
LCtrl    1D     9D
LAlt     38     B8
RShift   36     B6
        press    free
RCtrl  *E0 1D*   E0 9D
RAlt   *E0 38*   E0 B8
            press                  free
Up     *E0 2A E0 48 E0 AA*    E0 2A E0 C8 E0 AA
Left   *E0 2A E0 4B E0 AA*    E0 2A E0 CB E0 AA
Right  *E0 2A E0 4D E0 AA*    E0 2A E0 CD E0 AA
Down   *E0 2A E0 50 E0 AA*    E0 2A E0 D0 E0 AA

注:Up   *E0 2A E0 48 E0 AA*  表示按住 Up 时(编辑区)60h端口的值沿着这个顺序循环变化(运行上面的测试程序可以看到结果)
这里把暂且把 E0 2A E0 48 E0 AA 称作 Up的“检测序列”

板凳

对于一般按键 按下时60h端口的值直接为扫描码(press code)
松开按键时 60h端口的值(free code)=(press code)+ &H80
(press code)和 (free code)都是一个字节的数据
可以通过上面的程序测试需要的按键的(press code)和(free code)
从上面的分析可以看出 当有扩展键 被按下时
60h端口会先送出一个 E0h 其后为扫描码
这样就可以把 E0h作为一个扩展键的开始码 这也是程序中出现 exflag的原因

对于RCtrl 和 RAlt 是E0 + ctrl、Alt的扫描码
即 *E0 (press code)* 按住时会循环出现这两个值
松开时为 E0 (free code)
对于up~down 是 E0 2A E0 +up、left、right、down 的扫描码 + E0 AA
分析同上

不过多了E0 2A 和E0 AA
2A 为LShift的 (press code)
AA 为LShift的 (free code)

读到这里 大概会想 如果LShift 和 Up按下了怎么检测
经测试 按下L、R shift后 Up的为 press: *E0 48*  free: E0 C8
也就是说按下shift后 Up的“检测序列”发生变化了

3 楼

最后 关于这个按键检测 还有很多很有意思的问题 限于篇幅(说多了显得累赘)
大家可以在一楼提供的程序的基础上 测试一下 一些按键 以及按键序列 产生的相应的“检测序列”

关于键盘的说明
键盘中有一个芯片 在键盘上有按键 按下时 向60h端口写入一个字节的数据 同时向CPU 发出一个中断请求 ,CPU接到中断请求后执行Int 09h 中断例程(硬件中断)
(测试一下同时按键序列 你将会发现这个芯片很神气的)

关于60h端口的说明(如有不对请指出)
ibm Pc机中的存在一个独立于内存的64k的空间 ,在这个空间中每一个字节都是一个端口
cpu通过这个端口和外设传输少量数据 或者设置端口中的某些位来控制外设的工作状态
外设也通过端口来返回外设当前的状态 比如 free busy

键盘芯片和cpu的交换数据的端口之一就是60h端口

4 楼

看不懂,讲细点

5 楼

[quote]关于60h端口的说明(如有不对请指出)
ibm Pc机中的存在一个独立于内存的64k的空间 ,在这个空间中每一个字节都是一个端口
cpu通过这个端口和外设传输少量数据 或者设置端口中的某些位来控制外设的工作状态
外设也通过端口来返回外设当前的状态 比如 free busy

键盘芯片和cpu的交换数据的端口之一就是60h端口[/quote]

建议你看一下硬件/汇编的相关书籍。

所谓0x60端口(原谅我,我是用c/c++的),并不是说在内存中,或者是在内存外,真的有一块储存区,以cpu读取0x60端口为例,地址线输出0x60(哪几根0哪几根1我就不负责数了),同时IOR置有效,说明是一次IO端口操作而非MEM操作。经过片选译码之后,给键盘上的芯片一个(两个?)使能信号,但是——但是我犯了一个错误,键盘输出是锁存的——总之cpu接下来的某个时钟周期里对data线进行一个读取的动作,就把0x60端口的数据读入了。

换句话说,cpu指示了0x60这个地址,结果是某个外设接到了信号,并把数据传到数据线上。

传送数据可以不是“少量”——君不见usb2.0可以达到12M/s的峰值,那也是一个端口,我自己写过一个网卡驱动,虽然破烂不堪,也有1.2M/s的传输速率,那也是从一个端口读出来的。

:P

我来回复

您尚未登录,请登录后再回复。点此登录或注册