C# 在DirectInput应用程序中使用SendInput API模拟键盘
我正在尝试为自定义游戏控制器应用程序模拟键盘命令。因为我需要在DirectInput环境中模拟命令,所以大多数常用方法都不起作用。我知道使用钩子将100%有效,但我正在尝试找到一个更简单的实现 我做了很多搜索,发现通过使用sendinputapi和扫描码而不是虚拟键应该可以工作,但它的行为似乎像键的“粘滞”。我已经发送了KEYDOWN和KEYUP事件,但是当我尝试在DirectInput环境中发送消息时,游戏的行为就好像按下了键一样 例如,如果我模拟一个“W”键,并在第一人称射击游戏中将该键映射到“向前移动”动作,一旦我进入游戏,下面的函数将使角色向前移动。但是,只要发出一次命令,它就会无限期地向前移动角色 下面是我正在调用的SendInput函数的代码片段(C#):C# 在DirectInput应用程序中使用SendInput API模拟键盘,c#,directinput,sendinput,C#,Directinput,Sendinput,我正在尝试为自定义游戏控制器应用程序模拟键盘命令。因为我需要在DirectInput环境中模拟命令,所以大多数常用方法都不起作用。我知道使用钩子将100%有效,但我正在尝试找到一个更简单的实现 我做了很多搜索,发现通过使用sendinputapi和扫描码而不是虚拟键应该可以工作,但它的行为似乎像键的“粘滞”。我已经发送了KEYDOWN和KEYUP事件,但是当我尝试在DirectInput环境中发送消息时,游戏的行为就好像按下了键一样 例如,如果我模拟一个“W”键,并在第一人称射击游戏中将该键映射
[DllImport("user32.dll")]
static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize);
public static void Test_KeyDown()
{
INPUT[] InputData = new INPUT[2];
Key ScanCode = Microsoft.DirectX.DirectInput.Key.W;
InputData[0].type = 1; //INPUT_KEYBOARD
InputData[0].wScan = (ushort)ScanCode;
InputData[0].dwFlags = (uint)SendInputFlags.KEYEVENTF_SCANCODE;
InputData[1].type = 1; //INPUT_KEYBOARD
InputData[1].wScan = (ushort)ScanCode;
InputData[1].dwFlags = (uint)(SendInputFlags.KEYEVENTF_KEYUP | SendInputFlags.KEYEVENTF_UNICODE);
// send keydown
if (SendInput(2, InputData, Marshal.SizeOf(InputData[1])) == 0)
{
System.Diagnostics.Debug.WriteLine("SendInput failed with code: " +
Marshal.GetLastWin32Error().ToString());
}
}
我不确定这种方法是失败的,还是我遗漏了一些愚蠢的东西。如果不必使用钩子的话,我不喜欢让代码过于复杂,但这对我来说也是一个新领域
任何人能给予的任何帮助都是非常感激的
谢谢 我找到了解决我自己问题的办法。所以,我想我会在这里发表文章来帮助任何将来可能有类似问题的人 keyup命令无法正常工作,因为在仅发送扫描代码时,必须使用扫描代码标志(有效地启用两个标志)对keyup进行OR,以告知SendInput()API这是一个keyup和扫描代码命令 例如,以下代码将正确地向上发出扫描代码密钥:
INPUT[] InputData = new INPUT[1];
InputData[0].Type = (UInt32)InputType.KEYBOARD;
//InputData[0].Vk = (ushort)DirectInputKeyScanCode; //Virtual key is ignored when sending scan code
InputData[0].Scan = (ushort)DirectInputKeyScanCode;
InputData[0].Flags = (uint)KeyboardFlag.KEYUP | (uint)KeyboardFlag.SCANCODE;
InputData[0].Time = 0;
InputData[0].ExtraInfo = IntPtr.Zero;
// Send Keyup flag "OR"ed with Scancode flag for keyup to work properly
SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT)))
感谢汉斯的回复。我做了一些调查,并将两条消息背靠背发送,就像最初的示例确实模拟了“按键”,但速度非常快。对于移动命令来说,它不会很好地工作,但当动作键被“点击”而不是按下时,它将是理想的
此外,在发送扫描代码时,虚拟密钥字段将被忽略。MSDN对此发表了以下看法:
“设置KEYEVENTF_SCANCODE标志,以根据扫描代码定义键盘输入。这对于模拟物理击键非常有用,无论当前使用的是哪个键盘。键的虚拟键值可能会根据当前键盘布局或按下的其他键而改变,但扫描代码始终相同。”
我试图用Flash模拟键盘演示,但也遇到了同样的问题。它确实适用于记事本等应用程序,但不适用于flash。经过数小时的谷歌搜索,我终于成功了:
public static void GenerateKey(int vk, bool bExtended)
{
INPUT[] inputs = new INPUT[1];
inputs[0].type = INPUT_KEYBOARD;
KEYBDINPUT kb = new KEYBDINPUT(); //{0};
// generate down
if ( bExtended )
kb.dwFlags = KEYEVENTF_EXTENDEDKEY;
kb.wVk = (ushort)vk;
inputs[0].ki = kb;
SendInput(1, inputs, System.Runtime.InteropServices.Marshal.SizeOf(inputs[0]));
// generate up
//ZeroMemory(&kb, sizeof(KEYBDINPUT));
//ZeroMemory(&inputs,sizeof(inputs));
kb.dwFlags = KEYEVENTF_KEYUP;
if ( bExtended )
kb.dwFlags |= KEYEVENTF_EXTENDEDKEY;
kb.wVk = (ushort)vk;
inputs[0].type = INPUT_KEYBOARD;
inputs[0].ki = kb;
SendInput(1, inputs, System.Runtime.InteropServices.Marshal.SizeOf(inputs[0]));
}
在你的解决方案中,你提到了一个DirectInputKeyScanCode,我无法使用它,你能帮我吗?你能发布一个完整的解决方案来按下一个键和按下一个键吗?在您发送的第一个代码段中,我不确定我做错了什么,需要替换什么。谢谢!什么是
输入[]
?那应该是来自“user32.dll”
?