捕获输入内容

    原本应该先给大家说明一下程序框架的,不过,现在程序框架还没有定下来,所以暂时再给大家介绍一些具体的技术。这篇随笔告诉大家怎么获得输入的内容。

    输入内容,随便Google一下的话,大概会出现以下解决方法:

    KeyPress事件的 KeyPressEventArgs 参数 的 e.KeyChar 就是输入的内容(包括直接输入和使用IME输入。)

    KeyPress这个事件没有什么问题,的确程序是需要这个事件来捕获输入内容的,但是还是有2个注意点,请大家牢记。

    第一:输入法输入 和 .Net版本问题

        如果是通过输入法来输入文字的话(中文,日本语等输入法),.Net1.x 和.Net2.0以上有一个明显的区别:

       Net1.x只触发一次KeyPress事件,Net2.0以上将触发两次KeyPress事件!!

       Net2.0以上IME输入时两次触发KeyPress事件原因:

       KeyPress事件的源头是WM_CHAR消息和WM_IME_CHAR消息。当非IME输入的时候,只引发了WM_CHAR消息,   KeyPress只触发一次。但是,当内容文字是通过IME输入的时候,在引发WM_CHAR消息的同时,还将引发WM_IME_CHAR消息。这样的话,通过IME输入文字的时候,我们将两次得到KeyPress事件。不知道Net1.x的KeyPress为什么没有这个问题,可能Net1.x的时候,KeyPress只对WM_CHAR作出反应吧。

       知道了原因的话,那对策也很容易就找到了。在WndProc里面进行预先判断。如果是由WM_IME_CHAR消息引发的KeyPress,则在KeyPress事件里什么都不做,不然的话,在KeyPress里绘制字符。(所有的输入,均有WM_CHAR消息)

    第二个问题:是不是可以绘制的字符

    KeyPress事件的 KeyPressEventArgs 参数 的 e.KeyChar ,这里并没有保证所有的字符均是可以绘制的字符,如果你按下一些特殊键和组合键的时候,也会产生e.KeyChar。由于可能涉及到不同的字符集,还不能用简单的方法过滤掉他们呢。

我的做法是在PreviewKeyDown事件里面做筛选,PreviewKeyDown事件在KeyPress事件之前发生,我是在KeyPress里面做绘制字符的操作的,如果PreviewKeyDown事件里面判断出按下的键是一些功能键和控制键,怎在KeyPress里面什么都不做。至于为什么在PreviewKeyDown里做判断,而不是在KeyDown事件里呢,原因是PreviewKeyDown能捕获一些KeyDown事件不能捕获的KeyCode!

   综上所述,在KeyPress事件里面是否绘制字符串,有两个前提条件,第一,通过WndProc截获的消息,判断是不是由于WM_IME_CHAR造成的两次触发;第二,通过PreviewKeyDown事件来判断是不是控制系的键或操作系的键引发的KeyPress事件。如果是WM_IME_CHAR触发的KeyPress或控制系的键或操作系的键引发的KeyPress,则不做绘图操作。

 

<以下代码只是节选,并非完整代码!!>

'IsDrawString如果为假的话,不将字符绘制到窗体
Private IsDrawString As Boolean
'这个内容是否从IME传递过来
Private CharFormIME As Boolean
'*************************************************************************
'*      VS2003中,从输入法输入的字符只表示一次,VS2003以后,表示两次
'*      原因据说和两个消息有关,一个是0x286,一个是0x102
'*************************************************************************
Private Sub TextBoxEx_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
    '如果不是操作系的按键,不是从IME发出的重复信息,则绘制文字
    If IsDrawString And CharFormIME = False Then
       。。。。。。。。。。。。。。 

        DrawLine(mDocument.InputPosition.Y)

      。。。。。。。。。。。。。。。
    End If
End Sub

''' <summary>
''' 捕获系统消息
''' </summary>
''' <param name="m">系统消息</param>
''' <remarks></remarks>
Protected Overrides Sub WndProc(ByRef m As Message)
    Select Case m.Msg
        '所有需要画的字符都来自语WM_CHAR,中文,日语的话,还回发生WM_IME_CHAR,造成KeyPress里2次同样的事件
        '基于这个原因,我们吧WM_IME_CHAR产生的KeyPress过滤掉
        Case WM_IME_CHAR
            CharFormIME = True
        Case WM_CHAR
            CharFormIME = False
    End Select
    MyBase.WndProc(m)
End Sub

****************************************************
关于箭头等无法在KeyDown里面捕获的键只能在PreViewKeyDown里截获了         
****************************************************
Private Sub TextBoxEx_PreviewKeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles Me.PreviewKeyDown
    '先假设不能绘制,如果没有被过滤掉的话,则能绘制
    IsDrawString = False
    '如果Shift被按下,则现在的位置做为选中内容开始位置
    Select Case e.KeyCode
        Case Keys.ShiftKey

        。。。。。。。。
        Case Keys.Enter

        。。。。。。。。

        Case Keys.Back

        。。。。。。。。

        Case Else
            IsDrawString = True
End Select

End Sub

posted @ 2009-07-11 11:57  灰毛毛  阅读(940)  评论(0编辑  收藏  举报