Отправить быстрый текстовый ввод другому процессу (Окно)
Я пишу 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 возвращает ноль, когда у меня есть другая программа, установленная в качестве окна переднего плана. Если кто-то может сказать мне, как получить IInputElement другого окна, я бы хотел знать. В качестве альтернативы, если у кого-то есть предложение по лучшему методу отправки ввода, я бы очень хотел его услышать.
Спецификации: Windows 7, 64-битная Visual Studio 2010, Framework 4
2 ответа
Прежде всего, вы намеренно используете WM_KEYDOWN (0x0100)
вместо WM_KEYUP (0x0101)
в вашем SendMessage
пример? Это будет просто нажимать клавиши и никогда не отпускать их, поэтому приложение не будет обрабатывать их должным образом.
Еще один способ, который стоит попробовать, - отправить WM_SETTEXT, предполагая, что элемент управления правильно его интерпретирует (например, элементы управления редактирования или поля со списком)
Последний вариант - использовать SendInput, который синтезирует ввод с клавиатуры и мыши на очень низком уровне, но, как и в вашей макрос-программе для клавиатуры, для этого требуется активировать правильное окно и установить фокус, что может быть довольно болезненным.
В зависимости от типа окна вашей программы вы можете использовать UI Automation. Посмотрите этот пример здесь:
Добавление содержимого в текстовое поле с помощью автоматизации пользовательского интерфейса