Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


Keystrokes on unfocused process

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking
View previous topic :: View next topic  
Author Message
Invictus01
How do I cheat?
Reputation: 0

Joined: 11 May 2023
Posts: 7

PostPosted: Sat May 20, 2023 4:59 am    Post subject: Keystrokes on unfocused process Reply with quote

Hi everyone,

First of all, I know this was probably discussed in various ways, but I'm stupid enough to need further help Sad.
First, I'm going to include the info I gathered so far for anyone looking for the same stuff in order to shorten their search hopefully, so if you're knowledgeable and want to help, you'll likely have to go through some pretty unnecessarily verbose content for you.

Basically, like the title says, I want to send keystrokes to a background process in order to create a bot for a certain MMO game.

What I did so far:
Used Spy++ in order to see what messages the game window registers when I sent keystrokes using the keyboard. That way I ended up with POST messages, along with the parameters used for every event:

Quote:
<000001> 000303E8 P WM_KEYDOWN nVirtKey:'W' cRepeat:1 ScanCode:11 fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000057 lParam:1 time:2:47:44.578 point:(462, 350)]
<000002> 000303E8 P WM_KEYUP nVirtKey:'W' cRepeat:1 ScanCode:11 fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000057 lParam:C0110001 time:2:47:44.625 point:(462, 350)]

The P in the above messages means it's a POST message, and the "user32.PostMessageA" method from user32.dll is needed in order to simulate that call towards the process.
Note that the wParam and lParam are also important, and those are not visible in the logs unless you tick the raw input parameter options in Spy++;

Further I searched on how I can execute the code from user32.dll within cheat engine, ending up with the very useful
Code:
executeCodeLocalEx
method, usable in the LUA engine/trainer scripts.

I also found out that
Code:
sendMessage
works for this case as well.

Both the above methods need a window handle in order to send the messages towards the game, so I used
Code:
local gameWindow = findWindow("WINDOW_CLASS_HERE", "WINDOW_CAPTION_HERE");

Window class and Caption can be found by using the find windows option in Spy++ or using the dissect windows tool in Cheat Engine.
Moving on, managed to send the keystrokes to the game, also seeing them registered in Spy++ using either of the following methods:
Code:
executeCodeLocalEx("user32.PostMessageA", gameWindow, 0x0100, 0x57, W_KD)
executeCodeLocalEx("user32.PostMessageA", gameWindow, 0x0101, 0x57, W_KU)

OR
Code:

sendMessage(gameWindow, 0x0100, 0x57, W_KD)
sendMessage(gameWindow, 0x0101, 0x57, W_KU)

In the above commands,
0x0100 = WM_KEYDOWN - key press
0x0101 = WM_KEYUP - key release
0x57 = virtual key code for W key, can be found on MSDN, I can't post links yet
W_KD = local W_KD = 0x00110001 - local variable storing the actual lParam specified in the Spy++ messages (raw parameters, again, needs settings adjustments to be displayed)
W_KU = same as above, only for the key release message
The lParam can be calculated but it's a rather complex process at least for me, so I preferred to go with just reverse engineering and getting the already calculated values in Spy++.

