Как я могу программно генерировать события нажатия клавиш в C #?

107

Как я могу программно создать событие, которое имитировало бы нажатие клавиши на клавиатуре?

Дэн Фогель
источник
6
Вам просто нужно, чтобы событие зажглось?
Дэниел А. Уайт,
Я думаю, вам придется войти в неуправляемый код, чтобы имитировать «настоящее» нажатие клавиши.
Jonas B,
Да, мне просто нужно, чтобы событие сработало.
Дэн Фогель,
1
@GONeale: Вау, комментарий трехлетней давности. Хорошо, тогда. Да, для этого есть допустимые применения, поэтому API вообще существует. Однако их немного, и они очень редки. По моему опыту, многие люди поступают так, потому что не совсем понимают лучший способ решения проблемы, например: «Я хочу вызвать код в моем обработчике событий нажатия кнопки, но не только при нажатии кнопки». Итак, для новичка кажется логичным моделировать нажатие кнопки, тогда как на самом деле им нужно взять этот код, передать его в функцию и вызвать его из другого места в коде.
Эд С.
6
@EdS: Вопрос был по существу. Я мог бы добавить много лишних деталей о создании клавиатуры и получить тот же ответ. Учитывая, что я получил именно то, что мне было нужно, мне это не кажется вопросом «плохого качества».
Дэн Фогель

Ответы:

147

Вопрос помечен как WPF, но пока ответы касаются конкретных WinForms и Win32.

Для этого в WPF просто создайте KeyEventArgs и вызовите RaiseEvent для цели. Например, чтобы отправить событие Insert key KeyDown текущему элементу с фокусом:

var key = Key.Insert;                    // Key to send
var target = Keyboard.FocusedElement;    // Target element
var routedEvent = Keyboard.KeyDownEvent; // Event to send
     target.RaiseEvent(
  new KeyEventArgs(
    Keyboard.PrimaryDevice,
    PresentationSource.FromVisual(target),
    0,
    key)
  { RoutedEvent=routedEvent }
);

Это решение не полагается на собственные вызовы или внутренние компоненты Windows и должно быть намного надежнее других. Он также позволяет имитировать нажатие клавиши на определенном элементе.

Обратите внимание, что этот код применим только к событиям PreviewKeyDown, KeyDown, PreviewKeyUp и KeyUp. Если вы хотите отправлять события TextInput, вы сделаете это вместо этого:

var text = "Hello";
var target = Keyboard.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;

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

Также обратите внимание, что:

  • Элементы управления ожидают получения событий предварительного просмотра, например PreviewKeyDown должен предшествовать KeyDown

  • Использование target.RaiseEvent (...) отправляет событие непосредственно в цель без метаобработки, такой как ускорители, композиция текста и IME. Обычно это то, что вы хотите. С другой стороны, если вы действительно делаете что-то для имитации реальных клавиш клавиатуры по какой-то причине, вы должны вместо этого использовать InputManager.ProcessInput ().

Рэй Бернс
источник
1
Я только что попробовал ваше предложение, эффекта не вижу. Я прикрепил обработчик события keyDown к элементу с фокусом. Событие, которое я поднял, получено, но KeyState - None, ScanCode - 0, а isDown - false. Я предполагаю, что получаю эти значения, потому что это фактическое состояние клавиатуры. Нажатие клавиши на реальной клавиатуре, KeyState = Down, isDown = true, а ScanCode имеет значение.
Дэн Фогель,
25
когда я попробовал первый код нажатия клавиши, я получил ошибку в "target", не могу преобразовать его в визуальный, почему?
kartal
3
Дэн, ты знаешь, как имитировать нажатие клавиши с модификатором (ctrl / alt / shift)? В частности, мне нужно смоделировать InputBinding: m_shell.InputBindings.Add (new KeyBinding (m_command, Key.Insert, ModifierKeys.Control | ModifierKeys.Alt));
Шрайк
14
О целевой проблеме, я работал его с помощью Keyboard.PrimaryDevice.ActiveSourceсм stackoverflow.com/questions/10820990/...
OscarRyz
4
Этот ответ очень хорош, но его нельзя использовать для отправки ключа с модификатором, как отметил @Shrike. (Например Ctrl+C)
ANeves
27

Для создания ключевых событий без контекста Windows Forms мы можем использовать следующий метод,

[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

пример кода приведен ниже:

const int VK_UP = 0x26; //up key
const int VK_DOWN = 0x28;  //down key
const int VK_LEFT = 0x25;
const int VK_RIGHT = 0x27;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
int press()
{
    //Press the key
    keybd_event((byte)VK_UP, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
    return 0;
}

Список виртуальных ключей определяется здесь .

Чтобы получить полную картину, воспользуйтесь приведенной ниже ссылкой http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html

Раджеш
источник
Подойдет, если ваше окно будет сверху. Это частично решило мою ситуацию, спасибо!
Сергей
В дополнение к ответу Раджеша, если вы хотите сделать это на мобильной платформе, вы должны импортировать «coredll.ddl»
user1123236
21

Я не использовал его, но SendKeys может делать то, что вы хотите.

Используйте SendKeys для отправки нажатий клавиш и комбинаций клавиш в активное приложение. Невозможно создать экземпляр этого класса. Чтобы отправить нажатие клавиши классу и немедленно продолжить выполнение программы, используйте Отправить. Чтобы дождаться каких-либо процессов, запущенных нажатием клавиши, используйте SendWait.

System.Windows.Forms.SendKeys.Send("A");
System.Windows.Forms.SendKeys.Send("{ENTER}");

Microsoft имеет еще несколько примеров использования здесь .

Майкл Петротта
источник
3
Я попытался использовать SendKeys.Send и получил это InvalidOperationException: «SendKeys не может работать внутри этого приложения, потому что приложение не обрабатывает сообщения Windows. Либо измените приложение для обработки сообщений, либо используйте метод SendKeys.SendWait». Использование SendKey.SendWait не имеет никакого эффекта.
Дэн Фогель,
Убедитесь, что вы не отправляете ключевое событие себе. Перед отправкой события переключите фокус на нужный процесс. Во второй связанной статье есть некоторая помощь по этому поводу.
Майкл Петротта,
11

Без труда! (потому что за нас уже работал кто-то другой ...)

Потратив много времени на попытки сделать это с предложенными ответами, я наткнулся на этот проект codeplex Windows Input Simulator, который упростил имитацию нажатия клавиши:

  1. Установить пакет можно либо из диспетчера пакетов NuGet, либо из консоли диспетчера пакетов, например:

    Инсталляционный пакет InputSimulator

  2. Используйте эти 2 строки кода:

    inputSimulator = new InputSimulator() inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RETURN)

И это все!

-------РЕДАКТИРОВАТЬ--------

Страница проекта на codeplex по какой-то причине помечена, это ссылка на галерею NuGet.

Равид Гольденберг
источник
Это работает очень хорошо, однако я не смог найти, как заставить это работать с помощью комбинации клавиш,
user1234433222
Когда вы говорите «комбинация клавиш», вы имеете в виду CTRL-C?
Равид Гольденберг
да, или даже если вы хотите, чтобы консольное приложение отображалось в полноэкранном режиме, например, Alt-Enter, я знаю, что вы можете использовать F11 для входа в полноэкранный режим, но было бы неплохо увидеть, будет ли работать Alt-Enter :)
user1234433222
1
Что ж, вы можете это сделать, хотя я не пробовал, просто используйте inputSimulator.Keyboard.ModifiedKeyStroke (VirtualKeyCode.CONTROL, VirtualKeyCode.VK_C);
Равид Гольденберг,