【问题标题】:Send Key Strokes to Games using Direct Input使用直接输入向游戏发送击键
【发布时间】:2018-06-15 22:07:59
【问题描述】:

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

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

【问题讨论】:

  • 这不是stackoverflow.com/questions/407020/about-my-macro-programs的副本吗?如果没有,您为什么要创建一个新帐户?
  • 不,它不是重复的。我还没有创建新帐户。帐户名称仍然相同。我想将密钥发送到游戏。而不是 Windows 应用程序。
  • 也许我错过了 soemthign 但不是游戏窗口应用程序吗?游戏没有消息循环,它们通过泵送用户的输入来处理吗?
  • 不要关闭它——他特别要求 DirectInput,而不是通用的 win32 程序。
  • Simulating Key Press c#的可能重复

标签: c#


【解决方案1】:

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

一旦您连接到 API,您就可以使用它做任何您想做的事情。然而,值得注意的是,在最近的 Windows 版本中,用于鼠标和键盘输入的 DirectInput 只是 Win32 Windows 消息的包装。 DirectInput 在后台生成一个线程,并在将窗口消息传递回应用程序之前简单地截取它们。这是 Microsoft 不再推荐使用 DirectInput 的原因之一 - 这意味着 PostMessage 等消息传递 API 应该 可以正常工作。

【讨论】:

  • 哇!他们改变了那个?很高兴听到。我从来没有真正喜欢过 DInput。
【解决方案2】:

一种替代方法是使用键盘驱动程序(这不是 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("{}|:\"<>?");

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

【讨论】:

    【解决方案3】:

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

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

    恐怕您无法通过托管语言做到这一点。您必须使用本机代码执行此操作,因为它需要相当多的低级黑客技术。

    【讨论】:

      【解决方案4】:

      您可以为此使用非托管的 SendInput 函数。它将输入发布在低于 DirectInput 的级别。知道要发送什么键码非常重要。这些可能因游戏而异。如果 Windows 虚拟键码对游戏不起作用,您可以尝试发送 DIKEYBOARD 常量(如 DIKEYBOARD_A 等),如果仍然不起作用,请继续尝试。例如,《半条命》或《反恐精英》期望 ASCII 码作为键码(我花了一段时间才弄清楚)

      【讨论】:

        【解决方案5】:

        为朋友游戏 (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);
                }
        

        【讨论】:

        • 这行不通。您的示例正是作者尝试过的,但以另一种方式。
        • 我认为您没有理解问题所在。你朋友的游戏对机器人没有任何防御,也没有过滤输入。作者试图自动化 DID 的游戏,在该游戏中发送这样的输入将失败,因为 Windows 会尽可能大声地喊出发送的输入是假的,而游戏可以检测到它。
        • @ParasolKirby 啊,好吧,我明白你的意思。你知道解决方案吗?我听到的类似保护是一个模拟真实键盘的自己的驱动程序。
        • @ParasolKirby Jason 的解决方案适用于防御机器人的游戏?
        • @Deniz 您实际上并不需要所有这些,您只需删除附加到输入的小标签窗口即可。我还没有弄清楚 Jason 的解决方案是否适用于过滤输入的游戏。
        猜你喜欢
        • 1970-01-01
        • 2014-05-26
        • 2019-07-24
        • 2014-05-08
        • 2020-11-11
        • 2016-09-14
        • 1970-01-01
        • 2019-03-21
        • 1970-01-01
        相关资源
        最近更新 更多