获得键盘扫描码
概述:
  
      在编制键盘输入程序时常常要用到一个键的扫描码或ASC码,如用到 Foxpro 的 inkey() 函数,以及用到 
  BIOS 的 INT 16H时,但找一个编码表不太容易,有时候找到的编码表又不全,无法查到组合键的编码,本程序就是一个随时用来显示按键的ASC码及扫描码的程序,可以用 
  16 进制和 10 进制同时显示一个键按下和放开的扫描码,以及ASC码,同样也支持组合键。这里是编译好的可执行文件:scancode.com
      在本程序中,查表的编程方法可用做参考,一般来说,如果程序有以下的结构:
  
         ...
         cmp     al,value1
         jz      offset1
         cmp      al,value2
         jz      offset2
         cmp     al,value3
         jz      offset3
         ...
  
  且要比较的值很多时,可以考虑查表的方法。程序改为以下结构后,修改起来很容易,可读性也大大增强了,如果要继续添加分支时,只需在表中加上一项就行。
  
         ...
  table  db     value1,value2,value3 ...
  table1 dw     offset1,offset2,offset3 ...
  
          mov    di,offset table
          mov    cx,table的长度
          repnz  scasb
          jnz    not_found
  
          dec    di
          sub    di,offset table 
          ;取出表的地址
          mov    si,di
          shl    si,1                    
  ;x2
          add    si,offset table1
          jmp    [si]                    
  ;跳转到表中的地址
          ...
  
      
  源程序:
  
  ;    Scan code viewer
  ;    Aug 3,1995
  ;    by Luo Yun Bin
  
  .286
  CODE      SEGMENT
            ASSUME     
  CS:CODE,DS:CODE
            ORG    
  100H
  start:
            jmp    
  install
  
  KEY_BUFF  DB    ?             
  ;INT 9H中按下一个键产生的扫描码
  KEY_BUFF1 DB    ?             
  ;INT 9H中松开一个键产生的扫描码
  AAH       DB    ?
  AAL       DB    ?
  
  D_COPYRIGHT    DB    "<< ScanCode viewer 
  >>",0dh,0ah
          DB    '(C) Copyright 
  by Luo Yun Bin, May 26,1996',0dh,0ah
          DB    'Phone: 0576-4114689.',0dh,0ah,0ah
          DB    "Press 
  any key to view it's scan code...",0dh,0ah
          DB    'or press Esc 
  key to return DOS...',0dh,0ah,0ah,24h
  D_MES1  DB    'Scan Code: %02shh (%2sd) ... '
          DB    'Release: %02shh 
  (%3sd) ... Key: ',0
          DW     KEY_BUFF,KEY_BUFF,KEY_BUFF1,KEY_BUFF1
  D_MES2  DB    0dh,0ah,0
  D_MES3  DB    'Key value: %02sh%02shh ...... '
          DB     '(AH=%sd,AL=%sd)',0dh,0ah,0ah,0
          DW    AAH,AAL,AAH,AAL
  D_MES4  DB    'This is Scan Code viewer by LYB.',0dh,0ah,24h
  
  ;键盘扫描码编码表
  ;                    
  0123456789abcdef ;
  KEY_TABLE    DB    '??1234567890-=??' ;0
               DB 
      'QWERTYUIOP[]??AS' ;1
               DB 
      "DFGHJKL;'`?\ZXCV" ;2
               DB 
      'BNM,./?*????????' ;3
               DB 
      '??????????-?5?+?' ;4
               DB 
      '????????????????' ;5
               DB 
      '????????????????' ;6
               DB 
      '????????????????' ;7
  
  ;特殊键的说明字符串编码表
  KEY_TABLE1   DB     3bh,3ch,3dh,3eh,3fh,40h,41h,42h,43h,44h,57h,58h
               DB 
      0eh,0fh,3ah,2ah,1dh,38h,36h,1ch,39h,1
               DB 
      52h,53h,47h,4fh,49h,51h,48h,50h,4bh,4dh,46h,45h
  
  ;对应上表
  KEY_TABLE1_END    EQU    THIS BYTE
            DW     
  f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12
            DW     
  bks,tab,cap,lsh,ctr,alt,rsh,ent,spa,_esc
            DW     
  _ins,del,hom,_end,pgu,pgd,up,dow,lef,rig,sco,num
  
  ;特殊键的说明字符串
  f1        db    'F1',0         
  ;
  f2        db    'F2',0
  f3        db    'F3',0
  f4        db    'F4',0
  f5        db    'F5',0
  f6        db    'F6',0
  f7        db    'F7',0
  f8        db    'F8',0
  f9        db    'F9',0
  f10       db    'F10',0
  f11       db    'F11',0
  f12       db    'F12',0
  bks       db    'Back Space',0
  tab       db    'Table',0
  cap       db    'Caps Lock',0
  lsh       db    'Left Shift',0
  ctr       db    'Ctrl',0
  alt       db    'Alt',0
  rsh       db    'Right Shift',0
  ent       db    'Enter',0
  spa       db    'Space',0
  _ins      db    'Insert',0
  del       db    'Delete',0
  hom       db    'Home',0
  _end      db    'End',0
  pgu       db    'Page Up',0
  pgd       db    'Page Down',0
  up        db    'Up',0
  dow       db    'Down',0
  lef       db    'Left',0
  rig       db    'Right',0
  sco       db    'Scroll Lock',0
  num       db    'Num Lock',0
  _esc      db    'Esc',0
  
  PRINT_KEY    PROC
  
          mov    bl,key_buff 
              ;取扫描码到BL
          xor    bh,bh
          mov    al,key_table 
  [bx]       ;查扫描码表
  
          cmp    al,'?'                  
  ;如果为?则继续查特殊码表
          jz     pk1
  pk0:
          call   prt_to_scr
          ret
  pk1:
          mov    al,key_buff 
              ;在特殊码表内扫描
          mov    di,offset key_table1
          mov    cx,offset key_table1_end-offset 
  key_table1
          repnz  scasb
          jnz    pk0
  
          dec    di
          sub    di,offset key_table1 
     ;取出说明字符串地址
          mov    si,di
          shl    si,1
          add    si,offset key_table1_end
          mov    si,[si]
          call   printf                  
  ;显示到屏幕
  
          ret
  
  PRINT_KEY    ENDP
  
  ;新的 INT 09H 键盘中断程序
  int9:
          pushf
          pusha
          push    ds
          push    es
  
          push    cs
          pop     ds
          push    cs
          pop     es
  
          in      
  al,60h                 
  ;读入扫描码
          mov     key_buff,al
  
          test    al,80h                 
  ;如果>80H则为放开一个键
          jnz     int9_quit
  
          or      
  al,80h
          mov     key_buff1,al
  
          mov     si,offset 
  d_mes1
          call    printf
          call    print_key
          mov     si,offset 
  d_mes2
          call    printf
  int9_quit:
          pop     es
          pop     ds
          popa
          popf
  
          DB      
  0EAH
  OFF9    DW      ?
  SEG9    DW      ?
  
  install:
          mov    ah,9              
  ;显示版权信息
          mov    dx,offset d_copyright
          int    21h
  
          mov    ax,3509h          
  ;保留INT 09H的中断向量
          int    21h
          mov    off9,bx
          mov    seg9,es
          mov    ax,2509h          
  ;把INT 09H指到 offset int9
          mov    dx,offset int9
          int    21h
          push   cs
          pop    es
  lop:
          mov    ah,10h             
  ;扩展键盘输入
          int    16h
  
          mov    aah,ah             
  ;显示键盘输入的编码
          mov    aal,al
          mov    si,offset d_mes3
          call   printf
  
          cmp    key_buff,1 
          ;如果非按下Esc,继续循环
          jnz    lop
  
          lds    dx,dword ptr 
  off9 ;恢复INT 09H中断向量
          mov    ax,2509h
          int    21h
  
          push   cs
          pop    ds
  
          mov    ah,9
          mov    dx,offset d_mes4
          int    21h
  
          int    20h
  
  INCLUDE PRINTF.ASM                
  ;一个公用的显示子程序
  
  CODE    ENDS
          END    START