寒江独钓 第四章 按键信息 扫描码和Ascii码

4.4.1从缓冲区中获得KEYBOARD_INPUT_DATA
    请求完成之后,读到的信息在Irp->AssociatedIrp.SystemBuffer中,这个缓冲区可能含有n个KEYBOARD_INPUT_DATA结构
    这个结构定义如下
   
   
  1. typedef struct _KEYBOARD_INPUT_DATA
  2. {
  3. //对设备\Device\KeyboardPort0,这个值是0;对\Device\KeyboardPort1,这个值是1,依次类推
  4. USHORT UnitId;
  5. //扫描码
  6. USHORT MakeCode;
  7. //一个标记.是一个键按下(0)放还是弹起(非0)
  8. USHRT Flags;
  9. //保留
  10. USHORT Reserved;
  11. //扩展信息
  12. ULONG ExtraInformation;
  13. }KEYBOARD_INPUT_DATA,*PKEYBOARD_INPUT_DATA;
    至于有多少个这样的结构,取决于输入缓冲区到底有多长
   
   
  1. size = buf_len/sizeof(KEYBOARD_INPUT_DATA);

4.4.3从MakeCode到实际字符
    所谓的实际字符就是ASII码,大写/小写字符的ASCII码并不相同,但是键是同一个(扫描码相同),具体是哪个取决于几个键的状态(Shift,Caps Lock,Num Lock键).Shift键和Caps Lock键不同:Shift键是按下生效,释放则无效;而Caps Lock键是按一次生效,再按一次无效.
    下面代码把这些控制键的状态保存在kb_status这个变量,用3个位来保留.
  
  
  1. #define S_SHIFT 1 //001
  2. #define S_CAPS 2 //010
  3. #define S_NUM 4 //100
  4. //这是一个标记,用来保存当前键盘的状态,其中3个位,分别表示CapsLock键,NumLock键和Shift键是否按下了
  5. static int kb_status = S_NUM;
  6. void __stdcall print_keystroke(UCHAR sch)
  7. {
  8. UCHAR ch = 0;
  9. switch(sch)
  10. {
  11. //Caps Lock键和Num Lock键类似,都是"按下两次"等于没按过一样,这里用异或设置标志
  12. case 0x3A:
  13. kb_status ^=S_CAPS;
  14. break;
  15. //Num Lock键
  16. case 0x45:
  17. kb_status ^=S_NUM;
  18. break;
  19. //注意Shift键的特点
  20. //(1)Shift键有两个,左右各一个,扫描码互不相同
  21. //(2)Shift键是按下起作用,弹起则作用消失,所以这里用或来设置标记
  22. case 0x2a:
  23. case 0x36:
  24. kb_status |= S_SHIFT;
  25. break;
  26. }
  27. //如果按下了字母或者是数字等可见字符
  28. if((sch <0x47) || ((sch >= 0x47 && sch < 0x54)&& (kb_status & S_NUM) ))
  29. {
  30. //最终得到哪个字符必须由Caps Lock和NumLock及Shift这几个键的状态来决定,所以写在一张表中
  31. if (kb_status & S_CAPS)
  32. {
  33. if (kb_status & S_SHIFT)
  34. ch = asciiTblCaps_Shift[sch];
  35. else
  36. ch = asciiTblCaps[sch];
  37. }
  38. else if(kb_status & S_SHIFT)
  39. ch = asciiTblShift[sch];
  40. else
  41. ch = asciiTblNormal[sch];
  42. if(ch >= 0x20 && ch < 0x7F) //打印出可见字符
  43. DbgPrint("%C \n",ch);
  44. }
  45. }
    完整的完成函数:
   
   
  1. //PKEYBOARD_INPUT_DATA要引用下面的头文件 #include <ntddkbd.h>   
  2. NTSTATUS c2pReadComplete(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)
  3. {
  4. size_t i;
  5. if(NT_SUCCESS(Irp->IoStatus.Status))
  6. {
  7. PKEYBOARD_INPUT_DATA KeyData = (PKEYBOARD_INPUT_DATA)(Irp->AssociatedIrp.SystemBuffer);
  8. //Flags == 0 表示按下
  9. if (KeyData->Flags == 0)
  10. {
  11. ULONG numKeys = Irp->IoStatus.Information/sizeof(KEYBOARD_INPUT_DATA);
  12. for (i=0;i<numKeys;i++)
  13. {
  14. //打印实际字符
  15. print_keystroke((UCHAR)KeyData->MakeCode);
  16. }
  17. }
  18. else
  19. {
  20. if(KeyData->MakeCode == 0xAA || KeyData->MakeCode == 0xB6) //+0x80为Shift弹起的扫描码
  21. kb_status &= ~S_SHIFT; //Shift键弹起,kb_status第1个位归为0
  22. }
  23. gC2pKeyCount--;
  24. if(Irp->PendingReturned)
  25. {
  26. IoMarkIrpPending(Irp);
  27. }
  28. return Irp->IoStatus.Status;
  29. }
  30. }
    Ascii字符表
   
   
  1. unsigned char asciiTblNormal[]={
  2. 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09, //normal
  3. 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x0D, 0x00, 0x61, 0x73,
  4. 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x60, 0x00, 0x5C, 0x7A, 0x78, 0x63, 0x76,
  5. 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
  7. 0x32, 0x33, 0x30, 0x2E,
  8. };
  9. unsigned char asciiTblCaps[]={
  10. 0x00, 0x1B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x2D, 0x3D, 0x08, 0x09, //caps
  11. 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x5B, 0x5D, 0x0D, 0x00, 0x41, 0x53,
  12. 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3B, 0x27, 0x60, 0x00, 0x5C, 0x5A, 0x58, 0x43, 0x56,
  13. 0x42, 0x4E, 0x4D, 0x2C, 0x2E, 0x2F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  14. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
  15. 0x32, 0x33, 0x30, 0x2E,
  16. };
  17. unsigned char asciiTblShift[]={
  18. 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09, //shift
  19. 0x51, 0x57, 0x45, 0x52, 0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x7B, 0x7D, 0x0D, 0x00, 0x41, 0x53,
  20. 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 0x7E, 0x00, 0x7C, 0x5A, 0x58, 0x43, 0x56,
  21. 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  22. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
  23. 0x32, 0x33, 0x30, 0x2E,
  24. };
  25. unsigned char asciiTblCaps_Shift[]={
  26. 0x00, 0x1B, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29, 0x5F, 0x2B, 0x08, 0x09, //caps + shift
  27. 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 0x75, 0x69, 0x6F, 0x70, 0x7B, 0x7D, 0x0D, 0x00, 0x61, 0x73,
  28. 0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3A, 0x22, 0x7E, 0x00, 0x7C, 0x7A, 0x78, 0x63, 0x76,
  29. 0x62, 0x6E, 0x6D, 0x3C, 0x3E, 0x3F, 0x00, 0x2A, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  30. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x38, 0x39, 0x2D, 0x34, 0x35, 0x36, 0x2B, 0x31,
  31. 0x32, 0x33, 0x30, 0x2E,
  32. };











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值