键盘按键处理过程

键盘按键:

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消息。

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

 

--写于2013-11-3

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值