尝试一些WinAPI的东西。我有一个C#控制台应用,它使用SendInput
来模拟某些键盘键的keydown
和keyup
事件。虽然它不起作用,也许我正在做一些愚蠢的事情,关键是没有发送,不知道我错过了什么 - (试图发送一个“W”,睡5秒,打开一些文本编辑器看到神奇地在那里写信:)
static void Main(string[] args)
{
INPUT input = new INPUT();
input.type = (int)InputType.INPUT_KEYBOARD;
input.U.ki.wScan = 0;
input.U.ki.time = 0;
input.U.ki.dwExtraInfo = UIntPtr.Zero;
input.U.ki.wVk = VirtualKeyShort.KEY_W;
System.Threading.Thread.Sleep(5000);
input.U.ki.dwFlags = KEYEVENTF.KEYDOWN;
NativeCalls.SendInput(1, new INPUT[] { input }, INPUT.Size);
input.U.ki.dwFlags = KEYEVENTF.KEYUP;
NativeCalls.SendInput(1, new INPUT[] { input }, INPUT.Size);
return;
}
解释
public static class NativeCalls
{
[DllImport("user32.dll")]
public static extern uint SendInput(
uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize);
}
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
internal uint type;
internal InputUnion U;
internal static int Size
{
get { return Marshal.SizeOf(typeof(INPUT)); }
}
}
[StructLayout(LayoutKind.Explicit)]
internal struct InputUnion
{
[FieldOffset(0)]
internal KEYBDINPUT ki;
}
[StructLayout(LayoutKind.Sequential)]
internal struct KEYBDINPUT
{
internal VirtualKeyShort wVk;
internal ScanCodeShort wScan;
internal KEYEVENTF dwFlags;
internal int time;
internal UIntPtr dwExtraInfo;
}
[Flags]
internal enum KEYEVENTF : uint
{
KEYDOWN = 0x0000,
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
SCANCODE = 0x0008,
UNICODE = 0x0004
}
internal enum InputType { INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2 }
internal enum VirtualKeyShort : short
{
// keys
KEY_W = 0x57,
// more keys
}
我做错了什么?为什么关键不被发送?
谢谢:)
答案 0 :(得分:2)
您的工会声明不完整。因此,Marshal.SizeOf(typeof(INPUT))
返回的值不正确。您至少需要定义MOUSEINPUT
联合的INPUT
部分,因为它具有最大的大小。 pinvoke.net
声明就足够了。
我希望SendInput
在检查返回值时会告诉您问题。我希望SendInput
返回false
,然后调用GetLastError
会产生ERROR_INVALID_PARAMETER
。当然,您不应该直接致电GetLastError
。使用SetLastError = true
和Marshal.GetLastWin32Error()
。您只需在调用Win32 API函数时执行准确的错误检查。
[DllImport("user32.dll", SetLastError=true)]
...
声明的这一部分在pinvoke.net上是错误的,他们省略了SetLastError
。
您正以笨拙的方式使用SendInput
。存在SendInput
函数,以便您可以在队列中放置多个输入消息,而不会让其他消息交错。在与现已弃用的SendInput
和keybd_event
函数相关的mouse_event
讨论时,该文档明确了这一点。通过长度为2的数组后调用SendInput
。