thomas-crane / famebot

A bot for Realm of the Mad God designed to automate the process of collecting fame.
MIT License
19 stars 12 forks source link

Some keystrokes don't get sent to the client when the client windows is focused then loses focus. #21

Closed thomas-crane closed 7 years ago

thomas-crane commented 7 years ago

The issue can be reproduced by following these steps

  1. Start the bot
  2. Focus the client window (click on the client window)
  3. Focus any other window (click on a window which isn't the client)

When the client window loses focus, some keystrokes don't get sent to the client. E.g. in the nexus, the client can still move sideways (S and D are fine) but cannot move forwards or backwards (W and D are not being sent).

So far this has only been tested in the nexus

OFFTKP commented 7 years ago

This kind of reminds me of a problem that I had at the start of my famebot when I was trying to send keystrokes thru a timer to simply move my character around. I noticed that I could send "D" for example to move right, but if I stopped sending D and tried A right after it wouldnt work.

Turns out I needed to release "D" in order to send "A" (same for W and S) Idk if this has anything to do with your code / if you release the keystrokes but maybe when it loses focus, the release flag isnt raised for that key?

The keyup flag that I used in keybd_event was public const int KEYEVENTF_KEYUP = 0x0002

The thing is, keybd_event required window focus while SendMessage can do it in the background. But I think it would be worth trying.

What I would do was release every key at the end of each "step" in my famebot just to be safe. So I released W A S D even if they weren't pressed before, because releasing a key has no side-effects, but can solve problems.

thomas-crane commented 7 years ago

Discussion

The movement system uses SendMessage with the virtual key codes for WM_KEYUP (0x0101) and WM_KEYDOWN (0x0100).

I don't think the issue is related to releasing a key before pressing the next one. If you look at the CalculateMovement code, you can see it always releases the appropriate key before pressing the next one. E.g. if A needs to be pressed, D_PRESSED will be set to false before A_PRESSED is set to true.

I think the issue is that when the key properties (W_PRESSED, A_PRESSED, ...) are set, the code to press/release the key is only run if the new state of the key is different to its current state. E.g. if A_PRESSED is false and you try to set it to false, no SendMessage will occur.

I implemented this because I was concerned that calling SendMessage many times could have performance impacts, but now that the bot has been out for a long time and no one has reported performance issues, it's probably safe to say it's a very cheap operation. Changing the properties to always call SendMessage regardless of the key's current state may not fix the issue, but considering the almost non-existent performance impact, it's probably a good idea.

It's also very unusual that some of the keys still work correctly (S and D as mentioned before) but the fact that W in particular stops working gives a lot of insight because (when testing in the Nexus) it is the key which is pressed when the Window loses focus.

This makes me think that the cause could be that when the window loses focus, any keys which were pressed get released by Windows, but that isn't reflected in the code. E.g. Windows releases the W key, but because W_PRESSED is still true, the bot thinks it is still pressed and doesn't call SendMessage again.

Results

After some research, I am fairly confident that the way I implemented the key properties is the cause of the issue. Windows sends the WM_KILLFOCUS message to a window "immediately before it loses the keyboard focus." I am guessing that this releases any pressed keys, but because this event isn't acknowledged by the bot, it still thinks the W key is pressed and so it doesn't call SendMessage to press the key again.

Solution

Either:

I will start on a fix when I finish work, but feel free to make a pull request if you want to have a stab at fixing it 😊

(In Core/Plugin.cs, look at the code in the #region Keys for the key press properties)

thomas-crane commented 7 years ago

Fixed. See commit 944e1886dcd0cceb30703f6029b9dc77ad43371c for details.