I am trying to mod an older game, more specifically I want to emulate keyboard input via Xbox controller input. I already have the gamepad input working, but the game ignores my fake input I create with PostMessage (I tried PostThreadMessage as well with worse outcome.)
So here is the core piece of my code, a detour of PeekMessage :
BOOL WINAPI MyPeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
BOOL ret = RealPeekMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax, wRemoveMsg);
if (lpMsg->message == WM_KEYDOWN)
{
cout << "Key press";
}
if (!ret)
{
if (joypadButtonDown)
{
LPARAM lparam = 0x00000001 | (LPARAM)(EnterScanCode << 16); // Scan code, repeat=1
BOOL res = PostMessage(mainHwnd, WM_KEYDOWN, VK_RETURN, lparam);
}
}
return ret;
}
Now the problem is that the game doesn't use its message loop to read keyboard input, but instead uses SetWindowsHookEx with WH_KEYBOARD on its own main window thread.
So on a real key press what happens is :
The game's main loop calls my detour which calls the real PeekMessage which calls the hook procedure. But if I send my fake message (with identical parameters) the game again calls my detour but the real PeekMessage doesn't call the hook procedure and therefore misses the input.
Some additional Info :
- I've checked that everything happens on the same thread (Main window creation, setting the hook and the main loop)
- I tried sending PostMessage directly from IDirectInputDevice8->GetDeviceState with the same result
- Invoking the hook procedure directly causes a crash (which makes sense).
I found a somewhat dirty workaround. I call the game's SetWindowsHookEx KeyboardProc callback directly and avoid the crash I mentioned in the OP by detouring CallNextHookEx to ignore my fake hook calls.
Related
I'm trying to implement the following scenario:
Requirement
Write a C++ program to capture all the keyboard inputs on Windows OS. The program should start capturing keystrokes and after about 3 seconds (the specific amount time is not very relevant, it could be 4/5/etc.), the program should stop capturing keystrokes and continue its execution.
Before I proceed with the actual implementation details, I want to clarify that I preferred tο write the requirements in a form of exercise, rather than providing a long description. I'm not trying to gather solutions for homework. (I'm actually very supportive to such questions when its done properly, but this is not the case here).
My solution
After working on different implementations the past few days, the following is the most complete one yet:
#include <iostream>
#include <chrono>
#include <windows.h>
#include <thread>
// Event, used to signal our thread to stop executing.
HANDLE ghStopEvent;
HHOOK keyboardHook;
DWORD StaticThreadStart(void *)
{
// Install low-level keyboard hook
keyboardHook = SetWindowsHookEx(
// monitor for keyboard input events about to be posted in a thread input queue.
WH_KEYBOARD_LL,
// Callback function.
[](int nCode, WPARAM wparam, LPARAM lparam) -> LRESULT {
KBDLLHOOKSTRUCT *kbs = (KBDLLHOOKSTRUCT *)lparam;
if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN)
{
// -- PRINT 2 --
// print a message every time a key is pressed.
std::cout << "key was pressed " << std::endl;
}
else if (wparam == WM_DESTROY)
{
// return from message queue???
PostQuitMessage(0);
}
// Passes the keystrokes
// hook information to the next hook procedure in the current hook chain.
// That way we do not consume the input and prevent other threads from accessing it.
return CallNextHookEx(keyboardHook, nCode, wparam, lparam);
},
// install as global hook
GetModuleHandle(NULL), 0);
MSG msg;
// While thread was not signaled to temirnate...
while (WaitForSingleObject(ghStopEvent, 1) == WAIT_TIMEOUT)
{
// Retrieve the current messaged from message queue.
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Before exit the thread, remove the installed hook.
UnhookWindowsHookEx(keyboardHook);
// -- PRINT 3 --
std::cout << "thread is about to exit" << std::endl;
return 0;
}
int main(void)
{
// Create a signal event, used to terminate the thread responsible
// for captuting keyboard inputs.
ghStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
DWORD ThreadID;
HANDLE hThreadArray[1];
// -- PRINT 1 --
std::cout << "start capturing keystrokes" << std::endl;
// Create a thread to capture keystrokes.
hThreadArray[0] = CreateThread(
NULL, // default security attributes
0, // use default stack size
StaticThreadStart, // thread function name
NULL, // argument to thread function
0, // use default creation flags
&ThreadID); // returns the thread identifier
// Stop main thread for 3 seconds.
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
// -- PRINT 4 --
std::cout << "signal thread to terminate gracefully" << std::endl;
// Stop gathering keystrokes after 3 seconds.
SetEvent(ghStopEvent);
// -- PRINT 5 --
std::cout << "from this point onwards, we should not capture any keystrokes" << std::endl;
// Waits until one or all of the specified objects are
// in the signaled state or the time-out interval elapses.
WaitForMultipleObjects(1, hThreadArray, TRUE, INFINITE);
// Closes the open objects handle.
CloseHandle(hThreadArray[0]);
CloseHandle(ghStopEvent);
// ---
// DO OTHER CALCULATIONS
// ---
// -- PRINT 6 --
std::cout << "exit main thread" << std::endl;
return 0;
}
Implementation details
The main requirement is the capturing of keystrokes for a certain amount of time. After that time, we should NOT exit the main program. What I thought would be suitable in this case, is to create a separate thread that will be responsible for the capturing procedure and using a event to signal the thread. I've used windows threads, rather than c++0x threads, to be more close to the target platform.
The main function starts by creating the event, followed by the creation of the thread responsible for capturing keystrokes. To fulfill the requirement of time, the laziest implementation I could think of was to stop the main thread for a certain amount of time and then signaling the secondary one to exit. After that we clean up the handlers and continue with any desired calculations.
In the secondary thread, we start by creating a low-level global keyboard hook. The callback is a lambda function, which is responsible for capturing the actual keystrokes. We also want to call CallNextHookEx so that we can promote the message to the next hook on the chain and do not disrupt any other program from running correctly. After the initialization of the hook, we consume any global message using the GetMessage function provided by the Windows API. This repeats until our signal is emitted to stop the thread. Before exiting the thread, we unhook the callback.
We also output certain debug messages throughout the execution of the program.
Expected behavior
Running the above code, should output similar messages like the ones bellow:
start capturing keystrokes
key was pressed
key was pressed
key was pressed
key was pressed
signal thread to terminate gracefully
thread is about to exit
from this point onwards, we should not capture any keystrokes
exit main thread
Your output might differ depending on the number of keystrokes that were captured.
Actual behavior
This is the output I'm getting:
start capturing keystrokes
key was pressed
key was pressed
key was pressed
key was pressed
signal thread to terminate gracefully
from this point onwards, we should not capture any keystrokes
key was pressed
key was pressed
key was pressed
A first glance into the output reveals that:
The unhook function was not called
The program keeps capturing keystrokes, which might indicate that something is wrong with the way I process the message queue
There is something wrong regarding the way I'm reading the messages from the message queue, but after hours of different approaches, I could not find any solution for the specific implementation. It might also be something wrong with the way I'm handling the terminate signal.
Notes
The closer I could get on finding an answer, here in SO, was this question. However the solution did not helped me as much as I wanted.
The provided implementation is a minimum reproducible example and can be compiled without the need to import any external libraries.
A proposed solution will be to implement the capturing-keystrokes functionality as a separate child process, where will be able to start and stop whenever we like. However, I'm more interested in finding a solution using threads. I'm not sure if this is even possible (it might be).
The above code does not contain any error handling. This was on purpose to prevent possible over bloated of the code.
For any questions you might have, feel free to comment! Thank you in advance for your time to read this question and possibly post an answer (it will be amazing!).
I think this is your problem:
while (WaitForSingleObject(ghStopEvent, 1) == WAIT_TIMEOUT)
{
// Retrieve the current messaged from message queue.
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
The reason is that currently your loop can get stuck on the GetMessage() step forever and never again look at the manual-reset event.
The fix is simply to replace the combination of WaitForSingleObject + GetMessage with MsgWaitForMultipleObjects + PeekMessage.
The reason you've made this mistake is that you didn't know GetMessage only returns posted messages to the message loop. If it finds a sent message, it calls the handler from inside GetMessage, and continues looking for posted message. Since you haven't created any windows that can receive messages, and you aren't calling PostThreadMessage1, GetMessage never returns.
while (MsgWaitForMultipleObjects(1, &ghStopEvent, FALSE, INFINITE, QS_ALLINPUT) > WAIT_OBJECT_0) {
// check if there's a posted message
// sent messages will be processed internally by PeekMessage and return false
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
1 You've got logic to post WM_QUIT but it is conditioned on receiving WM_DESTROY in a low-level keyboard hook, and WM_DESTROY is not a keyboard message. Some hook types could see a WM_DESTROY but WH_KEYBOARD_LL can't.
What I thought would be suitable in this case, is to create a separate
thread that will be responsible for the capturing procedure
it's not necessary to do this if another thread will just wait for this thread and nothing to do all this time
you can use code like this.
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if (HC_ACTION == code)
{
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
DbgPrint("%x %x %x %x\n", wParam, p->scanCode, p->vkCode, p->flags);
}
return CallNextHookEx(0, code, wParam, lParam);
}
void DoCapture(DWORD dwMilliseconds)
{
if (HHOOK hhk = SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0))
{
ULONG time, endTime = GetTickCount() + dwMilliseconds;
while ((time = GetTickCount()) < endTime)
{
MSG msg;
switch (MsgWaitForMultipleObjectsEx(0, 0, endTime - time, QS_ALLINPUT, MWMO_INPUTAVAILABLE))
{
case WAIT_OBJECT_0:
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
break;
case WAIT_FAILED:
__debugbreak();
goto __0;
break;
case WAIT_TIMEOUT:
DbgPrint("WAIT_TIMEOUT\n");
goto __0;
break;
}
}
__0:
UnhookWindowsHookEx(hhk);
}
}
also in real code - usual not need write separate DoCapture with separate message loop. if your program before and after this anyway run message loop - posiible all this do in common message loop,
I want to detect keypress in C++ and i need to use Windows System Call. So, i did some research and this is what i got using Hooks and Message:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <ctime>
using namespace std;
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wParam, LPARAM lParam) {
if (code == HC_ACTION) {
switch (wParam) {
case WM_KEYDOWN:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
char c = char(MapVirtualKey(p->vkCode, MAPVK_VK_TO_CHAR));
cout << c << endl;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
int main() {
HHOOK HKeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
MSG msg;
BOOL bRet;
while ((bRet = GetMessage(&msg, NULL, 0, 0)) > 0) {
cout << "bRet = " << bRet << endl; // I want to do something here, but the program doesn't seem to go in here
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(HKeyboard);
return 0;
}
My question is why my program doesn't go inside the loop(and instead stuck on GetMessage function)? I need it to set conditions to terminate after some seconds, so where should i put the conditions? I know the GetMessage function reads Message, but when i press keys on my keyboard it still not going in and the callback function works just fine.
The events are posted to the active window. Console windows are owned by the console subsystem, csrss.exe, and it receives the events, then translates them to characters and puts them in the console object which is your application's stdin.
If you want to process events the Win32 GUI way, you should use a Win32 window (e.g. RegisterClass and CreateWindow), not a console window.
If you just want the callbacks to work for a certain period of time, you can use an alertable wait such as SleepEx or MsgWaitForMultipleObjects, which accept a timeout.
That's not surprising, there aren't really any messages on your thread queue and you have no window so there's no window queue either.
If you want to play with values returned from your hook, put the code in the hook callback function.
I should warn you that hooks like these won't work in console applications since the console window resides in another process. Also, if you look at the MSDN page for SetWindowsHookEx, you'll see that WH_KEYBOARD_LL is a global hook only, ie you have to put your hook handler in a DLL library and inject the hook in the other applications. Then you have to handle the 32/64 bit issue yourself.
And as a last note, when you say cout << c; in your handler, that would be printing in the process's output file handle, not your own.
sorry, my english skill is very low.
i make a ATL(C++) dll. and handled by VB.
i make under base code.
WaitAndReadData, Thread_WaitAndReadData is working.
but, ::SendMessage, ::PostMessage is not working in Thread_WaitAndReadData or WaitAndReadData.
and breakpoint not working in Get_Data_Messagehandler.
(+ another function call.)
#define WM_SERVERTHREADFIREEVENT (WM_USER+2)
BEGIN_MSG_MAP(CHello)
CHAIN_MSG_MAP(CComControl<CHello>)
MESSAGE_HANDLER(WM_SERVERTHREADFIREEVENT, GetData_Messagehandler)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
-
static DWORD WINAPI Thread_WaitAndReadData(LPVOID pParam)
-
STDMETHODIMP CHello::WaitAndReadData(BSTR* ret_Result)
{
// TODO: Add your implementation code here
DWORD dwThreadID;
thread = CreateThread(NULL, 0, Thread_WaitAndReadData, (LPVOID)this, 0, &dwThreadID);
return S_OK;
}
-
DWORD WINAPI CHello::Thread_WaitAndReadData(LPVOID pParam)
{
CHello* hello = (CHello*)pParam;
::SendMessage(hello->m_hWnd, WM_SERVERTHREADFIREEVENT, (WPARAM)NULL, (LPARAM)NULL);
return S_OK;
}
-
LRESULT CHello::GetData_Messagehandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
MessageBox(L"GetData_Messagehandler", L"asd", MB_OK);
return 0;
}
Even though MSDN states that there is no marshaling of WM_USER + x messages in cross-process sending, if my memory serves me right you might have troubles with cross-thread sending as well. In this case use RegisterWindowMessage API to obtain "sendable" WM_xxx identifier rather than harcoding it using a #define
Don't use bare CreateThread, use AtlCreateThread instead (or, _beginthreadex). See why.
Another reason to not receive messages on window thread is thread deadlock or window creation on thread that does not have a message pump later on, in both cases a message might be sent but there is no dispatching it to window. You can also use Spy++ tool (spyxx.exe in Visual Studio Comment\Tools directory) to make sure that the message in question is indeed being sent to the window.
I think i am ruining in to a deadlock, have been searching for the solution over hours. Any suggestions?
What i am trying to do is: ater startGame button click, create thread that send request to the server and then gets the answer, after the answer the thread must send a message to Initialize game window to the main proc...
Message Proc that belongs to WinMain:
LRESULT CALLBACK WndProc(HWND myWindow, UINT messg, WPARAM wParam, LPARAM lParam)
{
switch (messg) {
case WM_STARTGAME:
DestroyWindow(hStartGameButton);
DestroyWindow(hHistoryButton);
InitGameWindow(myWindow);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_STARTGAME_BUTTON:
{
parametros param;
param.myWindow = myWindow;
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
}
}
}
And this is the thread:
DWORD WINAPI ThreadStartGame(LPVOID param){
HWND w = (HWND)param;
DWORD n;
BOOL ret;
mensagem resposta;
mensagem msg;
msg.tipo = COMECAR_JOGO;
msg.verifica = true;
if (!WriteFile(hPipe, &msg, (DWORD)sizeof(mensagem), &n, NULL)) {return 0;}
ret = ReadFile(hPipeN, &resposta, (DWORD)sizeof(mensagem), &n, NULL);
if (!ret || !n) {
return false;
}
PostMessage(w, WM_STARTGAME, NULL, NULL); // <- THIS GETS EXECUTED BUT NOTHINK HAPPENS AFTER
return 0;
}
I don't think there is any deadlock here.
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)&myWindow, 0, NULL);
This line passes the address of the HWND to the thread (&myWindow)
HWND w = (HWND)param;
This line uses the adress itself as HWND and the SendMessage sends the message to this address which is not a HWND.
Try modifying to
start_game = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadStartGame, (LPVOID)myWindow, 0, NULL);
W/o even looking at the code, I can tell you right away: do not use SendMessage between threads. I recommend reading Psychic debugging: The first step in diagnosing a deadlock is a simple matter of following the money and Preventing Hangs in Windows Applications:
Use asynchronous window message APIs in your UI thread, especially by replacing SendMessage with one of its non-blocking peers: PostMessage, SendNotifyMessage, or SendMessageCallback
...
Any blocking call that crosses thread boundaries has synchronization properties that can result in a deadlock. The calling thread performs an operation with 'acquire' semantics and cannot unblock until the target thread 'releases' that call. Quite a few User32 functions (for example SendMessage), as well as many blocking COM calls fall into this category.
For starters, you're unlikely supposed to do that in the first place. Quoting MSDN:
A thread in an executable that calls the C run-time library (CRT) should use the _beginthreadex and _endthreadex functions for thread management rather than CreateThread and ExitThread; this requires the use of the multithreaded version of the CRT. If a thread created using CreateThread calls the CRT, the CRT may terminate the process in low-memory conditions.
Second, your thread can be worker or UI thread, from the first type you must not call most of the window related functions, as it has no message pump. DestroyWindow is such. (So many times I tried to use MessageBox despite my own comment a few lines upper telling it's forbidden in that function ;).
From worker threads the usual method is to use PostThreadMessage and react on the UI thread. (If you have multiple UI threads, I don't know the rules, was never brave enough for that.)
I'm programming a little game, and I set the lpfnWndProc to DefWindowProc
and after that, I made a loop in that way:
MSG lastMessage;
while (true)
{
if (PeekMessage(
&lastMessage,
this->getWindow(),
0, 0,
PM_REMOVE))
{
TranslateMessage(&lastMessage);
DispatchMessage(&lastMessage);
}
}
So how do I handle the Close Window event in that case?
First of all, this is not how you write a message loop: it will take 100% CPU while waiting for messages, and won't remove messages for other windows from the queue. It will also never terminate. See here for an example of a message loop.
About closing windows: DefWindowProc will handle WM_CLOSE automatically and destroy your window. If you want your application to terminate when the window is closed, you need to handle WM_DESTROY and call PostQuitMessage(0) from it. This means you will need your own window procedure instead of DefWindowProc.
If you want WindowProc to be handled by a class, you do something like
class CWindow
{
static LRESULT WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
CWindow* self;
if(uMsg == WM_CREATE)
{
self = (CWindow*)((LPCREATESTRUCT)lParam)->lplpCreateParams;
}
else
self = GetWindowLong(hwnd,GWL_USERDATA);
if(self){
switch(uMsg){
case WM_CREATE:
return self->OnCreate(hwnd,(LPCREATESTRUCT)lParam);
case WM_CLOSE:
self->OnClose();
return 0;
// etc.
}
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
int OnCreate(HWND hwnd,LPCREATESTRUCT lpcs)
{
m_hwnd = hwnd;
SetWindowLong(m_hwnd,GWL_USERDATA,this);
return 0;
}
}
Making sure of course to pass 'this' as the last parameter to CreateWindow(Ex).
Next, In your message loop, you MUST check for WM_QUIT messages and use that as a cue to exit the loop. Also, NEVER do a filter on hwnd as that will prevent your application loop from dispatching messages for other windows on your thread. And many windows libraries create message windows on threads to facilitate inter process (and thread) comms. If you dont process all windows messages then (a) your game will eventually run out of memory, and (b) the entire system may start to act funny as your application will make IPC messages deadlock, or time out.
Also, WM_CLOSE is (usually) sent via SendMessage, not PostMessage. Sent messages are delivered straight to the window proc and can't be filtered in the app loop.