.Net WinForm 控件键盘消息处理剖析

转帖|其它|编辑:郝浩|2010-10-26 14:20:39.000|阅读 677 次

概述:在WinForm控件上我们可以看到很多关于键盘消息处理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等,那么这些方法是如何被组织的,每一个方法的具体含义又是什么哪?Win32的键盘消息又是如何到达控件上的这些方法的,本文将着重阐述这些问题,对.Net WinForm控件的键盘消息处理过程进行剖析。

  在WinForm控件上我们可以看到很多关于键盘消息处理的方法,比如OnKeyDown, OnKeyPress, ProcessCmdKey, ProcessDialogKey,IsInputKey等等,那么这些方法是如何被组织的,每一个方法的具体含义又是什么哪?Win32的键盘消息又是如何到达控件上的这些方法的,本文将着重阐述这些问题,对.Net WinForm控件的键盘消息处理过程进行剖析。

1.      WinForm消息循环

  大家都知道WinForm也是依赖于底层的消息机制的,通常我们的WinForm应用程序会以如下方式启动:

  Application.Run(new Form());

  上面的代码将会在当前线程启动一个消息循环,并且显示指定窗体。

  反编译Application类的Run方法,我们可以看到这一点:

  public static void Run(Form mainForm)

  {

   ThreadContext.FromCurrent().RunMessageLoop(-1,new ApplicationContext(mainForm));

  }
 

  启动消息循环之后,操作系统就会将用户对于当前应用程序的UI输入转换为Windows消息发给当前线程进行处理。本文的重点不在于讲述Windows消息机制,而在于底层消息到达.Net这一层后,WinForm控件是如何处理的。

2. 消息处理

  从上面可以看到通过ThreadContext类型的RunMessageLoop方法,构建了消息循环。那么对于一个特定的Windows消息,ThreadContext又是如何处理的哪?

  分析ThreadContext的代码可以发现其调用关系如下:

 

  在LocalModalMessageLoop方法中我们就可以看到对于Windows消息的处理了:

  private bool LocalModalMessageLoop()

  {

   // ...

   if(!PreTranslateMessage(ref msg))

   {

   // ...

   UnsafeNativeMethods.TranslateMessage(ref msg);

   UnsafeNativeMethods.DispatchMessage(ref msg);

   }

   // ...

  }

  
可以发现对于一个特定的Windows消息,分为两个阶段进行处理:

  PreTranslateMessage
DispatchMessage
WinForm控件消息的处理将从这两个地方开始。

  2.1 PreTranslateMessage

  PreTranslateMessage提供了一个时机,来决定是否应该Dispatch这个消息,如果返回值为False,这个消息才会派发给WinForm控件。

  PreTranslateMessage分为两个层次,第一优先调用当前应用程序的IMessageFilter来进行处理,用户可以在这一层进行消息预处理或者消息过滤。如果没有被过滤掉,调用当前控件的PreProcessMessage方法进行消息预处理。

  Control类型的PreProcessMessage处理流程如下:

  

  对于WM_KeyDown消息,其预处理Control类上有三个时机:ProcessCmdKey,IsInputKey以及ProcessDialogKey;对于WM_KeyChar消息,其预处理有两个时机:IsInputChar和ProcessDialogChar。

  ProcessCmdKey默认用来处理快捷键以及菜单快捷键,此方法会递归调用父控件。如果返回值为False,继续调用IsInputKey,决定是否引发KeyDown事件。如果不是InputKey,调用ProcessDialogKey来检查该键是否为导航键,或者进行一些特别的处理,此方法会递归调用父控件的处理。

  IsInputChar决定输入字符是否为普通字符,如果返回值为True会引发KeyPress事件。返回值为False会调用ProcessDialogChar,ProcessDialogChar默认用来处理Mnemonic键,例如控件的文本为"&OK", 对于Char"O"的处理。

  2.2 DispatchMessage

  如果PreTranslateMessage没有过滤掉该Windows消息的话,该消息将会派发到控件,交由控件的WndProc函数进行处理。

  下图是控件的处理流程:

   

  消息到达WnProc之后,会交由ProcessKeyMessage,ProcessKeyPreview以及ProcessKeyEventArgs处理。每一个方法都会返回一个Boolean值,表明控件是否已经处理了该消息。

  ProcessKeyMessage会处理所有由WndProc过来的所有键消息,首先会调用父控件的ProcessKeyPreview函数,如果返回True,表明父控件已经处理。否则调用ProcessKeyEventArgs来触发控件的KeyDown,KeyPress,KeyUp事件。   

3. 结语

  本文着重讲述了WinForm控件对于键盘消息的处理,分析了消息预处理以及处理两个阶段的各个函数。在进行三方控件的开发中可以根据需要重载这些函数,另外也可从其设计以及实现思路中获得更多启发。


 



标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处,尊重他人劳动成果

文章转载自:博客转载

登录 慧都网发表评论


暂无评论...

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
在线客服 在线QQ 电话咨询
400-700-1020
反馈
在线客服系统
live chat