将快速文本输入发送到另一个进程(窗口)
我正在编写一个 C# WPF 程序,它将文本消息发送到另一个程序的窗口。我有一个宏程序作为我的键盘驱动程序(Logitech g15)的一部分,它已经做到了这一点,尽管它不会将击键直接发送到进程,而是发送到当前聚焦的窗口。它运行良好,但我也需要能够从我的程序发送输入。还有其他人使用该过程,因此来自我的程序的输入文本消息需要足够快,以便我的文本不会干扰他们的输入。 问题是,当我尝试使用 ac# 程序执行此操作时,延迟太多。宏程序(Logitech G-Series Profiler)立即发送命令。我尝试了以下三个命令来发送消息进行处理。 (按最慢到最快的顺序列出)
SetForegroundWindow(_hWnd);
SendKeys.SendWait("{Enter}This is a keystroke input.{Enter}");
它可能在名称中,但是执行命令的速度非常慢,以至于我实际上可以用眼睛跟踪文本,因为它是逐个字母输入的。我尝试使用“SendKeys.Send”方法,但收到一条错误消息:“SendKeys 无法在此应用程序内运行,因为该应用程序不处理 Windows 消息。”
PostMessage((IntPtr)_hWnd, (uint)WMessages.WM_KEYUP, (int)key, (int)key);
PostMessage 有点快,但对于我的程序来说仍然不够快。此外,该方法在进程读取消息之前返回,这意味着两个连续的 PostMessage 调用可能不会发送连续的消息。
SendMessage(_hWnd, 0x100, (int) VKeys.VK_2, (int) VKeys.VK_2);
这比 PostMessage 快,但不如 Logitech 的宏程序快。此外,接收程序对输入的处理方式很奇怪,显然没有像处理来自键盘的“真实”输入那样对待它。
SetForegroundWindow(_hWnd);
const string text = "This is a keystroke input.";
IInputElement target = Keyboard.FocusedElement;
IInputElement target = InputManager.Current.PrimaryKeyboardDevice.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice, new TextComposition(InputManager.Current, target, text)) { RoutedEvent = routedEvent });
这是我尝试过的最后一件事。文本发送到进程的方式似乎是即时的。但是,我只能将其发送到我自己的程序,因为当我将另一个程序设置为前台窗口时,Keyboard.FocusedElement 返回 null。 如果有人可以告诉我如何获取另一个窗口的 IInputElement,我肯定想知道。或者,如果有人对发送输入的更好方法有建议,我非常想听听。
规格:Windows 7,64 位 Visual Studio 2010,框架 4
I am writing a C# WPF program which sends text messages to another program's window. I have a macro program as part of my keyboard drivers (Logitech g15) which already does this, though it does not send keystrokes directly to the process, but to the currently focused window. It works well but i need to be able to send inputs from my program as well. There are other people using the process so the input text messages from my program needs to be fast enough so that my text does not interfere with their input.
The problem is that when I try to do this with a c# program I get too much delay. The macro program (Logitech G-Series Profiler) sends a command instantly. I have tried the following three commands for sending messages to process. (Listed by order of slowest to fastest)
SetForegroundWindow(_hWnd);
SendKeys.SendWait("{Enter}This is a keystroke input.{Enter}");
It is probably in the name, but this performs the command so slowly that I can actually follow with my eyes the text as it is input letter by letter. I have tried using the “SendKeys.Send” method but I get an error saying: “SendKeys cannot run inside this application because the application is not handling Windows messages.”
PostMessage((IntPtr)_hWnd, (uint)WMessages.WM_KEYUP, (int)key, (int)key);
PostMessage is a bit faster but still not fast enough for the purpose of my program. Besides the method returns before the message has been read by the process, which means two sequential PostMessage calls may not send sequential messages.
SendMessage(_hWnd, 0x100, (int) VKeys.VK_2, (int) VKeys.VK_2);
This is faster than the PostMessage but not nearly as fast as the macro program from Logitech. Also, the receiving program handles the input strangely, apparently not treating it the same way it does "genuine" input from the keyboard.
SetForegroundWindow(_hWnd);
const string text = "This is a keystroke input.";
IInputElement target = Keyboard.FocusedElement;
IInputElement target = InputManager.Current.PrimaryKeyboardDevice.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice, new TextComposition(InputManager.Current, target, text)) { RoutedEvent = routedEvent });
This is the last thing I have tried. It seems instant with the way the text is sent to a process. However, I have only been able to send this to my own program since Keyboard.FocusedElement returns null when I have another program set as foreground window.
If someone can tell me how to get an IInputElement of another window I would sure like to know. Alternatively, if someone has a suggestion for a better method of sending input, I would dearly like to hear it.
Specs: Windows 7, 64bit
Visual Studio 2010, Framework 4
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您是否有意在
SendMessage
示例中使用WM_KEYDOWN (0x0100)
而不是WM_KEYUP (0x0101)
?这只会按下按键,而不会释放它们,因此应用程序将无法正确处理它们。另一种值得尝试的方法是发送 WM_SETTEXT,假设控件正确解释它(如编辑控件或组合框)。
最后一个选项是使用 SendInput 它在非常低的级别上合成键盘和鼠标输入,但与键盘的宏程序类似,这需要您激活正确的窗口并设置焦点,这可能会非常痛苦。
First of all, are you intentionally using
WM_KEYDOWN (0x0100)
instead ofWM_KEYUP (0x0101)
in yourSendMessage
example? This would just press the keys, and never release them, so the application would not process them properly.Another way worth trying would be to send WM_SETTEXT, assuming the control interprets it correctly (like edit controls or combo boxes).
A last option would be to use SendInput which synthesizes keyboard and mouse input on a very low level, but similarly to you keyboard's macro program, this requires you to activate the correct window and set the focus, which can be quite painful.
根据其他程序窗口类型,您可以使用 UI 自动化。请参阅此处的示例:
使用 UI 自动化将内容添加到文本框
Depending on your other's program window type, you could use UI Automation. See this example here:
Add Content to a Text Box Using UI Automation