0

Необходимо написать метод, принимающий строку в виде любого текста, который в результате должен написать этот текст в любое поле ввода имитируя ввод с клавиатуры.

Недавно я уже задавал похожий вопрос, но там речь была о нажатии конкретных клавиш клавиатуры, коды для которых уже имеются в виде enum. Здесь же речь идет вообще о любых символах - то есть должен имитироваться ввод подобного текста: "³⁸⁽⋜" и т.п.


Что я пробовал:

System.Windows.Forms.SendKeys.SendWait("³⁸⁽⋜");

Это работает только для полей ввода в приложении, т.к. Keyboard фокусируется только на ни х. (Решение взял отсюда)

var text = "³⁸⁽⋜";
var target = Keyboard.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;

target.RaiseEvent( new TextCompositionEventArgs( InputManager.Current.PrimaryKeyboardDevice, new TextComposition(InputManager.Current, target, text)) { RoutedEvent = routedEvent } );

denisnumb
  • 5,710
  • 1
    А нельзя просто скопировать текст в буфер обмена и вставить его, где это нужно будет? (Clipboard) У меня создается впечатление, что я не совсем правильно вас понял – Frehzy May 16 '22 at 09:53
  • Так как вам нужно отправлять символы юникода, то эмуляция нажатия клавиш с клавиатуры вам не подойдет. Вы же не можете эти смайлики ввести просто нажимая кнопки на клаве, так? Самое простое решение - буфер обмена, отправляете туда текст и эмулируете нажатие Ctrl+V. – aepot May 16 '22 at 09:58
  • @Frehzy - здОрово, оригинальное решение! И никакой возни с юникодом: кто может - понимает его, а кто не может - тот как то по своему воспринимает... – S.H. May 16 '22 at 09:58
  • @S.H. это не просто нормальное, это единственное рабочее из тех что знаю, а я давно с буфером дружу. – aepot May 16 '22 at 09:59
  • @aepot мне приходило в голову это решение. Разве это будет правильно постоянно забивать буфер обмена? Просто, например в python есть библиотека keyboard, у которой есть метод write(), принимающий и пишущий любой текст. Вот, 936 строка: https://github.com/boppreh/keyboard/blob/master/keyboard/init.py – denisnumb May 16 '22 at 10:01
  • 1
    А вы проверяли, он работает со всем приложениями? Что по поводу буфера, можно его сбэкапить перед вводом туда своих данных, а после того как вставка отработает, восстановить бэкап. Задача не суперпростая, но я решил. – aepot May 16 '22 at 10:04
  • 1
    Хотя, вот решение https://stackoverflow.com/a/22308727/12888024 через SendInput. В вашем случае эту строку надо просто отправить посимвольно, с флагом KEYEVENTF_UNICODE – aepot May 16 '22 at 10:05
  • @aepot - строго говоря, можно ввести символы юникода с клавиатуры, но это "нечестный способ": через ALT. Нажимаем ALT, удерживаем его, в правой части на цифровой части клавиатуры (с включенным нумлоком) набираем что то вроде 0174 - и отпускаем альт. Но, я думаю, этот способ Вам знаком :-) – S.H. May 16 '22 at 10:07
  • @S.H. это не исмволы юникода, а альт-коды https://ru.wikipedia.org/wiki/Alt-%D0%BA%D0%BE%D0%B4 – aepot May 16 '22 at 10:08
  • @aepot - да, точно; я прочитал еще про такой способ: печатаем в Ворде (ну, я проверял в ворде) код символа цифрами, например, 2764, потом нажимаем ALT и не отпуская его - X (по русски - ALT+X). И в этот момент происходит магия: код превращается в юникод - символ! :-) – S.H. May 16 '22 at 10:13
  • Вспомнил, почему SendInput мне в свое время не подошел. Мне нужно было в визуальный редактор HTML вставлять фрагменты верстки именно как HTML, а на такое способен оказался только буфер обмена. Поэтому для просто текстовых полей таки SendInput вполне подходит. – aepot May 16 '22 at 10:26

1 Answers1

2

Можно эмулировать ввод с помощью того же SendInput, на базе структур из прошлого ответа.

public static void SendStringInput(string text)
{
    static NativeMethods.INPUT BuildINPUT(char c) => new NativeMethods.INPUT
    {
        type = NativeMethods.InputType.Keyboard,
        union = new NativeMethods.InputUnion { keyboard = new NativeMethods.KEYBDINPUT { virtualKey = 0, scanCode = (ushort)c, flags = NativeMethods.KeyboardFlags.Unicode, timeStamp = 0, extraInfo = IntPtr.Zero } }
    };
    NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[text.Length];
    for (int i = 0; i < text.Length; i++)
    {
        inputs[i] = BuildINPUT(text[i]);
    }
    _ = NativeMethods.SendInput(inputs.Length, inputs, NativeMethods.SizeOfInput);
}
aepot
  • 49,560