zoukankan      html  css  js  c++  java
  • XNA中的中文输入(三)

          XNA中的中文输入(三)

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

     

         把前两部分的代码移植到XNA Game中,最大的问题在于无法访问底层的WinForm窗口,自然也就无法获得窗口消息。网上有一些通过window handle创建一个NativeWindow,然后重载NativeWindow WndProc的方法来获得windos消息。不幸的是把之前的代码添加在这样的构架中,不会有任何作用。顺便说一下,GameWinForm封装到内部实在是一种不太好的策略。因此,我们不得不直接调用API hook窗口消息。

             首先,声明以下函数:

    代码
    [DllImport("user32.dll",CharSet = CharSet.Unicode)]
    static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport(
    "user32.dll", CharSet = CharSet.Unicode)]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

      

             创建一个静态类来完成所有消息捕获任务:

    代码
    public static class InputCaputure
    {
        
    delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

        
    static bool initialized;
        
    static IntPtr prevWndProc;
        
    static WndProc hookProcDelegate;
        
    static IntPtr hIMC;

         
    public static void Initialize(GameWindow window)
        {
            
    if (initialized)
                
    throw new InvalidOperationException("InputCaputure.Initialize can only be called once!");

            hookProcDelegate 
    = new WndProc(HookProc);
            prevWndProc 
    = (IntPtr)SetWindowLong(window.Handle, GWL_WNDPROC, (int)Marshal.GetFunctionPointerForDelegate(hookProcDelegate));
            hIMC 
    = ImmGetContext(window.Handle);
            initialized 
    = true;
        }

        
    static IntPtr HookProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
        {
            
    switch (msg)
            {             
                
    case WindowMessage.ImeSetContext:
                    {
                        
    //add code here
                        return (IntPtr)1;
                    }

                
    case WindowMessage.ImeStartCompostition:
                    
    //add code here

                    
    return (IntPtr)0;

                
    case ............

                
    default:
                    
    return CallWindowProc(prevWndProc, hWnd, msg, wParam, lParam);
            }
        }
    }

             好了,现在把之前的代码搬到HookProc中,它将捕获并处理所有我们关心的消息,之后,再把所有消息传递给Game

             移植完所有代码之后,你会发现几个问题。首先,虽然成功激活了IME窗口,但IME似乎接收不到任何按键消息,添加以下代码:

    case WM_GETDLGCODE:
        
    return (IntPtr)DLGC_WANTALLKEYS;  

             其次,系统默认的IME窗口不会显示了。很好,这正是我们希望的效果。此外,在IME激活的状态下,一直按着键盘键盘,会导致游戏被卡住。这是hook窗口消息得到的bug吗?不是,做个试验,wow也会这样。最后,如果在全屏模式下,还会出现一些问题,这主要是看是否在正确的位置,调用了Initialize

             通过这三篇文章的,你应该已经能够为游戏编写一个最基本的中文输入系统了。最后还有一些函数是你应该留意的:

    1. 除了在捕获WM_IME_ENDCOMPOSITIONImmGetCompositionString获得合成的字符串外,捕获WM_IME_CHARWM_CHAR也能获得同样的效果。

    2. GetKeyboardLayout可以获得与当前键盘布局相关的消息。

    3. ImmGetIMEFileName可以获得当前输入法的标识名称。

    4. ImmSetConversionStatus可以切换半角全角状态。

    5. WM_CHAR处理普通输入,而不要用Xna中的Keyboard。因为XNA中的Keyboard本来就不是为输入字符设计的,你根本无法获得Caps Lock等状态,因此,即使是普通英文输入,也非常麻烦。

     

  • 相关阅读:
    测试策略(1)
    css在网页中的一些重要运用
    拖拽禁止点击事件
    js入门的心结
    响应式布局
    web中的兼容性
    css中的bfc和ifc
    css格式化的基本运用
    css基础知识
    html中输入控件的元素
  • 原文地址:https://www.cnblogs.com/clayman/p/1626819.html
Copyright © 2011-2022 走看看