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 提供)。 - 在该例程中:
- 从端口读取按键的扫描码。
- 将扫描码存入
KEYBOARD_INPUT_DATA
结构。 - 将该结构存入 i8042prt 的输入数据队列。
- 数据队列中指针
DataIn
后移,InputCount
加 1。 - 调用内核函数
KeInsertQueueDpc
,执行延迟过程调用(DPC, Deferred Procedure Call)以进一步处理数据。
- 中断信号触发后,执行键盘中断服务例程
2. 端口驱动与类驱动的数据交互
- 延迟过程调用(DPC):
- 在 DPC 中,i8042prt 调用上层的回调函数(KbdClass 的输入数据处理函数)。
- 回调函数从 i8042prt 的输入数据队列中取出数据,完成后:
DataOut
指针后移,InputCount
减少。
3. 处理读请求
- 应用层通过
IRP_MJ_READ
请求读取键盘数据,具体处理逻辑如下:- 读请求的大小 ≥ i8042prt 队列中的数据量:
- 直接从 i8042prt 的输入数据队列中读取所有数据,无需经过 KbdClass 队列。
- 读请求的大小 < i8042prt 队列中的数据量:
- 从 i8042prt 的输入数据队列中读取请求大小的数据,完成后将剩余数据存入 KbdClass 的输入数据队列。
- 后续读请求可以直接从 KbdClass 的队列中读取数据,无需等待新的键盘事件。
- 读请求的大小 ≥ i8042prt 队列中的数据量:
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)