如何使用SendInput模拟向上键按下(或其他扩展键)
我正在尝试以编程方式模拟按下键盘上的向上箭头键以进行端到端测试。使用以下代码,GUI 控件不会接收任何消息(WM_KEYDOWN、WM_GETDLGCODE、WM_KEYUP)。我使用 Spy++ 来检测传入的消息。你知道为什么\你能建议另一个解决方案吗?
该控件继承自UserControl 类(WinForms)。另外,没有跨线程异常,因为我使用了 Control.InvokeRequired() 和所有相关的东西。
我尝试了2次。第一个是:
[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);
}
第二次尝试:
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);
}
}
这是来自的后续问题 模拟按下键盘上的向上箭头键键盘
非常感谢您的帮助!
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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
关于 SendInput(),与您尝试做的事情相关。
SetFocus()
可能会失败,因此我们事先附加到该线程。在这里,我使用 GetCurrentThreadId()< /a> 并与 GetWindowThreadProcessId(),验证是否调用者线程和目标线程不同。
如果它们不相同,则 AttachThreadInput () 被调用。
如果目标主窗口最小化(请参阅对 IsIconic()),它被恢复,调用SetWindowPlacement() 并带到前台使用 BringWindowToTop()。
然后调用 SetFocus() 将焦点移动到目标句柄(假设它可以接收焦点,也就是说 - 该函数无论如何都应该返回成功)。
最后,您收集需要在不同的
INPUT
结构中发送的所有键(每个键修饰符在其自己的结构中),并对SendInput()
进行一次调用。例如:
将 Up 键发送到目标句柄:
发送 Control + Shift + Home:
这是这样的它有效:
标准 PictureBox 无法聚焦,因此当
时,您会看到按钮闪烁SetFocus() 被调用
用于测试的示例项目 (Google Drive)
NativeMethods :
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
INPUT
structs (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:
吉米,你很有帮助!根据你的回答,我修复了我的代码。我针对我的问题提交了另一个答案。
Jimi, you were very helpful! From you answer, I fixed my code. I submit another answer to my problem.