Практическое руководство. Имитация событий мыши и клавиатуры в коде
Windows Forms предоставляет несколько вариантов программного моделирования ввода мыши и клавиатуры. В этом разделе представлен обзор этих вариантов.
Имитация ввода мыши
Лучший способ имитации событий мыши — вызвать метод On
EventName, который вызывает событие мыши, которое нужно имитировать. Этот параметр обычно возможен только в пользовательских элементах управления и формах, так как методы, вызывающие события, защищены и не могут быть доступны за пределами элемента управления или формы. Например, в следующих шагах показано, как имитировать нажатие правой кнопки мыши в коде.
Чтобы программно нажать правую кнопку мыши
Создайте MouseEventArgs, свойство Button которого имеет значение MouseButtons.Right.
Вызовите метод OnMouseClick с этим MouseEventArgs в качестве аргумента.
Дополнительные сведения о пользовательских элементах управления см. в разработке элементов управления Windows Forms на этапе проектирования.
Существуют другие способы имитации ввода мыши. Например, можно программно задать свойство элемента управления, представляющее состояние, которое обычно устанавливается с помощью ввода мыши (например, свойство Checked элемента управления CheckBox), или можно напрямую вызвать делегат, подключенный к событию, которое вы хотите имитировать.
Имитация ввода клавиатуры
Хотя вы можете имитировать ввод клавиатуры с помощью стратегий, описанных выше для ввода мыши, Windows Forms также предоставляет класс SendKeys для отправки нажатий клавиш в активное приложение.
Осторожность
Если приложение предназначено для международного использования с различными клавиатурами, использование SendKeys.Send может привести к непредсказуемым результатам и следует избежать.
Заметка
Класс SendKeys обновлен для .NET Framework 3.0, чтобы включить его использование в приложениях, работающих в Windows Vista. Улучшенная безопасность Windows Vista (известная как контроль учетных записей пользователей или UAC) запрещает предыдущую реализацию работать должным образом.
Класс SendKeys подвержен проблемам с временными задержками, которые некоторые разработчики вынуждены обходить. Обновленная реализация по-прежнему подвержена проблемам времени, но немного быстрее и может потребовать изменений в обходных решениях. Класс SendKeys сначала пытается использовать предыдущую реализацию, и при сбое использует новую реализацию. В результате класс SendKeys может вести себя по-разному в разных операционных системах. Кроме того, когда класс SendKeys использует новую реализацию, метод SendWait не ожидает обработки сообщений при отправке в другой процесс.
Если приложение зависит от согласованного поведения независимо от операционной системы, вы можете принудительно принудить класс SendKeys использовать новую реализацию, добавив следующий параметр приложения в файл app.config.
<appSettings>
<add key="SendKeys" value="SendInput"/>
</appSettings>
Чтобы принудительно заставить класс SendKeys использовать предыдущую реализацию, используйте значение "JournalHook"
для этого.
Отправка нажатия клавиш в то же приложение
Вызовите метод Send или SendWait класса SendKeys. Указанные нажатия клавиш будут получены активным элементом управления приложением. В следующем примере кода используется Send для имитации нажатия клавиши ВВОД, когда пользователь дважды щелкает поверхность формы. В этом примере предполагается, что Form имеет один элемент управления Button с индексом табуляции 0.
// Send a key to the button when the user double-clicks anywhere // on the form. private: void Form1_DoubleClick(Object^ sender, EventArgs^ e) { // Send the enter key to the button, which triggers the click // event for the button. This works because the tab stop of // the button is 0. SendKeys::Send("{ENTER}"); }
// Send a key to the button when the user double-clicks anywhere // on the form. private void Form1_DoubleClick(object sender, EventArgs e) { // Send the enter key to the button, which raises the click // event for the button. This works because the tab stop of // the button is 0. SendKeys.Send("{ENTER}"); }
' Send a key to the button when the user double-clicks anywhere ' on the form. Private Sub Form1_DoubleClick(ByVal sender As Object, _ ByVal e As EventArgs) Handles Me.DoubleClick ' Send the enter key to the button, which raises the click ' event for the button. This works because the tab stop of ' the button is 0. SendKeys.Send("{ENTER}") End Sub
Отправка нажатия клавиш в другое приложение
Активируйте окно приложения, которое получит нажатия клавиш, а затем вызовите метод Send или SendWait. Так как для активации другого приложения нет управляемого метода, необходимо использовать собственные методы Windows, чтобы принудительно сосредоточиться на других приложениях. В следующем примере кода используется вызов платформы для вызова методов
FindWindow
иSetForegroundWindow
для активации окна приложения калькулятора, а затем вызывается SendWait для выдачи ряда вычислений приложению Калькулятора.Заметка
Правильные параметры вызова
FindWindow
, который находит приложение калькулятора, зависят от вашей версии Windows. Следующий код находит приложение Калькулятора в Windows 7. В Windows Vista измените первый параметр на SciCalc. Для определения правильных параметров можно использовать средство Spy++, входящее в состав Visual Studio.// Get a handle to an application window. public: [DllImport("USER32.DLL", CharSet = CharSet::Unicode)] static IntPtr FindWindow(String^ lpClassName, String^ lpWindowName); public: // Activate an application window. [DllImport("USER32.DLL")] static bool SetForegroundWindow(IntPtr hWnd); // Send a series of key presses to the Calculator application. private: void button1_Click(Object^ sender, EventArgs^ e) { // Get a handle to the Calculator application. The window class // and window name were obtained using the Spy++ tool. IntPtr calculatorHandle = FindWindow("CalcFrame", "Calculator"); // Verify that Calculator is a running process. if (calculatorHandle == IntPtr::Zero) { MessageBox::Show("Calculator is not running."); return; } // Make Calculator the foreground application and send it // a set of calculations. SetForegroundWindow(calculatorHandle); SendKeys::SendWait("111"); SendKeys::SendWait("*"); SendKeys::SendWait("11"); SendKeys::SendWait("="); }
// Get a handle to an application window. [DllImport("USER32.DLL", CharSet = CharSet.Unicode)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); // Activate an application window. [DllImport("USER32.DLL")] public static extern bool SetForegroundWindow(IntPtr hWnd); // Send a series of key presses to the Calculator application. private void button1_Click(object sender, EventArgs e) { // Get a handle to the Calculator application. The window class // and window name were obtained using the Spy++ tool. IntPtr calculatorHandle = FindWindow("CalcFrame","Calculator"); // Verify that Calculator is a running process. if (calculatorHandle == IntPtr.Zero) { MessageBox.Show("Calculator is not running."); return; } // Make Calculator the foreground application and send it // a set of calculations. SetForegroundWindow(calculatorHandle); SendKeys.SendWait("111"); SendKeys.SendWait("*"); SendKeys.SendWait("11"); SendKeys.SendWait("="); }
' Get a handle to an application window. Declare Auto Function FindWindow Lib "USER32.DLL" ( _ ByVal lpClassName As String, _ ByVal lpWindowName As String) As IntPtr ' Activate an application window. Declare Auto Function SetForegroundWindow Lib "USER32.DLL" _ (ByVal hWnd As IntPtr) As Boolean ' Send a series of key presses to the Calculator application. Private Sub button1_Click(ByVal sender As Object, _ ByVal e As EventArgs) Handles button1.Click ' Get a handle to the Calculator application. The window class ' and window name were obtained using the Spy++ tool. Dim calculatorHandle As IntPtr = FindWindow("CalcFrame", "Calculator") ' Verify that Calculator is a running process. If calculatorHandle = IntPtr.Zero Then MsgBox("Calculator is not running.") Return End If ' Make Calculator the foreground application and send it ' a set of calculations. SetForegroundWindow(calculatorHandle) SendKeys.SendWait("111") SendKeys.SendWait("*") SendKeys.SendWait("11") SendKeys.SendWait("=") End Sub
Пример
Следующий пример кода — это полное приложение для предыдущих примеров кода.
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.dll>
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Drawing;
using namespace System::Windows::Forms;
namespace SimulateKeyPress
{
public ref class Form1 : public Form
{
public:
Form1()
{
Button^ button1 = gcnew Button();
button1->Location = Point(10, 10);
button1->TabIndex = 0;
button1->Text = "Click to automate Calculator";
button1->AutoSize = true;
button1->Click += gcnew EventHandler(this, &Form1::button1_Click);
this->DoubleClick += gcnew EventHandler(this,
&Form1::Form1_DoubleClick);
this->Controls->Add(button1);
}
// Get a handle to an application window.
public:
[DllImport("USER32.DLL", CharSet = CharSet::Unicode)]
static IntPtr FindWindow(String^ lpClassName, String^ lpWindowName);
public:
// Activate an application window.
[DllImport("USER32.DLL")]
static bool SetForegroundWindow(IntPtr hWnd);
// Send a series of key presses to the Calculator application.
private:
void button1_Click(Object^ sender, EventArgs^ e)
{
// Get a handle to the Calculator application. The window class
// and window name were obtained using the Spy++ tool.
IntPtr calculatorHandle = FindWindow("CalcFrame", "Calculator");
// Verify that Calculator is a running process.
if (calculatorHandle == IntPtr::Zero)
{
MessageBox::Show("Calculator is not running.");
return;
}
// Make Calculator the foreground application and send it
// a set of calculations.
SetForegroundWindow(calculatorHandle);
SendKeys::SendWait("111");
SendKeys::SendWait("*");
SendKeys::SendWait("11");
SendKeys::SendWait("=");
}
// Send a key to the button when the user double-clicks anywhere
// on the form.
private:
void Form1_DoubleClick(Object^ sender, EventArgs^ e)
{
// Send the enter key to the button, which triggers the click
// event for the button. This works because the tab stop of
// the button is 0.
SendKeys::Send("{ENTER}");
}
};
}
[STAThread]
int main()
{
Application::EnableVisualStyles();
Application::Run(gcnew SimulateKeyPress::Form1());
}
using System;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
namespace SimulateKeyPress
{
class Form1 : Form
{
private Button button1 = new Button();
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
public Form1()
{
button1.Location = new Point(10, 10);
button1.TabIndex = 0;
button1.Text = "Click to automate Calculator";
button1.AutoSize = true;
button1.Click += new EventHandler(button1_Click);
this.DoubleClick += new EventHandler(Form1_DoubleClick);
this.Controls.Add(button1);
}
// Get a handle to an application window.
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);
// Activate an application window.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
// Send a series of key presses to the Calculator application.
private void button1_Click(object sender, EventArgs e)
{
// Get a handle to the Calculator application. The window class
// and window name were obtained using the Spy++ tool.
IntPtr calculatorHandle = FindWindow("CalcFrame","Calculator");
// Verify that Calculator is a running process.
if (calculatorHandle == IntPtr.Zero)
{
MessageBox.Show("Calculator is not running.");
return;
}
// Make Calculator the foreground application and send it
// a set of calculations.
SetForegroundWindow(calculatorHandle);
SendKeys.SendWait("111");
SendKeys.SendWait("*");
SendKeys.SendWait("11");
SendKeys.SendWait("=");
}
// Send a key to the button when the user double-clicks anywhere
// on the form.
private void Form1_DoubleClick(object sender, EventArgs e)
{
// Send the enter key to the button, which raises the click
// event for the button. This works because the tab stop of
// the button is 0.
SendKeys.Send("{ENTER}");
}
}
}
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports System.Windows.Forms
Namespace SimulateKeyPress
Class Form1
Inherits Form
Private WithEvents button1 As New Button()
<STAThread()> _
Public Shared Sub Main()
Application.EnableVisualStyles()
Application.Run(New Form1())
End Sub
Public Sub New()
button1.Location = New Point(10, 10)
button1.TabIndex = 0
button1.Text = "Click to automate Calculator"
button1.AutoSize = True
Me.Controls.Add(button1)
End Sub
' Get a handle to an application window.
Declare Auto Function FindWindow Lib "USER32.DLL" ( _
ByVal lpClassName As String, _
ByVal lpWindowName As String) As IntPtr
' Activate an application window.
Declare Auto Function SetForegroundWindow Lib "USER32.DLL" _
(ByVal hWnd As IntPtr) As Boolean
' Send a series of key presses to the Calculator application.
Private Sub button1_Click(ByVal sender As Object, _
ByVal e As EventArgs) Handles button1.Click
' Get a handle to the Calculator application. The window class
' and window name were obtained using the Spy++ tool.
Dim calculatorHandle As IntPtr = FindWindow("CalcFrame", "Calculator")
' Verify that Calculator is a running process.
If calculatorHandle = IntPtr.Zero Then
MsgBox("Calculator is not running.")
Return
End If
' Make Calculator the foreground application and send it
' a set of calculations.
SetForegroundWindow(calculatorHandle)
SendKeys.SendWait("111")
SendKeys.SendWait("*")
SendKeys.SendWait("11")
SendKeys.SendWait("=")
End Sub
' Send a key to the button when the user double-clicks anywhere
' on the form.
Private Sub Form1_DoubleClick(ByVal sender As Object, _
ByVal e As EventArgs) Handles Me.DoubleClick
' Send the enter key to the button, which raises the click
' event for the button. This works because the tab stop of
' the button is 0.
SendKeys.Send("{ENTER}")
End Sub
End Class
End Namespace
Компиляция кода
Для этого примера требуется:
- Ссылки на сборки System, System.Drawing и System.Windows.Forms.
См. также
.NET Desktop feedback