Keyboard class + a shitty hook.

Posts 1–8 of 8 · Page 1 of 1
Keyboard class + a shitty hook.
This isn't really "CA specific" as it'll work in any application that uses the Windows Message Queue. Basically it's a way to introduce "callback-oriented" keyboard commands; a nice alternative from everyone's spammed calls to "GetAsyncKeyState". I've included my basic Hook class too so I'll add a bit of explanation about that in case someone wants to rip it out and use it somewhere.

For people that haven't ever done any Win32 Windows programming, essentially all Windows applications (GUI-subsystem, not console applications) implement a "message queue" at some level (yes even in the .NET framework, although you never really see this unless you're overriding the famous "WndProc" event). To read more about the Message Queue, check here.

The Keyboard Class
The way a window behaves depends on the messages it receives in its message queue (is the mouse down, it it in a draggable area..etc etc). A typical message loop is implemented something like this:

Code:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
    TranslateMessage(&msg);
    DispatchMessage(&msg); // dispatches the message to the window handler, typically WndProc
}
That's it! In DirectX games you may see a message loop that doesn't block so much, like the following:
Code:
// Enter the infinite message loop
while(TRUE)
{
    while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    if(msg.message == WM_QUIT)
        break;

    // Run game code here
    // ...
    // ...
}
Source: DirectXTutorial.com | Lesson 4: The Real-Time Message Loop

Either way, we see some common API calls here. Why is this relevant? Your keyboard messages also go through this message loop before being processed by the game. By hooking into one of these public API calls, you can intercept keyboard messages and do your own processing to respond to the user's input. This is what I've done.

The hook is very simple:
1) Call the real API to translate the message properly.
2) Check if the MSG we received is relevant to us (a keyboard message)
3) If yes to 2) construct the KBDLLHOOKSTRUCT and run the callbacks. If no to 2), skip this step and go to 4
4) Reset the hook and return the real value of the TranslateMessage call.

Easy peasy. There are only 3 methods you need to concern yourself with in the Keyboard class:
Code:
Keyboard::set();
Keyboard:unset();
Keyboard::add_callback();
That's it. I've written the class so you can even specify member functions as a callback (i.e class methods)

Your callback must have the following signature:
Code:
void __cdecl KeyboardProc(key_message msg, const KBDLLHOOKSTRUCT *pKeyData);
An example of using the class is demonstrated below:
Code:
#include "keyboard.h"

HANDLE	hMainThread = NULL;
BOOL	bExiting	= FALSE;

void __cdecl KeyboardCallback(key_message msg, const KBDLLHOOKSTRUCT *pKbData) {
	if (msg == KEYDOWN) {
		char szKey[2];
		sprintf(szKey, "%c", (char)pKbData->vkCode);
		MessageBoxA(NULL, szKey, "key pressed", MB_OK);
		// ZOMG DO H4X HERE
	}
}

DWORD WINAPI EntryProc(LPVOID) {
	// add the custom callback, then set the hook
	Keyboard::add_callback(&KeyboardCallback);
	Keyboard::set();

	while (!bExiting)
		Sleep(150);

	// module is being unloaded now, unset the hook to be as unintrusive as possible
	Keyboard::unset();

	return TRUE;
}

BOOL APIENTRY DllMain(HMODULE hThis, DWORD dwReason, LPVOID lpReserved) {
    // typical entry point code blah blah.
	if (dwReason == DLL_PROCESS_ATTACH) {
		hMainThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&EntryProc, NULL, 0, NULL);
	}
	else if (dwReason == DLL_PROCESS_DETACH) {
		// flag the module as closing to exit the infinite loop
		bExiting = TRUE;
		WaitForSingleObject(hMainThread, 150);
		CloseHandle(hMainThread);
	}
	return TRUE;
}
Super simple stuff.

The Hook Class
Alright to support this I needed to be able to hook into the API. I wrote a very simple Hook class to do this and it's included in the source code in the attachment. Unlike most hooks this is more OO, some people might not like this and deem it "inefficient" or whatever; I don't really give a fuck, replace my hook with your own, it's not very difficult.

Basically I've implemented 3 "types" of hook into this. You can configure a bunch of shit in the header file to change the way that the Hook is implemented at runtime.

Code:
#	define JMP_HOOK			0
#	define PUSHRET_HOOK		1
#	define MOVJMP_HOOK		2

#	define DEFAULT_HOOK		MOVJMP_HOOK
//#	define VARIABLE_HOOKS 	// comment this #define out to get a single lean and mean default hook
The first 3 defines need to remain exactly as they are. Touch them and any ensuing assfuckery is your own stupid fault.
DEFAULT_HOOK specifies, you guessed it, the default hooking method to use. If you have VARIABLE_HOOKS #defined, this value is ignored.
If you uncomment VARIABLE_HOOKS the Hook class will compile into a dynamic hooking beast, using 1 of the 3 available hooks each time the hook is reset.

I've commented the source code for all the included files so I won't spend too much time going over how it all works and how to use it. Read the code comments, then see how I've hooked the TranslateMessage API in keyboard.cc to see how to properly use the Hook class.

Hopefully someone pulls their head out of their ass and uses this, but I doubt it.

Cheers,
Jason
keyboard_class_mpgh.net.zip4 KB · 41 downloads Scanning…
What happened to CBF writing a thread

Really glad you released it, looks really nice.
Thanks, but I already knew this method
Any idea how to Block input of ca?
Quote Originally Posted by Ch40zz-C0d3r View Post
Thanks, but I already knew this method
Any idea how to Block input of ca?
You could hook DispatchMessage, filter the message coming in and then just return a garbage value without calling the real DispatchMessage. Haven't tested this but it should work.
Quote Originally Posted by Jason View Post


You could hook DispatchMessage, filter the message coming in and then just return a garbage value without calling the real DispatchMessage. Haven't tested this but it should work.
They are using DirectInput, I tried hooking it but it resultwd in only no mouse movement on the y-axe
Quote Originally Posted by Ch40zz-C0d3r View Post
They are using DirectInput, I tried hooking it but it resultwd in only no mouse movement on the y-axe
If they do use DirectInput, you'll need to hook whatever functions DirectInput use for processing the input. I don't know off the top of my head what those would be.
I would recommend event based input achieved via raw input and AttachThreadInput. Good job though
-Pyro
Posts 1–8 of 8 · Page 1 of 1
This thread is closed for replies.

Similar Threads

Tags for this Thread

None

Talk with us