The rather simple code that took me around one week to put together (see why I'm trying to help, and WHY I need help Razz) was the following:

Code:
local gameWindow = findWindow("yourclasshere", "yourcaptionhere");
local W_KD = 0x00110001
local W_KU = 0xC0110001

executeCodeLocalEx("user32.PostMessageA", gameWindow, 0x0100, 0x57, W_KD)
sleep(2000)
executeCodeLocalEx("user32.PostMessageA", gameWindow, 0x0101, 0x57, W_KU)


This sends the W keystroke (held for two seconds, then released), and can be executed in the Lua engine within Cheat Engine.

This works totally fine if the window is in focus, but stops working if the window loses the focus.
Now what's interesting is the fact that if I send an F1 (help) stroke, that worked while the game was out of focus as well, so I'm under the impression that there's some kind of filter that attempts to stop botting software.
Also, if I try to send a different Function key that changes the camera mode, it won't work even when in focus, so it's really strange...

The idea behind making this run on windows that are not in focus is making the bot run on multiple game instances.

Any ideas to move forward with?

Thank you!
Back to top
View user's profile Send private message
LeFiXER
Grandmaster Cheater Supreme
Reputation: 20

Joined: 02 Sep 2011
Posts: 1055
Location: 0x90

PostPosted: Sat May 20, 2023 5:31 am    Post subject: Reply with quote

SendMessage works for the active window. You could look at PostMessage
Back to top
View user's profile Send private message
Invictus01
How do I cheat?
Reputation: 0

Joined: 11 May 2023
Posts: 7

PostPosted: Sat May 20, 2023 6:02 am    Post subject: Reply with quote

LeFiXER wrote:
SendMessage works for the active window. You could look at PostMessage


Both sendMessage and PostMessageA had the same result for me, like specified above.
Back to top
View user's profile Send private message
LeFiXER
Grandmaster Cheater Supreme
Reputation: 20

Joined: 02 Sep 2011
Posts: 1055
Location: 0x90

PostPosted: Sat May 20, 2023 7:51 am    Post subject: Reply with quote

Invictus01 wrote:
Both sendMessage and PostMessageA had the same result for me, like specified above.


You are using executeCodeLocalEx incorrectly:
Code:

-- Note: it's important to get the correct handle, a process can have many handles so double check you have the handle to the required control.
local hwnd = FindWindow(class_name, caption)

local function pressKey(handle, key)
        executeCodeLocalEx('USER32.PostMessageA', handle, 0x100, key, 0)
      end

-- Just a loop to press a-z
for i = 0, 26 - 1 do
    local c = string.format('0x%X', 65 + i)
    pressKey(hwnd, tonumber(c))
end
Back to top
View user's profile Send private message
Invictus01
How do I cheat?
Reputation: 0

Joined: 11 May 2023
Posts: 7

PostPosted: Sat May 20, 2023 8:06 am    Post subject: Reply with quote

LeFiXER wrote:
Invictus01 wrote:
Both sendMessage and PostMessageA had the same result for me, like specified above.


You are using executeCodeLocalEx incorrectly:
Code:

-- Note: it's important to get the correct handle, a process can have many handles so double check you have the handle to the required control.
local hwnd = FindWindow(class_name, caption)

local function pressKey(handle, key)
        executeCodeLocalEx('USER32.PostMessageA', handle, 0x100, key, 0)
      end

-- Just a loop to press a-z
for i = 0, 26 - 1 do
    local c = string.format('0x%X', 65 + i)
    pressKey(hwnd, tonumber(c))
end


Hey, thanks for the reply again,
I have tried using your loop to send messages to the same handle that works with my code. Unfortunately it does not work.
I can confirm that the messages are sent to the window as I've checked in Spy++ but nothing happens in the game, regardless if the window is focused or not, whereas it works with the focused window when using either of the statements I initially posted.
Considering that something happens in the game when I use something hardcoded for a specific key as lParam, I am assuming I can't get results using the method/loop you provided because the lParam there is always hardcoded to 0, which I've tried some days ago and no matter what I did, unless I provided the "right" lParam for the key, nothing happened in the game.

Could you explain a bit more on how I'm improperly using executeCodeLocalEx?

Thanks Smile

LE: I've also tried adding sleep(200) and a keyup event for every keydown, still no change.
Back to top
View user's profile Send private message
++METHOS
I post too much
Reputation: 92

Joined: 29 Oct 2010
Posts: 4197

PostPosted: Sat May 20, 2023 1:15 pm    Post subject: Reply with quote

Just curious, have you tried to NOP the function that removes focus from the target process (or manipulating where the flag is set)?
Back to top
View user's profile Send private message
LeFiXER
Grandmaster Cheater Supreme
Reputation: 20

Joined: 02 Sep 2011
Posts: 1055
Location: 0x90

PostPosted: Sat May 20, 2023 2:30 pm    Post subject: Reply with quote

Invictus01 wrote:

Hey, thanks for the reply again,
I have tried using your loop to send messages to the same handle that works with my code. Unfortunately it does not work.
I can confirm that the messages are sent to the window as I've checked in Spy++ but nothing happens in the game, regardless if the window is focused or not, whereas it works with the focused window when using either of the statements I initially posted.
Considering that something happens in the game when I use something hardcoded for a specific key as lParam, I am assuming I can't get results using the method/loop you provided because the lParam there is always hardcoded to 0, which I've tried some days ago and no matter what I did, unless I provided the "right" lParam for the key, nothing happened in the game.

Could you explain a bit more on how I'm improperly using executeCodeLocalEx?

Thanks Smile

LE: I've also tried adding sleep(200) and a keyup event for every keydown, still no change.


You have to pass the arguments the function expects. In the case of PostMessageA
Code:

BOOL PostMessageA(
  [in, optional] HWND   hWnd,
  [in]           UINT   Msg,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);


executeCodeLocalEx requires:
Code:

executeCodeEx(callmethod, timeout, address, {type=x, value=param1} or param1, {type=x, value=param2} or param2, ...)
callmethod: 0=stdcall, 1=cdecl
  timeout: Number of milliseconds to wait for a result. nil or -1, infitely. 0 is no wait (will not free the call memory, so beware of its memory leak)
  address: Address to execute
  {type,value} : Table containing the value type, and the value
    {
    type: 0=integer (32/64bit) can also be a pointer
          1=float (32-bit float)
          2=double (64-bit float)
          3=ascii string (will get converted to a pointer to that string)
          4=wide string (will get converted to a pointer to that string)
     
    value: anything base type that Lua can interpret
    }
  if just param is provided CE will guess the type based on the provided type


In our case, we omit the call method and the timeout, we pass the address of the function to call ('USER32.PostMessageA'), the handle, the message (in this case WM_KEYDOWN), the key as wparam, lparam is set to 0 because it's not required.

You did not call the function like this. I must stress, that the code provided works just fine, it's important that you have the exact handle to the control you want to send the message to see video: https://streamable.com/hyc3ez
Back to top
View user's profile Send private message
Invictus01
How do I cheat?
Reputation: 0

Joined: 11 May 2023
Posts: 7

PostPosted: Sun May 21, 2023 1:26 am    Post subject: Reply with quote

@LeFIXER
Quote:
You have to pass the arguments the function expects. In the case of PostMessageA

That's what I'm actually doing, unless there's something very specific about the lPARAM I'm sending you are referring to.

Code:
Your statement:
executeCodeLocalEx('USER32.PostMessageA', handle, 0x100, key, 0)
My Statement:
executeCodeLocalEx("user32.PostMessageA", handle, 0x0100, 0x57, W_KD)

Note: both 0x100/0x0100 yields the same result for me.
W_KD is a local variable, storing 0x00110001, which I'm seeing as lParam in the window message triggered when I send the W key to the game by using the keyboard.
Aside from the lParam, I'm sending the virtual code for the key instead of a variable, but that doesn't matter.
Again, when sending keystrokes to the game, there's absolutely no feedback even if the window is in focus, unless I send the lParam, so I doubt that's not required, once because I can practically see a positive feedback when I provide it and window is in focus, and twice, because It's not specified as being optional in the documentation.
Your code works well with Notepad, and so does mine, even on unfocused window, but your version with 0 as lParam doesn't trigger any feedback in the focused window on the game.
I'm pretty sure I have the right handle to the window since I get feedback on the focused window, unless there's again something very specific.

Putting that aside, I've randomly discovered that setting the WS_EX_NOACTIVATE window style actually triggers the game to accept the input even when other windows are in focus.
Definition:
Quote:
A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window.


Based on this, I set this style using WinSpy (newly found tool, Windows Detective you use seems to be trickier to set on x64), then I just click the game window. Afterwards, the input keys are accepted while another window is in focus, magically. I opened two instances of the game and got the handles for both, and while the Lua engine is in the actual focus, I can switch the handles and send input to any of the instances, which so far seems to be working fine.
Minimizing or restoring the game resets this 'acceptance' state, so you'd have to click the game window again to restore the magic.

@++METHOS
I feel that what I managed to do above has to do with what you're saying, but the other way around.
I would like to try your idea, and actually I've thought about having to alter something in order for the input filter to be bypassed, but I'm not sure where to start with that. Any hints and pointers on what to specifically look for would be useful. I'm still discovering Cheat Engine and know little about it. I can work my way around the basic stuff, setup an injection script, find pointers/etc., but not very much in the ASM direction.

Thanks!
Back to top
View user's profile Send private message
++METHOS
I post too much
Reputation: 92

Joined: 29 Oct 2010
Posts: 4197

PostPosted: Sun May 21, 2023 1:49 am    Post subject: Reply with quote

Invictus01 wrote:
Any hints and pointers on what to specifically look for would be useful.
-There are a few ways to go about it, depending on your comfort level. The most basic method would be to simply try to search for changed/unchanged value when the target process is in focus (and not in focus). There may be a single value that you can freeze, or, an instruction that you can manipulate or bypass to give you what you want.

Another way would be to use ultimap or similar to narrow in on the call that gets executed when the program goes out of focus etc. You can either jump over the call or return at the start of the call etc..

With both methods, you may be able to back-trace to see if there is a flag that gets set somewhere that handles key input. However, you may not even need to do that.
Back to top
View user's profile Send private message
LeFiXER
Grandmaster Cheater Supreme
Reputation: 20

Joined: 02 Sep 2011
Posts: 1055
Location: 0x90

PostPosted: Sun May 21, 2023 2:17 am    Post subject: Reply with quote

Invictus01 wrote:
...


It's been a long time since I used PostMessage for sending input, some 10-years, but last I recall lParam isn't required to successfully send input. Can I ask, what game is it you're wanting to send input to?
Back to top
View user's profile Send private message
Invictus01
How do I cheat?
Reputation: 0

Joined: 11 May 2023
Posts: 7

PostPosted: Sun May 21, 2023 6:01 am    Post subject: Reply with quote

LeFiXER wrote:

It's been a long time since I used PostMessage for sending input, some 10-years, but last I recall lParam isn't required to successfully send input. Can I ask, what game is it you're wanting to send input to?


From what I understand it's against the rules to specify online game names when it comes to cheating topics, so I can share the name in private, but as I'm a new user I cannot PM you unless you PM me first.
Send me a PM pls.

@METHOS, I'll try your suggestions, thanks! Smile
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General Gamehacking All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites