Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
844 views
in Technique[技术] by (71.8m points)

unicode - C# and IME - getting the current input text

I'm using the Japanese IME as an example but it is probably the same in other languages which use an IME for input.

When the user types text into a textbox using the IME, the KeyDown and KeyUp events are fired. However the TextBox.Text property does not return the typed text until the user has validated the input in the IME using the Enter key.

So for example if the user types 5 times あ then validates, I will get 5 keydown/keyup events, with each time TextBox.Text returning "" (the empty string) and at the end I will get a keydown/keyup for the enter key and the TextBox.Text will directly become "あああああ".

How can I get the user input while the user is typing, before the user validates at the end?

(I know how to do this in javascript on an <input> field on a webpage, so it must be possible in C#!)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use this to get the current composition. This will work in any composition state, and for Japanese, Chinese, and Korean. I've only tested it on Windows 7, so not sure if it'll work on other versions of Windows.

As for things being the same, well, things are actually horribly different between the three.

using System.Text;
using System;
using System.Runtime.InteropServices;

namespace Whatever {
    public class GetComposition {
        [DllImport("imm32.dll")]
        public static extern IntPtr ImmGetContext(IntPtr hWnd);
        [DllImport("Imm32.dll")]
        public static extern bool ImmReleaseContext(IntPtr hWnd, IntPtr hIMC);
        [DllImport("Imm32.dll", CharSet = CharSet.Unicode)]
        private static extern int ImmGetCompositionStringW(IntPtr hIMC, int dwIndex, byte[] lpBuf, int dwBufLen);

        private const int GCS_COMPSTR = 8;

        /// IntPtr handle is the handle to the textbox
        public string CurrentCompStr(IntPtr handle) {
            int readType = GCS_COMPSTR;

            IntPtr hIMC = ImmGetContext(handle);
            try {
                int strLen = ImmGetCompositionStringW(hIMC, readType, null, 0);

                if (strLen > 0) {
                    byte[] buffer = new byte[strLen];

                    ImmGetCompositionStringW(hIMC, readType, buffer, strLen);

                    return Encoding.Unicode.GetString(buffer);

                } else {
                    return string.Empty;
                }
            } finally {
                ImmReleaseContext(handle, hIMC);
            }
        }
    }
}

Other implementations I've seen used a StringBuilder, but it is much better to use a byte array, because the SB will usually end up with some rubbish in it as well. The byte array is encoded in UTF16.

And usually, you would want to call GetComposition whenever you receive a "WM_IME_COMPOSITION" message as Dian said.

It is very important to call ImmReleaseContext after you call ImmGetContext, which is why it is in a finally block.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...