我正在寻找一种使用 Windows API 模拟非 ASCII 字符(例如 CJK 字符)输入的方法。keybd_event
或者因为输入的字符可能不是有效的虚拟键而SendInput
无法工作。
我想要的是
我想通过使用 Windows API 来模拟 Unicode 字符的输入,而无需编写 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++ 上不起作用。我得到了垃圾输入,而不是所需的字符。
使用 Spy++ 的进一步调查表明,当使用 IME 输入时,没有WM_IME_CHAR
消息发送到 Notepad++ 编辑窗口。我得到的只是WM_IME_STARTCOMPOSITION
, WM_IME_ENDCOMPOSITION
,WM_IME_REQUEST
和. Notepad++ 处理 IME 输入的方式似乎与其他程序不同。(另外我相信还有更多类似于 Notepad++ 的程序,但我还没有找到。)WM_IME_NOTIFY
WM_IME_SETCONTEXT
此外,如果字符超出目标操作系统的默认字符编码(例如,简体中文不适用于 Big5),则此代码将不起作用。
我想阻止的事情
- 将字符放入剪贴板并在目标窗口上调用粘贴
附加信息
我意识到 Windows 7 Tablet PC 输入面板非常好地执行文本插入(甚至适用于 GTK+ 应用程序)。我试图模仿它发送的内容,但它似乎只是重复了最后一个 IME 输入的字符。即使它看起来与在 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);
我还在SendKeys
.NET 中找到了一个类。它可以在我的应用程序中使用吗?