I am trying to programmatically simulate the pressing of the UP arrow key on the keyboard for an end-to-end test. With the below code, the GUI control receives no message (WM_KEYDOWN, WM_GETDLGCODE, WM_KEYUP). I used Spy++ to detect the incoming messages. Do you know why \ can you suggest another solution?
The control inherits from the UserControl class (WinForms). Also there is no cross-thread exception because I used Control.InvokeRequired() and all the relevant stuff.
I did 2 tries. The first one is:
[System.Runtime.InteropServices.DllImport("User32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
public static int WM_KEYDOWN = 0x100;
public static int WM_KEYUP = 0x101;
public static int VK_UP = 0x26;
public void SimulateKeystrokeEventMethod()
{
Thread.Sleep(20000);
Control control = Control.FromHandle(MyGUICOntrol.Handle);
if (control.InvokeRequired)
{
System.Action safeStimulation = delegate
{
SetForegroundWindow(Handle);
const uint MK_LBUTTON = 0x0001;
Point ClickPos = new Point(330, 401); //The position on top of the objects
IntPtr lParam = (IntPtr)((401 << 16) | 330);
IntPtr result = IntPtr.Zero;
SendMessage(Handle, WM_LBUTTONDOWN, new IntPtr(MK_LBUTTON), lParam);
SendMessage(Handle, WM_LBUTTONUP, IntPtr.Zero, lParam);
for (int i = 0; i < 100; i++)
{
lParam = (IntPtr)(0);
PostMessage(Handle, WM_KEYDOWN, new IntPtr(VK_UP), lParam);
SendMessage(Handle, WM_GETDLGCODE, 0x00, 0x00);
PostMessage(Handle, WM_KEYUP, new IntPtr(VK_UP), lParam);
}
};
control.Invoke(safeStimulation);
}
The second try:
public void SimulateKeystrokeEventMethod()
{
Thread.Sleep(20000);
Control control = Control.FromHandle(MyGUICOntrol.Handle);
if (control.InvokeRequired)
{
System.Action safeStimulation = delegate
{
SetForegroundWindow(Handle);
const uint MK_LBUTTON = 0x0001;
Point ClickPos = new Point(330, 401); //The position on top of the objects
IntPtr lParam = (IntPtr)((401 << 16) | 330);
IntPtr result = IntPtr.Zero;
SendMessage(Handle, WM_LBUTTONDOWN, new IntPtr(MK_LBUTTON), lParam);
SendMessage(Handle, WM_LBUTTONUP, IntPtr.Zero, lParam);
////for (ushort tryScanCode = 0x79; tryScanCode < 0xFF; tryScanCode++)
{
ushort tryScanCode = 0x48;
Input[] inputs1 = new Input[]
{
new Input
{
type = (int) InputType.Keyboard,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = 0x48,
dwFlags = (uint) (KeyEventF.KeyDown | KeyEventF.Scancode),
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
Input[] inputs2 = new Input[]
{
new Input
{
type = (int)InputType.Keyboard,
u = new InputUnion
{
ki = new KeyboardInput
{
wVk = 0,
wScan = 0x48,
dwFlags = (uint)(KeyEventF.KeyUp | KeyEventF.Scancode),
dwExtraInfo = GetMessageExtraInfo()
}
}
}
};
SetForegroundWindow(Handle);
SendInput((uint)inputs1.Length, inputs1, Marshal.SizeOf(typeof(Input)));
SendMessage(Handle, WM_GETDLGCODE, 0x00, 0x00);
SendInput((uint)inputs2.Length, inputs2, Marshal.SizeOf(typeof(Input)));
}
};
control.Invoke(safeStimulation);
}
}
This is a follow up question from Simulate the pressing of the UP arrow key on a keyboard
Your help is much appreciated!
A few notes about SendInput(), in relation to what you tried to do.
SetFocus()may fail, so we attach to that Thread beforehand.Here, I'm using GetCurrentThreadId() and compare with GetWindowThreadProcessId(), to verify whether the caller Thread and the target Thread are different.
If they're not the same, then AttachThreadInput() is called.
If the target Main Window is minimized (see the call to IsIconic()), it's restored, calling SetWindowPlacement() and brought to the foreground using BringWindowToTop().
Then a call to SetFocus() moves the focus to the target handle (assuming it can receive focus, that is - the function should return success anyway).
In the end, you collect all the Keys you need to send in different
INPUTstructs (each Key Modifiers in its own struct) and make a single call toSendInput().For example:
Send the Up key to the target handle:
Send Control + Shift + Home:
This is how it works:
A standard PictureBox cannot be focused, so you'll see a Button flicker when
SetFocus()is calledSample Project for testing (Google Drive)
NativeMethods: