【问题标题】:Why do some applications not accept some sendkeys at some times为什么某些应用程序有时不接受某些发送密钥
【发布时间】:2016-10-01 16:44:24
【问题描述】:

这是我以前遇到过的问题,但我总是放弃解决问题并找到解决方法。不是今天(希望如此)。

我正在尝试为经典的 Doom II 制作一个机器人。我希望我的机器人能够访问通过退出键访问的主菜单。我自然试过了:

sendkeys.send("{ESC}")

运气不好。但随后奇怪的事情发生了。当我已经在菜单上时,我不小心运行了代码......它关闭了菜单(如果您在菜单上按 Escape 是正常的)。很明显 Doom II 听的是 Sendkeys。

我已经尝试过sendinput、postmessage 和simulateinput。没有一个起作用(它们都具有与 sendkeys 描述的相同的行为)。

如果有人能骑着白马过来,给我代码来解决这个问题,那就太好了,但除此之外,任何人都可以简单地向我解释这种行为吗?

【问题讨论】:

  • 啊,Doom II...一个古老的经典...我真的很喜欢那个游戏:)。 -- 题外话,你是在运行 Doom II 的 DOS 版本还是 Windows 95 版本?因为如果您使用的是 DOS 模拟器,问题可能出在 DOS 模拟器上。
  • @visualVincent 这真的是一部经典之作,可惜我太不擅长了!我实际上正在使用 Zandronum 运行它。我一辈子都想不通为什么逃生会关闭菜单但不会打开它!
  • 那很好,因为我也用 Zandronum!如果你会说 DOS,我会更难提供帮助,因为我只有 Doom95 和 Zan。 -- 我将尝试使用SendKeysSendInput。你是在全屏模式还是窗口模式下运行?
  • @FraserOfSmeg 在游戏中,游戏可能会测试键盘状态而不是处理 Windows 消息。
  • @AndrewMorton :我相信确实如此,它在 OpenGL 或经典软件渲染器上运行(您可以自己选择渲染器)。无论哪种方式SendInput应该工作。

标签: vb.net sendkeys postmessage sendinput


【解决方案1】:

似乎 Zandronum 不接受在游戏运行(未暂停)时向其发送虚拟键。我不确定,但似乎虚拟键实际上可能是窗口消息,就像 Andrew Morton 所说的(或者它们至少是类似的东西......)。解决方法是发送hardware scan code 而不是virtual key code

硬件扫描代码看起来是实际键盘在按键时发送的代码,而虚拟键代码是系统从扫码(reference)。

所以我设法使用一些 WinAPI 函数将击键发送到 Zandronum(全屏和窗口):

通过使用我构建的以下帮助程序类(或更准确地说:包装器),您现在可以以一种简单的方式发送击键(硬件或非硬件),其键种类比SendKeys.Send() 包含的键种类更多。您可以使用System.Windows.Forms.Keys enumeration 中的任意键。

这已经用 Zandronum 进行了测试并且完全可以工作:

InputHelper.Keyboard.PressKey(Keys.Escape, True) 'True = Send key as hardware scan code.

编辑(2019-09-20)

InputHelper 早就被移到了自己的库中。答案已更新以反映这一变化。

从 GitHub 下载 InputHelper:
https://github.com/Visual-Vincent/InputHelper/releases

只是为了好玩,我还设法在MSDN上找到了一个扫描码列表:https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx


由于我自己是 Doom 的粉丝并且熟悉它的工作原理,也许您应该(根据您的老问题)还确保您在按 Enter 之前在菜单中选择了 New Game

Zandronum 知道菜单项的名称,所以你只需给它第一个字母,它就会跳转到以它开头的项目:

InputHelper.Keyboard.PressKey(Keys.Escape, True) 'Open the menu.
System.Threading.Thread.Sleep(100)      'Small delay to let the menu open.
InputHelper.Keyboard.PressKey(Keys.N, True)      'Jump to the "New Game" menu item.
InputHelper.Keyboard.PressKey(Keys.Enter, True)  'Go into the "New Game" menu.
InputHelper.Keyboard.PressKey(Keys.Enter, True)  'Start a new game.

我已经在游戏中测试了上面的代码,在全屏模式下运行。像魅力一样工作。

【讨论】:

  • 这不仅是我想要的,而且是一个非常好的和简洁的实现!谢谢!
  • 这就是我要找的东西!这是完美的!谢谢!
  • 我说:“这不完全是only...”我的意思是你给我的代码完全符合我的要求,这是一个很棒的实现!附带说明一下 - 你知道在 doom2 中获取玩家坐标的任何方法吗?
  • @FraserOfSmeg :哦哦……每次阅读评论时,我都完全错过了这一点。那么很好:)。 (我删除了我之前的两个 cmets 以保持整洁) -- 我不知道如何从另一个进程中获取玩家坐标,不。您必须读取 Zandronum 进程的内存才能获得它(这可能相当棘手,因为您还必须在内存中找到 where 坐标所在的位置)。这里稍微介绍一下:codeproject.com/Articles/716227/…
  • 谢谢。实际上,我已经从以前的游戏机器人中获得了自己的用于内存编辑的代码。我只是希望可能有一种方法可以在控制台中获取坐标(这样我就可以更容易地找到基本内存地址)。无论如何谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-03-12
  • 2023-01-27
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 2011-12-05
  • 2017-07-26
  • 1970-01-01
相关资源
最近更新 更多