寒江独钓 第四章 按键信息 扫描码和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. };











### 回答1: 《寒江独钓Windows内核编程源》是一本非常经典的内核编程书籍。该书主要介绍了Windows内核的结构和工作原理,以及如何进行内核编程。作者通过自己的实践经验,深入浅出地解释了内核编程的基本原理和技巧。 该书的主要内容包括:Windows内核架构、内核模式和用户模式编程、驱动程序开发、处理器管理、内存管理、进程和线程管理、设备驱动程序、文件系统等。通过学习这些内容,读者可以全面了解Windows内核的各个方面,并具备进行内核编程的基础知识和技能。 内核编程是一项非常高级和复杂的技术,需要读者具备扎实的操作系统和编程基础。《寒江独钓Windows内核编程源》提供了丰富的源示例和实践案例,帮助读者加深对内核编程的理解,并能够在实践中掌握内核编程的各种技巧和方法。 通过学习该书,读者可以深入了解Windows内核的工作原理和开发方法,提升自己的技术水平,并有可能在内核开发领域取得突破。同时,该书也适合作为操作系统课程的参考书籍,帮助读者更好地理解操作系统的底层原理和设计思想。 总之,《寒江独钓Windows内核编程源》是一本值得学习的经典书籍,通过学习该书,读者可以从理论和实践两个方面全面提升自己的内核编程能力。 ### 回答2: 寒江独钓Windows内核编程源,这是指在Windows操作系统内核级别的编程过程中,个人独自执钓的情景。在传统的Windows内核编程中,需要深入理解Windows操作系统的内部机制、数据结构和调度算法,并通过编写驱动程序或者修改系统核心源来实现特定的功能或解决某些问题。这是一项相当具有挑战性和专业性的技术领域。 寒江者,指的是独自一人默默钓鱼的情景。在这个比喻中,内核编程者是在深入学习和专研Windows内核编程的过程中,独自探索和解决问题,就像在江边的一个人默默地捕捞。 Windows内核编程源指的是Windows操作系统的核心代。对这些源的学习和理解,是了解Windows操作系统内部工作原理的关键。通过研究内核编程源,我们可以了解系统如何管理进程、内存分配、文件系统等功能,以及与硬件的交互过程。 进行寒江独钓Windows内核编程源可以带来许多好处。首先,它可以深入了解Windows操作系统的底层工作原理,从而更好地进行系统调试和性能优化。其次,它可以为用户定制和开发高性能的驱动程序,提升系统的稳定性和响应能力。此外,通过研究内核编程源,可以了解Windows操作系统的安全性和漏洞,从而更好地防范和解决安全问题。 然而,寒江独钓Windows内核编程源并不是一项简单的事情,它需要对操作系统原理、编程语言和底层架构有深入的理解。同时,需要拥有扎实的计算机科学基础和编程技巧,以及耐心和毅力来解决各种挑战和问题。 总之,寒江独钓Windows内核编程源是一项有挑战性的技术活动,通过对Windows操作系统内核代的深入研究和理解,可以提高对系统的控制和优化能力,从而为用户提供更好的系统性能和功能。 ### 回答3: 《寒江独钓Windows内核编程源》是一本关于Windows内核编程的书籍,作者以“寒江独钓”来形容自己在Windows内核编程领域的独孤求败之意。这本书主要介绍了Windows操作系统的内核编程细节和原理。 在这本书中,作者首先介绍了Windows内核的基本概念和架构,包括进程和线程管理、内存管理、驱动程序开发等。接着,作者深入讲解了Windows内核的各个模块和重要组件的实现原理,如调度器、文件系统、网络协议栈等。读者可以通过学习这些源,深入理解Windows内核的工作原理和设计思想。 《寒江独钓Windows内核编程源》不仅仅是一本理论性的书籍,更重要的是它提供了丰富的源代示例和实践案例,读者可以通过实际的代实现和调试来加深对内核编程的理解。同时,本书还特别注重实用性,提供了大量的编程技巧和调试技巧,帮助读者快速掌握Windows内核编程的方法和技巧。 总之,《寒江独钓Windows内核编程源》是一本全面而深入的Windows内核编程技术书籍,适合那些对Windows系统内核感兴趣的程序员和操作系统开发者阅读。通过学习这本书,读者可以系统地学习Windows内核编程的原理和实践,提升自己的技术水平。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值