I am looking for a way to simulate input of non-ASCII characters (e.g. CJK characters) using Windows APIs. keybd_event or SendInput won't work because the input characters may not be valid virtual keys.
What I want
I want to simulate input of Unicode character(s) by using Windows API, without needing to write an IME or TSF provider.
What I've tried
I've tried to send the WM_IME_CHAR message to the currently focused window:
// Gets the currently focused input control (if any) internal static IntPtr GetActiveWindowControl() { IntPtr activeWin = GetForegroundWindow(); if (activeWin == IntPtr.Zero) { return IntPtr.Zero; } uint threadId = GetWindowThreadProcessId(activeWin, IntPtr.Zero); GUITHREADINFO guiThreadInfo = new GUITHREADINFO(); guiThreadInfo.cbSize = Marshal.SizeOf(guiThreadInfo); GetGUIThreadInfo(threadId, ref guiThreadInfo); if (guiThreadInfo.hwndFocus == IntPtr.Zero) { return activeWin; // Example: console } else { return guiThreadInfo.hwndFocus; } } internal void SimulateInput() { // Encoding.Default on my computer is CP950 (Big5) byte[] b = Encoding.Default.GetBytes("我"); // one single Chinese character IntPtr activeHwnd = GetActiveWindowControl(); if (activeHwnd != IntPtr.Zero) { int ch = 0; for (int i = 0; i < b.Length; i++) // Assumed b has <=2 elements { ch = (ch << 8) | b[i]; } uint WM_IME_CHAR = 0x0286; SendMessage(activeHwnd, WM_IME_CHAR, (IntPtr)ch, (IntPtr)0) } } Problem encountered
So far this code seems to have worked quite well in most cases, however it doesn't work on Notepad++. Instead of the desired character, I got garbage input instead.
Further investigation using Spy++ shows that when using an IME to input, there isn't a WM_IME_CHAR message sent to the Notepad++ edit window. All I get are WM_IME_STARTCOMPOSITION, WM_IME_ENDCOMPOSITION, WM_IME_REQUEST, WM_IME_NOTIFY and WM_IME_SETCONTEXT. It seems that Notepad++ handles IME input different from other programs. (Also I believe there exist more programs that acts similar to Notepad++, but I just haven't found one yet.)
Also, this code will not work if the character(s) is outside the default character encoding of the target operating system (e.g. Simplified Chinese does not work with Big5).
Things that I want to prevent
- Putting the character(s) in clipboard and invoking paste on target window
Additional information
I realize that the Windows 7 Tablet PC input panel perform text insertion very nicely (even works on GTK+ applications). I tried to emulate what it sends but it only appears to repeat the last IME-entered character. It doesn't work even it appears to be exactly the same as seen in Spy++.
SendMessage(active, WM_IME_STARTCOMPOSITION, (IntPtr)0, (IntPtr)0); //SendMessage(active, WM_IME_COMPOSITION, (IntPtr)ch, (IntPtr)0x0800); SendMessage(active, WM_IME_COMPOSITION, (IntPtr)0xA7DA, (IntPtr)0x0800); SendMessage(active, WM_IME_NOTIFY, (IntPtr)0x010D, (IntPtr)0); SendMessage(active, WM_IME_ENDCOMPOSITION, (IntPtr)0, (IntPtr)0); SendMessage(active, WM_IME_NOTIFY, (IntPtr)0x010E, (IntPtr)0); I've also found a SendKeys class in .NET. Could it be used in my application?
WM_IME_CHARmessages sent to it when I type using an IME, so there is something strange happening.