XNA中的中文输入(一)

 XNA中的中文输入(一)

仅供个人学习使用,请勿转载,勿用于任何商业用途。

 

         游戏中的中文输入一直是个很棘手的问题,就连wow也实现的不是很好,很多人不得不在窗口最大化模式下游戏。对大部分程序员来说,如果不开发输入法,永远也不需要关心IME是如果工作的,即使是游戏开发,除了中日韩等少数使用多字符语言的国家,也不需要关心IME。了解游戏IME开发的人,也因为种种原因,不愿过多讨论,因此相关资料非常之少。

     最近花了一周时间,终于实现了中文输入。本文主要讨论如何在XNA中调用IME,有些特定WinForm下的行为也许和传统DirectX程序不太一样。本文不会给出详细的实现代码和原理,但会把所有关键步骤都写出来。

       继续阅读之前,你应该先了解或准备以下资料:

1. DirectX SDKCustomeUIsample。虽然这并不是一个很适合“学习”的例子(代码太过于复杂),但毕竟是ms建议的标准实现方法,也是最兼容性最好的实现。

2.  DirectX SDK中的Using an Input Method Editor in a Game一文,以下简称“指南”。在我看来,这同样也是一篇不太好的指南,很多关键部分讲的非常模糊。

3.  Windows SDKIME相关的文档,可在MSDN—Win32 and COM—User Interface—Internationalization—SDK Document—International Text Display找到。

4. 对于XNA开发者还需要对windows消息机制(WindowProc)以及P/Invoke有所了解。

         我们要做的事情非常简单,1,在游戏程序中打开IME窗口;2,获得IME所“合成”的文字;3,隐藏IME窗口(可选)。实现的思想也很简单:拦截IME相关的windows消息,并进行处理就可以了。 

         要处理的第一个消息是WM_IME_SETCONTEXT(请先了解文档里Input Cotext的概念)SDK里说“Sent to an application when a window is activated”,按照我的理解,这句话的意思是每次窗口active之后,向窗口发送一次。但我在WinForm下的测试结果是很多IME状态改变都会触发这个消息。SDK里还说“By default, the operating system creates and assigns an input context to each thread”,这句话迷惑了我很久,从后来的实验来看,系统并没有“assigns an input context to each thread”,因为如果在接收到WM_IME_SETCONTEXT时,显式调用ImmAssociateContext,再Ctrl+shift,运气好的话,此时打字会发现IME窗口已经出现了!对,就这么简单(指南里竟然完全没有提到ImmAssociateContext这个函数,怨念啊,我苦苦google了一整个下午T_T)。为什么要说运气好呢?因为此时你见到IME窗口的可能性,基于你安装了哪种输入法!搜狗,恭喜你中奖了;紫光,你有50%的可能性看到;微软或者google拼音,基本上你什么都看不到。无论如何,总算是有了进展。让我讲的更详细一些,以便你能重现这个伟大的时刻J

1. 创建一个新的winForm程序,对我们先从winForm开始,然后再讨论XNA

2. 声明以下API

class  IMM
{
   [DllImport(
" imm32.dll " , SetLastError  =   true )]
   
public   static   extern  IntPtr ImmAssociateContext(IntPtr hWnd, IntPtr hIMC);
}

 

3. 为了方便使用API,还需要声明以下常量

ExpandedBlockStart.gif 代码
[Flags]
public   enum  CompositionStringFlag
{
    ReadingString 
=   0x0001 ,
    ReadingStringAttribute 
=   0x0002 ,
    ReadingClause 
=   0x0004 ,
    CompositionString 
=   0x0008 ,
    CompositionStringAttribute 
=   0x0010 ,
    CompositionStringClause 
=   0x0020 ,
    CursorPosition 
=   0x0080 ,
    DeltaStart 
=   0x0100 ,
    ResultReadingString 
=   0x0200 ,
    ResultReadingStringClause 
=   0x0400 ,
    ResultString 
=   0x0800 ,
    ResultClause 
=   0x1000
}

public   static   class  WindowMessage
{
    
public   const   int  Char  =   0x0102 ;
    
public   const   int  ImeStartCompostition  =   0x010D ;
    
public   const   int  ImeEndComposition  =   0x010E ;
    
public   const   int  ImeComposition  =   0x010F ;
    
public   const   int  ImeKeyLast  =   0x010F ;
    
public   const   int  ImeSetContext  =   0x0281 ;
    
public   const   int  ImeNotify  =   0x0282 ;
    
public   const   int  ImeControl  =   0x0283 ;
    
public   const   int  ImeCompositionFull  =   0x0284 ;
    
public   const   int  ImeSelect  =   0x0285 ;
    
public   const   int  ImeChar  =   0x286 ;
    
public   const   int  ImeRequest  =   0x0288 ;
    
public   const   int  ImeKeyDown  =   0x0290 ;
    
public   const   int  ImeKeyUp  =   0x0291 ;
    
public   const   int  InputLanguageChange  =   0x0051 ;
}

 

4. 为窗口添加以下函数:

 

ExpandedBlockStart.gif 代码
protected   override   void  WndProc( ref  Message m)
{
    
if  (m.Msg  ==  WindowMessage.ImeSetContext)
    {
        
if  (m.WParam.ToInt32()  ==   1 )
        {
            IntPtr imeContext 
=  IMM.ImmGetContext( this .Handle);
            IMM.ImmAssociateContext(
this .Handle, imeContext);
        }
    }
    base.WndProc(ref m);
}

         好了,编译运行。成功没有?没有!对,就算你装了先前提到的第一种输入法,此时程序也不会有任何反应。Why?设置断点,你会发现imeContext的值是0,意味着根本没有得到正确的context。再仔细Debug,你会发现在程序启动时,WM_IME_SETCONTEXT消息被触发了不止一次,第一次消息触发时,正确得到了context,但后面的几次消息,只会返回0。所以,必须在初始化时,保存对context的引用,这是与CustomeUI例子非常不同的一点,猜想也许是winForm底层机制的原因。再次运行,你应该能看到些东西了。

         现在来解决只对搜狗和紫光有效的问题(顺便说一下,之前一直觉得各种输入法之间没多大差别,这次才发现搜狗是所有输入法里最神奇的)。这是真正困扰了我一周的问题,结果却出乎意料,只需要在WndProc里添加以下代码:

 

if  (m.Msg  ==  WindowMessage.InputLanguageChange)
{
    
return // Don't pass this message to base class!!!!
}

         不出意外的话,现在你已经可以调出所有输入法了。下一次,我将讨论如何取出IME中的字符

 

 

转载于:https://www.cnblogs.com/clayman/archive/2009/12/17/1626084.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值