在.net cf(C#)中捕获输入法面板(InputPanel&SIP)高度改变事件

在进行Windows Mobile编程的时候,经常需要将Form上控件的Location随输入法面板的高度改变而调整,以免被面板遮盖。

    但是.Net CF的InputPanel控件只给我们提供了EnabledChanged(即输入法打开/关闭)事件,这就意味着在Enabled属性没有发生变化的情况下进行输入法切换,我们便无法及时获取新的面板高度以做出相应处理。

    有过Win32 sdk编程经验的朋友都知道,用户对应用程序产生的动作是首先以消息的形式传递给操作系统,操作系统根据消息中的窗口句柄(hWnd)回调该窗口的的消息响应函数而得到应用程序的反馈的。既然.Net CF没有对此消息进行封装,那么我们只好自己手动处理消息了。

    在Windows环境下我们可以通过重写System.Windows.Forms.Form类的WndProc()函数来实现对该窗体消息的控制。但CE环境下,System.Windows.Forms.Form类没有提供给我们此方法,我们可以利用API函数从消息队列中取出消息经过处理后再将该消息的处理权返还给系统。

    OK,有了思路就开始行动啦。首先,我们把.Net CF自带的Application扔掉,建立自己的消息循环,代码如下:
using  System;
using  System.Collections.Generic;
using  System.Runtime.InteropServices;
using  System.Windows.Forms;
using  Microsoft.WindowsCE.Forms;

///   < summary>
///  Application扩展类。
///  LastUpdate: 2007-12-25 NSnaiL
///  Merry Christmas! :)
///   < /summary>
public   class  ApplicationEx
{
    
#region  Native
    
/ //导出非托管代码 / //

    
///   < summary>
    
///  向系统表明有个线程有终止请求,通常用来响应WM_DESTROY消息。
    
///   < /summary>
    
///   < param name="nExitCode"> 退出代码,此值被用作消息WM_QUIT的wParam参数。 < /param>
    [DllImport( " coredll.dll " , SetLastError  =   true )]
    
internal   static   extern   void  PostQuitMessage( int  nExitCode);
    
///   < summary>
    
///  将虚键消息转换为字符消息;
    
///  字符消息被寄送到调用线程的消息队列里,
    
///  当下一次线程调用函数GetMessage或PeekMessage时被读出。
    
///   < /summary>
    
///   < param name="lpMsg"> 指向含有消息的MSG结构的指针。 < /param>
    
///   < returns>
    
///  如果消息被转换(即,字符消息被寄送到调用线程的消息队列里),返回非零值。
    
///  如果消息是WM_kEYDOWN,WM_KEYUP WM_SYSKEYDOWN或WM_SYSKEYUP,返回非零值,不考虑转换。
    
///  如果消息没被转换(即,字符消息没被寄送到调用线程的消息队列里),返回值是零。
    
///   < /returns>
    [DllImport( " coredll.dll " , SetLastError  =   true )]
    
internal   static   extern   bool  TranslateMessage( out  MessageExtern lpMsg);
    
///   < summary>
    
///  调度一个消息给窗口程序;
    
///  通常调度从GetMessage取得的消息。
    
///   < /summary>
    
///   < param name="lpMsg"> 指向含有消息的MSG结构的指针。 < /param>
    
///   < returns> 返回值是窗口程序返回的值。尽管返回值的含义依赖于被调度的消息,但返回值通常被忽略。 < /returns>
    [DllImport( " coredll.dll " , SetLastError  =   true )]
    
internal   static   extern   bool  DispatchMessage( ref  MessageExtern lpMsg);

    
///   < summary>
    
///  从调用线程的消息队列里取得一个消息并将其放于指定的结构。
    
///   < /summary>
    
///   < param name="lpMsg"> 指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。 < /param>
    
///   < param name="hWnd"> 取得其消息的窗口的句柄。 < /param>
    
///   < param name="wMsgFilterMin"> 指定被检索的最小消息值的整数。 < /param>
    
///   < param name="wMsgFilterMax"> 指定被检索的最大消息值的整数。 < /param>
    
///   < returns>
    
///  如果函数取得WM_QUIT之外的其他消息,返回非零值。
    
///  如果函数取得WM_QUIT消息,返回值是零。
    
///  如果出现了错误,返回-1。
    
///   < /returns>
    [DllImport( " coredll.dll " , EntryPoint  =   " GetMessageW " , SetLastError  =   true )]
    
internal   static   extern   bool  GetMessage( out  MessageExtern lpMsg, IntPtr hWnd,  uint  wMsgFilterMin,  uint  wMsgFilterMax);

    
///   < summary>
    
///  消息结构体。
    
///   < /summary>
    [StructLayout(LayoutKind.Sequential)]
    
internal   struct  MessageExtern
    {
        
public  IntPtr hwnd;  // 窗口句柄。
         public   int  message;  // 消息ID。

        
// 附加参数。
         public  IntPtr wParam;
        
public  IntPtr lParam;

        
public   int  time;  // 产生时间。

        
// 鼠标位置。
         public   int  pointX;
        
public   int  pointY;
    }

    
#endregion

    
#region  Fields

    
///   < summary> 用于接收消息。 < /summary>
     private   static  MessageExtern Msg;

    
///   < summary> 主窗体。 < /summary>
     private   static  Form FrmMain;

    
///   < summary> 指示是否返还处理权。 < /summary>
     private   static   bool  IsSysProc;

    
///   < summary> 接收消息的对象集合(实现IMessageListener接口)。 < /summary>
     private   static  List < IMessageListener >  MessageListeners;

    
///   < summary> 空的对象,用于线程锁。 < /summary>
     private   static   object  SyncObject;

    
#endregion

    
#region  Methods

    
static  ApplicationEx()
    {
        MessageListeners 
=   new  List < IMessageListener > ();
        Msg 
=   new  MessageExtern();
        SyncObject 
=   new   object ();
    }

    
///   < summary>
    
///  增加一个消息接收对象。
    
///   < /summary>
    
///   < param name="value">< /param>
     public   static   void  AddMessageListener(IMessageListener value)
    {
        MessageListeners.Add(value);
    }

    
///   < summary>
    
///  移除一个消息接收对象。
    
///   < /summary>
    
///   < param name="value">< /param>
     public   static   void  RemoveMessageListener(IMessageListener value)
    {
        MessageListeners.Remove(value);
    }

    
///   < summary>
    
///  在当前线程上开始运行标准应用程序消息循环,并使指定窗体可见。
    
///   < /summary>
    
///   < param name="frmMain"> 一个 System.Windows.Forms.Form,它代表要使之可见的窗体。 < /param>
     public   static   void  Run(Form frmMain)
    {
        ApplicationEx.FrmMain 
=  frmMain;
        ApplicationEx.FrmMain.Closed 
+=   new  EventHandler(OnFrmMainClosed);
        MessageLoop();
    }

    
///   < summary>
    
///  结束应用程序。
    
///   < /summary>
     public   static   void  Exit()
    {
        
if  (FrmMain  !=   null )
            FrmMain.Dispose();
        GC.GetTotalMemory(
true );
    }

    
///   < summary>
    
///  消息循环。
    
///   < /summary>
     private   static   void  MessageLoop()
    {
        FrmMain.Visible 
=   true ;
        
for  (; MessageHook(); )
        {
        }
        Exit();
    }

    
///   < summary>
    
///  消息获取及处理。
    
///   < /summary>
    
///   < returns>< /returns>
     private   static   bool  MessageHook()
    {
        
if  (GetMessage( out  Msg, IntPtr.Zero,  0 0 ))
        {
            IsSysProc 
=   true ;
            IMessageListener[] listeners 
=  MessageListeners.ToArray();
            
lock  (SyncObject)
            {
                
for  ( int  i  =   0 ; i  <  listeners.Length; i ++ )
                {
                    Message m 
=  Message.Create(Msg.hwnd, Msg.message, Msg.wParam, Msg.lParam);
                    IsSysProc 
=  IsSysProc  ?   ! listeners[i].WndProc( ref  m) :  false ;
                }
                
if  (IsSysProc)
                {
                    TranslateMessage(
out  Msg);
                    DispatchMessage(
ref  Msg);
                }
                
return   true ;
            }
        }
        
return   false ;
    }

    
///  主窗体关闭事件。
     private   static   void  OnFrmMainClosed( object  sender, EventArgs e)
    {
        PostQuitMessage(
0 );
    }

    
#endregion
}

    我们再定义一个接口,规定消息接收者对象必须实现消息处理函数WndProc。
using  Microsoft.WindowsCE.Forms;

///   < summary>
///  消息接收者接口。
///  LastUpdate: 2007-12-25 NSnaiL
///  Merry Christmas! :)
public   interface  IMessageListener
{
    
///   < summary>
    
///  消息处理过程。
    
///   < /summary>
    
///   < param name="m"> 消息结构体。 < /param>
    
///   < returns> 返回false以将消息处理权返回系统。 < /returns>
     bool  WndProc( ref  Message m);
}

    到此就实现了消息的捕获,我们只要在让Form实现IMessageListener接口,就可以利用WndProc函数对消息进行处理了。
    下面是一个TextBox控件随InputPanel高度调整而自动调整位置的示例:

using  System;
using  System.Windows.Forms;
using  System.Drawing;
using  System.ComponentModel;

///   < summary>
///  测试程序。
///  LastUpdate: 2007-12-25 NSnaiL
///  Merry Christmas! :)
///   < /summary>
public   class  FrmTest : Form, IMessageListener
{
    
///   < summary>
    
///  必需的设计器变量。
    
///   < /summary>
     private  System.ComponentModel.IContainer components  =   null ;
    
private  TextBox textBox1;
    
private  Microsoft.WindowsCE.Forms.InputPanel inputPanel1;
    
private  System.Windows.Forms.MainMenu mainMenu1;

    
///   < summary>
    
///  清理所有正在使用的资源。
    
///   < /summary>
    
///   < param name="disposing"> 如果应释放托管资源,为 true;否则为 false。 < /param>
     protected   override   void  Dispose( bool  disposing)
    {
        
if  (disposing  &&  (components  !=   null ))
        {
            components.Dispose();
        }
        
base .Dispose(disposing);
    }

    
#region  Windows 窗体设计器生成的代码

    
///   < summary>
    
///  设计器支持所需的方法 - 不要
    
///  使用代码编辑器修改此方法的内容。
    
///   < /summary>
     private   void  InitializeComponent()
    {
        
this .mainMenu1  =   new  System.Windows.Forms.MainMenu();
        
this .textBox1  =   new  System.Windows.Forms.TextBox();
        
this .inputPanel1  =   new  Microsoft.WindowsCE.Forms.InputPanel();
        
this .SuspendLayout();
        
//  
        
//  textBox1
        
//  
         this .textBox1.Location  =   new  System.Drawing.Point( 0 206 );
        
this .textBox1.Multiline  =   true ;
        
this .textBox1.Name  =   " textBox1 " ;
        
this .textBox1.Size  =   new  System.Drawing.Size( 240 62 );
        
this .textBox1.TabIndex  =   0 ;
        
this .textBox1.Text  =   " textBox1 " ;
        
//  
        
//  inputPanel1
        
//  
         this .inputPanel1.EnabledChanged  +=   new  System.EventHandler( this .inputPanel1_EnabledChanged);
        
//  
        
//  FrmTest
        
//  
         this .AutoScaleDimensions  =   new  System.Drawing.SizeF(96F, 96F);
        
this .AutoScaleMode  =  System.Windows.Forms.AutoScaleMode.Dpi;
        
this .AutoScroll  =   true ;
        
this .ClientSize  =   new  System.Drawing.Size( 240 268 );
        
this .Controls.Add( this .textBox1);
        
this .Menu  =   this .mainMenu1;
        
this .MinimizeBox  =   false ;
        
this .Name  =   " FrmTest " ;
        
this .Text  =   " FrmTest " ;
        
this .Closing  +=   new  System.ComponentModel.CancelEventHandler( this .FrmTest_Closing);
        
this .ResumeLayout( false );

    }

    
#endregion

    

     // 从这里开始 -------- 入口函数
     static   void  Main()
    {
        
// 使用Application扩展类替代Application类。
        ApplicationEx.Run( new  FrmTest());
    }

    
// 原始位置(以textbox1为例)
     private  Point InitLocation  =   new  Point( 0 206 );
    
// 记录面板的高度,当此值发生改变应调整textbox1的Location
     private   int  SIPHeight  =   0 ;

    
public  FrmTest()
    {
        InitializeComponent();
        
// 将此窗体加入消息接受者集合。
        ApplicationEx.AddMessageListener( this );
    }

    
#region  IMessageListener 成员

    
bool  IMessageListener.WndProc( ref  Microsoft.WindowsCE.Forms.Message m)
    {
        
if  (inputPanel1.Enabled  &&  inputPanel1.Bounds.Height  !=  SIPHeight)
        {
            textBox1.Location 
=   new  Point(InitLocation.X,
                InitLocation.Y 
-  inputPanel1.Bounds.Height);
            SIPHeight 
=  inputPanel1.Bounds.Height;
        }
        
return   false ;
    }

    
#endregion

    
private   void  FrmTest_Closing( object  sender, CancelEventArgs e)
    {
        
// 将此窗体从消息接受者集合移除。
        ApplicationEx.AddMessageListener( this );
    }

    
private   void  inputPanel1_EnabledChanged( object  sender, EventArgs e)
    {
        textBox1.Location 
=   new  Point(InitLocation.X,
            inputPanel1.Enabled 
?  InitLocation.Y  -  inputPanel1.Bounds.Height :
            InitLocation.Y);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值