键盘按键处理过程

键盘按键:
1. 当按下键盘的一个按键时,键盘产生硬件中断信号发到总线,总线将信号发送到ioapic寄存器接收,ioapic寄存器存储了键盘中断的中断idt的索引号,和发给哪个cpu来处理(针对多核),
   然后发给该cpu的local apic 寄存器
2. local apic接收到信号,里面存储了中断idt 索引号到idt键盘中断处理地址的映射。然后发给键盘中断处理例程,该例程再依次传给键盘端口驱动,端口类驱动,将按键的break code放到端口类驱动的设备扩展中。自下而上的过程结束
3. win32k的RawInputThread是一个死循环的例程,它会不断的发送io control 给顶层的键盘类驱动设备,读出按键的break code
4. RawInputThread接收到扫描码后,调用ProcessKeyboardInput()函数经过底层键盘钩子处理,匹配是win,alt+tab等按键,如果是则调用对应的显示开始菜单函数。
   不是再匹配普通字符,发post消息给顶层窗口的线程,顶层窗口进入windows注册的WndProc过程中,进入wm_char处理按键消息



详细版:
1. 当按下键盘的一个按键时,键盘产生硬件中断信号发到总线,总线将信号发送到ioapic寄存器接收,ioapic寄存器存储了键盘中断的中断idt的索引号,和发给哪个cpu来处理(针对多核),然后发给该cpu的local apic 寄存器
2. local apic接收到信号,里面存储了中断idt 索引号到idt键盘中断处理地址的映射。然后发给键盘中断处理例程(i8042prt!I8042KeyboardInterruptService).该函数工作:读入用户敲击按键,将按键信息读入i8042prt驱动的设备扩展队列中,投递一个Dpc,请求上层键盘类驱动kbdclass处理。具体:调用I8xGetByteAsynchronous获取按键信息,调用I8xQueueCurrentKeyboardInput处理按键信息:首先调用I8xWriteDataToKeyboardQueue将按键信息写入设备对象扩展的一个保存队列中,然后投递一个DPC。该dpc用来请求绑定在i8042上的kbdclass键盘类驱动,具体过程是执行i8042prt!I8042KeyboardIsrDpc函数,该函数调用I8xGetDataQueuePointer获取键盘端口驱动保存在设备扩展的按键信息队列指针,调用kbdclass!KeyboardClassServiceCallback完成按键信息的交付。然后调用I8xSetDataQueuePointer更新设备扩展的按键信息队列。
3.kbdclass!KeyboardClassServiceCallback类驱动函数处理过程。将键盘信息从端口驱动的键盘信息队列中复制到类驱动的队列中。wdk的例子中有该函数源代码。

自下而上的执行过程就结束了。

4.win32k的RawInputThread例程负责处理键盘和鼠标的中断和应用层消息。该函数被调用的过程大致为xxxCreateWindowStation->xxxInitTerminal(创建rit和desktop线程)->CreateTerminalInput->xxxInitInput->CreateSystemThread(RawInputThread).
在win32k中,有个全局变量aDeviceTemplate存储了键盘和鼠标的处理函数,对应键盘DEVICE_TYPE_KEYBOARD的为ProcessKeyboardInput函数。在RawInputThread函数中,先初始化键盘和鼠标设置,然后调用_RegisterHotKey注册系统热键,然后while(true)不断通过KeWaitForMultipleObjects等待键盘和鼠标事件,如果有鼠标事件,则调用ProcessDeviceChanges(DEVICE_TYPE_KEYBOARD)处理键盘事件。然后看是不是按下了alt+tab键。
5.在ProcessDeviceChanges(DEVICE_TYPE_KEYBOARD)函数中,判断是鼠标或者键盘消息,根据pDeviceInfo->usActions判断是读还是其他操作做对应处理。然后ZwDeviceIoControlFile查询按键信息。然后KeSetEvent激活PnP事件调用4中说的键盘处理函数ProcessKeyboardInput。调用win32k!InputApc->win32k!StartDeviceRead->nt!ZwReadFile
->调用到kbdclass!KeyboardClassRead去读键盘按键信息。
5.在ProcessKeyboardInput函数中,先通过VKFromVSC做扫描码的转换,然后调用xxxProcessKeyEvent处理按键。.在xxxProcessKeyEvent函数中,调用xxxKeyEvent处理。
6.在xxxKeyEvent中,调用xxxCallHook2去实现WH_KEYBOARD_LL底层键盘钩子,然后检查热键,然后PostInputMessage(gpqForeground,xxxx)给顶层窗口发消息,然后匹配QEVENT_APPCOMMAND是不是windows增强消息,比如键盘按键直接打开浏览器等上网。
7.在PostInputMessage中,先调用StoreQMessage存储在消息队列,然后调用WakeSomeone唤醒目标进程处理.
8.在WakeSomeOne中,匹配消息类型,是wm_keydown,wm_char,wm_mousemove等,然后调用  StoreQMessagePti存在目标线程即顶层窗口队列中,当轮到目标线程执行时,处理  wm_keydown和wm_char消息。
自上而下的过程就结束了。

你可能感兴趣的:(OD调试)