模拟非ASCII字符的input

我正在寻找一种方法来模拟使用Windows API的非ASCII字符(例如CJK字符)的input。 keybd_eventSendInput 不起作用,因为input字符可能不是有效的虚拟键。

我想要的是

我想通过使用Windows API来模拟Unicode字符的input,而不需要编写IME或TSF提供程序。

我试过了

我试图将WM_IME_CHAR消息发送到当前聚焦的窗口:

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

遇到的问题

到目前为止,这段代码似乎在大多数情况下工作得很好, 但是它在Notepad ++上不起作用。 而不是所需的字符,我得到了垃圾input。

使用Spy ++的进一步调查显示,使用IMEinput时,没有发送到Notepad ++编辑窗口的WM_IME_CHAR消息。 我所得到的是WM_IME_STARTCOMPOSITIONWM_IME_ENDCOMPOSITIONWM_IME_REQUESTWM_IME_NOTIFYWM_IME_SETCONTEXT 。 Notepad ++似乎处理与其他程序不同的IMEinput。 (我也相信有更多的程序行为类似于Notepad ++,但我还没有find一个。)

此外,如果字符超出目标操作系统的默认字符编码(例如,简体中文不适用于Big5),此代码将不起作用。

我想防止的事情

  • 将字符放入剪贴板并在目标窗口上调用粘贴

附加信息

我意识到,Windows 7平板电脑input面板执行文本插入非常好(即使在GTK +应用程序)。 我试图模仿它发送的内容,但它似乎只是重复上一次IMEinput的字符。 即使它看起来和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); 

我还在.NET中find了一个SendKeys类。 它可以在我的应用程序中使用吗?

经过多一点搜索后,事实证明SendInput实际上可以用来发送KEYEVENTF_UNICODE Unicode输入。

现在我的代码看起来像这样( InputSender是我自己的类):

 internal static void InputString(string str) { char[] chars = str.ToCharArray(); InputSender.Input[] inputs = new InputSender.Input[chars.Length * 2]; for (int i = 0; i < chars.Length; i++) { ushort ch = (ushort)chars[i]; // Key down inputs[i * 2].type = InputSender.InputType.Keyboard; inputs[i * 2].ki.wScan = ch; inputs[i * 2].ki.dwFlags = InputSender.KeyboardEventFlags.Unicode; // Key up inputs[i * 2 + 1].type = InputSender.InputType.Keyboard; inputs[i * 2 + 1].ki.wScan = ch; inputs[i * 2 + 1].ki.dwFlags = InputSender.KeyboardEventFlags.Unicode | InputSender.KeyboardEventFlags.KeyUp; } InputSender.SendInput(inputs); } 

但事实证明,它不适用于GTK +程序 。 有点搜索表明,它应该是前一阵子,但使用旧版GTK +的程序可能仍然会遇到问题。 刚刚尝试最新的GTK +与Geany与最新的GTK +是好的,而Inkscape拒绝解释输入。

无论如何,如果我忽略了GTK +的问题,使用SendInput就足够了(应该比WM_IME_CHAR更好)。 我还没有尝试过这个解决GTK +问题的答案,因为我不知道该怎么做,并认为这是不可行的。