Why do some applications not accept some sendkeys at some times

梦想与她 提交于 2019-11-28 06:54:01

问题


This is an issue I've ran into before, but I've always given up solving the problem and worked out a work around. Not today (hopefully).

I'm trying to make a bot for the classic Doom II. I want my bot to have access to the main menu which is accessed via the escape key. Naturally I tried:

sendkeys.send("{ESC}")

No luck. But then something weird happened. I accidently ran the code when I was already on the menu... and it closed the menu (which is normal if you press escape on the menu). So clearly Doom II listens to Sendkeys.

I've since tried sendinput, postmessage, and simulateinput. None have worked (they all have the same behaviour as described with sendkeys).

It would be great if someone could ride in on a white horse and give me code to get around this issue, but outside of that can any one simply explain this behaviour to me?


回答1:


It seems that Zandronum does not accept virtual keys to be sent to it when the game is running (not paused). I'm not sure but it seems that virtual keys might actually be window messages, like Andrew Morton said (or they're at least something similar...). The workaround to this was to send a hardware scan code instead of a virtual key code.

A hardware scan code appears to be the code sent by the actual keyboard when pressing a key, while a virtual key code is the key which the system interprets from the scan code (reference).

So I managed to send keystrokes to Zandronum (both fullscreen and windowed) using a few WinAPI functions:

  • SendInput() which is used to send the actual keyboard input.
  • MapVirtualKeyEx() which is used to convert key codes to scan codes, or vice versa.
  • GetKeyboardLayout() which is used to get the user's current keyboard layout (I, for example, have a Swedish keyboard).

By using the below helper class (or more correctly: wrapper) that I built you may now send keystrokes (hardware or not) in a simple manner, with a larger variety of keys than what SendKeys.Send() includes. You may use any key in the System.Windows.Forms.Keys enumeration.

This was tested with Zandronum and works completely:

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

Just for fun, I also managed to find a list of scan codes on the MSDN: https://msdn.microsoft.com/en-us/library/aa299374(v=vs.60).aspx


Since I'm a Doom fan myself and familiar with how it works, perhaps you should (per your old question) also make sure that you have selected New Game in the menu before you make it press enter?

Zandronum is aware of the names of the menu items, so you just have to give it the first letter and it will jump to the item starting with it:

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.

I've tested the above code in-game, running in fullscreen mode. Works like a charm.



来源:https://stackoverflow.com/questions/39809095/why-do-some-applications-not-accept-some-sendkeys-at-some-times

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!