WinAPI:模拟一个完整的键按(键上下)



我正在尝试模拟给定窗口上的键向下和向上事件,我使用Spy++来比较结果。

public static void Keyboard(IntPtr windowHandle, Keys key)
{
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
var keyCode = (uint) key.GetHashCode();
var scanCode = MapVirtualKey(keyCode, 0);
var lParamDown = GetLongParam(0u, scanCode, 0u, 0u, 0u, 0u);
try
{
PostMessage(windowHandle, WM_KEYDOWN, new IntPtr(keyCode), new IntPtr(lParamDown));
Thread.Sleep(50);
var lParamUp = GetLongParam(0u, scanCode, 0u, 0u, 1u, 1u);
PostMessage(windowHandle, WM_KEYUP, new IntPtr(keyCode), new IntPtr(lParamUp));
}
catch (Exception e)
{
Console.WriteLine(e.Message); // Arithmetic overflow
}
}
private static uint GetLongParam(uint repeatCount, uint scanCode, uint extended, uint contextCode, uint previousState, uint transitionState)
{
return (transitionState << 31) | (previousState << 30) | (contextCode << 29) | (extended << 24) | (scanCode << 16) | repeatCount;
}

显然,keydown事件工作得很好,但是key up部分抛出一个算术异常。根据MSDN,这些是映射的标志:https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input#keystroke-message-flags

上面的代码有什么问题,我们如何成功地实现这一点?

注意:本文选择c#和c++作为标记,因为答案可以是它们中的任何一个。

答案如下:

private static int GetLongParam(uint repeatCount, uint scanCode, uint extended, uint contextCode, uint previousState, uint transitionState)
{
return (int) (transitionState << 31) | (previousState << 30) | (contextCode << 29) | (extended << 24) | (scanCode << 16) | repeatCount;
}

将返回值更改为int可防止算术溢出。

我还发现在unchecked语句中包装new IntPtr(lParamUp)是很好的,但到目前为止,这不是必要的,因为没有它就可以工作,例如:unchecked(new IntPtr(lParamUp))

最新更新