easy_key

https://cloud.tencent.com/developer/article/2227809

通过键盘的输入安装驱动来输入

  • 类驱动(Class Driver):指的是负责同一类设备(如键盘)的通用驱动程序。无论设备通过 USB 接口还是 PS/2 接口连接,Windows 都会通过键盘类驱动程序(KbdClass)进行处理。类驱动更侧重于设备的通用逻辑操作,而不直接处理硬件细节。
  • 端口驱动(Port Driver):负责直接与具体硬件设备交互。对于键盘设备:
    • i8042prt 是 PS/2 键盘的端口驱动程序。
    • Kbdhid 是 USB 键盘的端口驱动程序。

1. 按键事件的处理流程

  • 按键产生扫描码
    • 当按键被按下,生成 Make Code,触发键盘中断。
    • 当按键被松开,生成 Break Code,再次触发键盘中断。
  • 键盘中断服务例程
    • 中断信号触发后,执行键盘中断服务例程 I8042KeyBoardInterruptService(由 i8042prt 提供)。
    • 在该例程中:
      1. 从端口读取按键的扫描码。
      2. 将扫描码存入 KEYBOARD_INPUT_DATA 结构。
      3. 将该结构存入 i8042prt 的输入数据队列
      4. 数据队列中指针 DataIn 后移,InputCount 加 1。
      5. 调用内核函数 KeInsertQueueDpc,执行延迟过程调用(DPC, Deferred Procedure Call)以进一步处理数据。

2. 端口驱动与类驱动的数据交互

  • 延迟过程调用(DPC)
    • 在 DPC 中,i8042prt 调用上层的回调函数(KbdClass 的输入数据处理函数)。
    • 回调函数从 i8042prt 的输入数据队列中取出数据,完成后:
      • DataOut 指针后移,InputCount 减少。

3. 处理读请求

  • 应用层通过 IRP_MJ_READ 请求读取键盘数据,具体处理逻辑如下:
    • 读请求的大小 ≥ i8042prt 队列中的数据量
      • 直接从 i8042prt 的输入数据队列中读取所有数据,无需经过 KbdClass 队列。
    • 读请求的大小 < i8042prt 队列中的数据量
      • 从 i8042prt 的输入数据队列中读取请求大小的数据,完成后将剩余数据存入 KbdClass 的输入数据队列
      • 后续读请求可以直接从 KbdClass 的队列中读取数据,无需等待新的键盘事件。

4. 关键点:类驱动的回调函数

  • i8042prt 与 KbdClass 的交互依赖于一个回调函数。
  • 这个回调函数的入口地址存储在 i8042prt 的设备扩展中。
  • Hook 该回调函数后,可以截获所有键盘输入,轻松获取扫描码。

这个就相当于是编写了这个回调函数,通过访问数据队列判断读入是否正确

https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#scan-codes

定位到地址 180001caf

输入的对应项为 Scan 1 Make

https://www.52pojie.cn/thread-1989657-1-1.html#51955863_easy_key%EF%BC%88%E5%A4%8D%E7%8E%B0%EF%BC%89

keys = [32, 42, 11, 34, 4, 45, 34, 42, 46, 42, 26, 42, 30, 7, 7, 48, 3, 4, 5, 3, 12, 11, 5, 32, 5, 12, 5, 7, 9, 30, 12, 10, 10, 32, 4, 12, 8, 18, 32, 48, 30, 5, 46, 10, 11, 11, 2, 33, 27, 42]
d = {0x1E: "A", 0x30: "B", 0x2E: "C", 0x20: "D", 0x12: "E", 0x21: "F", 0x22: "G", 0x23: "H", 0x17: "I", 0x24: "J", 0x25: "K", 0x26: "L", 0x32: "M", 0x31: "N", 0x18: "O", 0x19: "P", 0x10: "Q", 0x13: "R", 0x1F: "S", 0x14: "T", 0x16: "U", 0x2F: "V", 0x11: "W", 0x2D: "X", 0x15: "Y", 0x2C: "Z", 0x02: "1", 0x03: "2", 0x04: "3", 0x05: "4", 0x06: "5", 0x07: "6", 0x08: "7", 0x09: "8", 0x0A: "9", 0x0B: "0", 0x2a: "[shift]", 0xc: "-"}

# 将列表中的键码转换为对应的字符
mapped_keys = [d.get(key, '') for key in keys]

# 将字符列表合并为一个字符串
output_string = ''.join(mapped_keys)

print(output_string)