为什么某些应用程序有时不接受某些发送密钥

Why do some applications not accept some sendkeys at some times

这是我之前 运行 遇到的一个问题,但我总是放弃解决这个问题并想出解决办法。不是今天(希望如此)。

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

sendkeys.send("{ESC}")

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

此后我尝试了发送输入、邮寄消息和模拟输入。 None 有效(它们都具有与 sendkeys 所述相同的行为)。

如果有人能骑上一匹白马给我代码来解决这个问题就好了,但除此之外有人能简单地向我解释一下这种行为吗?

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

一个硬件扫描码似乎是按键时实际键盘发送的代码,而虚拟键码是系统从扫描码()解释的密钥。

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

通过使用我构建的以下助手 class(或更准确地说:包装器),您现在可以使用比 SendKeys.Send() 包括。您可以使用 System.Windows.Forms.Keys enumeration.

中的任意键

这已通过 Zandronum 测试并且完全有效:

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

EDIT (2019-09-20)

InputHelper has since long been moved to its own library. The answer has been updated to reflect this change.

Download InputHelper from GitHub:
https://github.com/Visual-Vincent/InputHelper/releases

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


因为我自己是 Doom 的粉丝并且熟悉它是如何工作的,也许你应该(根据你的老问题)也确保你在菜单中选择了 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.

我已经在游戏中测试了上面的代码,运行 在全屏模式下。很有魅力。