使用直接输入向游戏发送键击

时间:2009-01-03 21:31:02

标签: c#

我可以使用PostMessage api发送任何Windows应用程序键击。但我无法使用PostMessage将关键笔划发送到游戏窗口。

任何人都知道使用直接输入功能从C#向游戏发送密钥。

5 个答案:

答案 0 :(得分:6)

另一种方法是直接挂钩DirectInput API - Microsoft Research已经提供了一个库来执行此操作:http://research.microsoft.com/en-us/projects/detours/

一旦您加入API,您就可以随心所欲地做任何事情。但是,值得注意的是,在Windows的最新版本中,DirectInput for mouse&键盘输入只是Win32 Windows消息的包装。 DirectInput在后台生成一个线程,只是截获窗口消息,然后再将它们传递回应用程序。这是微软不再推荐使用DirectInput的原因之一 - 这意味着像PostMessage 这样的消息传递API应该正常工作。

答案 1 :(得分:4)

一种替代方法是使用键盘驱动程序(这不是SendInput())来模拟按键 - 以及事件鼠标按下,而不是挂钩到DirectX。

您可以使用Oblita's Interception keyboard driver(适用于Windows 2000 - Windows 7)和C# library Interception(包装键盘驱动程序以在C#中使用)。

有了它,你可以做很酷的事情,如:

input.MoveMouseTo(5, 5);
input.MoveMouseBy(25, 25);
input.SendLeftClick();

input.KeyDelay = 1; // See below for explanation; not necessary in non-game apps
input.SendKeys(Keys.Enter);  // Presses the ENTER key down and then up (this constitutes a key press)

// Or you can do the same thing above using these two lines of code
input.SendKeys(Keys.Enter, KeyState.Down);
Thread.Sleep(1); // For use in games, be sure to sleep the thread so the game can capture all events. A lagging game cannot process input quickly, and you so you may have to adjust this to as much as 40 millisecond delay. Outside of a game, a delay of even 0 milliseconds can work (instant key presses).
input.SendKeys(Keys.Enter, KeyState.Up);

input.SendText("hello, I am typing!");

/* All these following characters / numbers / symbols work */
input.SendText("abcdefghijklmnopqrstuvwxyz");
input.SendText("1234567890");
input.SendText("!@#$%^&*()");
input.SendText("[]\\;',./");
input.SendText("{}|:\"<>?");

因为这些按键背后的机制是键盘驱动程序,所以它几乎不受限制。

答案 2 :(得分:1)

现在可以通过DirectInput API执行此操作。

归档相同效果的唯一方法是编写自己的DirectInput COM对象,它只包装普通的DirectInput对象。之后,您可以添加代码来模拟击键。诀窍是用您的版本替换Win32 dinput.dll。然后所有游戏都会在启动时加载你的DLL。

我担心你不能用托管语言做到这一点。你必须使用本机代码执行此操作,因为它需要相当多的低级hackery。

答案 3 :(得分:0)

您可以使用非托管SendInput函数。它将输入发布在低于DirectInput的级别。了解要发送的密钥代码非常重要。这些可能因游戏而异。如果Windows虚拟键码不适用于游戏,您可以尝试发送DIKEYBOARD常量(如DIKEYBOARD_A等),如果仍然无法继续尝试。例如,半条命或反恐精英期望ASCII代码作为密钥代码(我需要一段时间来解决这个问题)

答案 4 :(得分:0)

为没有探测器的朋友游戏(Nostale)工作:

另外here 虚拟密钥代码

的有用列表
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll")]
        static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

        private void button1_Click(object sender, EventArgs e)
        {
            const int WM_SYSKEYDOWN = 0x0104;
            const int VK_SPACE = 0x20;

            IntPtr WindowToFind = FindWindow(null, "WINDOW NAME");

            PostMessage(WindowToFind, WM_SYSKEYDOWN, VK_SPACE, 0);
        }