I can't use IME for Chinese input

I want to solve the Chinese input problem for monogame.

Declare the following function

[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);

Create a static class to complete all message capture tasks:

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);
        }
    }
}

It will capture and process all the messages we care about, and then pass all the messages to Game.
Although the IME window was successfully activated, the IME does not seem to receive any key messages. Add the following code:

case WM_GETDLGCODE:
    return (IntPtr)DLGC_WANTALLKEYS;  

Finally, there are several points:

  1. In addition to capturing WM_IME_END COMPOSITION to get a synthesized string with ImmGetCompositionString, capturing WM_IME_CHAR and WM_CHAR can also achieve the same effect.

  2. GetKeyboardLayout can get the message related to the current keyboard layout.

  3. ImmGetIMEFileName can get the ID of the current input method.

  4. ImmSetConversionStatus can switch half-width full-width status.

  5. Use WM_CHAR to handle normal input instead of using Keyboard in MonoGame. Because the keyboard in MonoGame was not originally designed for input characters, you can’t get the Caps Lock state at all, so even ordinary English input is very troublesome.

I hope that MonoGame developers can see this article

1 Like

For DesktopGL we should use SDL_TextEditingEvent. It’s explained here: https://wiki.libsdl.org/SDL_TextInputEvent