views:

150

answers:

4

I'm developing an interface for an add-on to a game. I can't use the game API (for several reasons including the fact that the code must be game-agnostic) and I need to get keyboard input from the user so I've decided to use a keyboard hook (WH_KEYBOARD) to process user input when certain conditions are met.
The problem is that while I can receive and process the input correctly, when my hook returns TRUE instead of CallNextHookEx the system seems to take up a lot of time (well over 800ms) before letting things go on as expected and that's not acceptable because it doesn't even allow for a fluid typing experience.
What I have to achieve is preventing the key press message to reach the WndProc, so the question is: what can I do to achieve my target without hurting the game performance so much that the result will be unacceptable?
EDIT: due to specific requirements (games using anticheats which might create problems with my code despite it's not cheating-related) subclassing the active wndproc is not an option.

+2  A: 
  1. First you need your DLL to be injected into the target process, either by hooks, or by any other way.

  2. Find the window handle of interest.

  3. Obtain the current window procedure of that window, by calling GetWindowLongPtr(wnd, GWLP_WNDPROC), and save it.

  4. Sub-class the window, by calling SetWindowLongPtr( wnd, GWLP_WNDPROC, &NewWndProc ) where NewWndProc is your DLL-implemented message procedure.

Inside NewWndProc you'll want to process keyboard messages (there're a dozen of them, type "keyboard input" in MSDN index, I can't post more then 1 link). For the rest of windows messages call the original window procedure you've saved during (3), and return the value it returned. Don't call it directly, use CallWindowProc instead.

This way is not very reliable, some antivirus and anti-bot (e.g. "warden client") software might not like it, and debugging may be challenging.

However it should work.

Soonts
Thanks for your clever suggestion but as you pointed out anticheats won't love this and while I'm not doing this for cheating purposes, I can't really afford triggering false positives. The good part of the keyboard hook is that anticheats won't flag that because many programs use that for legitimate purposes...
emaster70
Windows subclassing is also used by many programms for legitimate purposes.
Soonts
A: 

A keyboard hook should not make things that slow. There's probably something else going on that causes the 800ms delay. Is it still slow if your hook does nothing and simply returns TRUE?

Assaf Lavie
Yes, just returning TRUE is enough to cause the slowdown while returning FALSE even if I process the keyboard event causes no performance impact at all (but that's not ok for me because the keypresses I handle shouldn't be processed by the game). I've tested it on two different games with different engines and the results are the same.
emaster70
A: 

If you want to prevent from message to arrive to the WndProc then you need to subclass using SetWindowLong, this way you will be able to catch all messages and decide if to continue their route.

Shay Erlichmen
Thanks but as commented above, subclassing is not an option.
emaster70
A: 

As much as I don't like answering my own question I've found the cause of the delay. The message pump of the games I've tested my code against was implemented with a while(PeekMessage) { GetMessage... } and removing the keyboard input message somehow caused GetMessage to block for sometime. Using PostMessage and WM_NULL helped preventing GetMessage from blocking.

emaster70