Global keyboard hook with WH_KEYBOARD_LL and keybd_event (windows) - c++

I am trying to write a simple global keyboard hook program to redirect some keys. For example, when the program is executed, I press 'a' on the keyboard, the program can disable it and simulate a 'b' click. I do not need a graphic ui, just a console is enough (keep it running)
My plan is to use global hook to catch the key input, and then use keybd_event to simulate the keyboard. But I have some problems.
The first problem is that the program can correctly block 'A' but if I hit 'A' on the keyboard once, the printf in the callback function is executed twice, as well as the keybd_event. So if i open a txt file, i click 'A' once, there are two 'B's input. why is that?
The second question is that why the hook using of WH_KEYBOARD_LL can work on other process without a dll? I thought that we had to use a dll to make a global hook until I wrote this example...
#include "stdafx.h"
#include <Windows.h>
#define _WIN32_WINNT 0x050
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
BOOL fEatKeystroke = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (fEatKeystroke = (p->vkCode == 0x41)) { //redirect a to b
printf("Hello a\n");
keybd_event('B', 0, 0, 0);
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
break;
}
break;
}
}
return(fEatKeystroke ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelKybd = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelKybd);
return(0);
}
Many thanks!

Your callback function execute twice because of WM_KEYDOWN and WM_KEYUP.
When you down a key of your keyboard, windows calls the callback function with WM_KEYDOWN message and when you release the key, windows calls the callback function with WM_KEYUP message. That's why your callback function execute twice.
You should change your switch statement to this:
switch (wParam)
{
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
case WM_KEYUP:
case WM_SYSKEYUP:
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)lParam;
if (fEatKeystroke = (p->vkCode == 0x41)) //redirect a to b
{
printf("Hello a\n");
if ( (wParam == WM_KEYDOWN) || (wParam == WM_SYSKEYDOWN) ) // Keydown
{
keybd_event('B', 0, 0, 0);
}
else if ( (wParam == WM_KEYUP) || (wParam == WM_SYSKEYUP) ) // Keyup
{
keybd_event('B', 0, KEYEVENTF_KEYUP, 0);
}
break;
}
break;
}
About your second question, I think you have already got from #Ivan Danilov answer.

First one is easy. You get one for key down and another for key up. :)
As for the why it can work without a DLL - that's because it is a global hook. Unlike thread-specific ones it is executed in your own process, not in the process where keyboard event happened. It is done via message sending to the thread which has installed the hook - that's precisely why you need message loop here. Without it your hook can't be ran as there would be no one to listen for incoming messages.
The DLL is required for thread-specific hooks because they're called in the context of another process. For this to work, your DLL should be injected into that process. It is just not the case here.

I have run your code but nothing happend? What wrong with me?
Base on msdn that WH_KEYBOARD_LL message is "Global only" It mean more than that.
The system calls this function .every time a new keyboard input event is about to be posted into a thread input queue.
This message is special case. You also need an DLL to make a real global hook for other message.

Related

MessageBox() returning 0 when called from Win32 button press

I'm barely a week into Win32 GUI programming, so I'm confident/hopeful this is something simple. For your consideration, I've provided a sample of my code below.
As a quick brief, my application watches for another application to be open so that I can modify that application's memory. I've placed this initial check at the top of my UI looper as follows such that it will only run once (in which case the user can only cancel and the app closes, or execution resumes past the if statement with hWndApp having a value assigned):
if (!hWndApp) {
appCheck();
}
If I start my application and the other application isn't running, appCheck(); fires and the waterfall of execution therefrom acts accordingly: a message box appears (and will keep appearing if the user clicks "Retry") until the other application's window is found. If the user clicks "Cancel," the application exits and all is well. If they click "Retry" once the other application is running, then my application will finish painting to the screen and execution is normal.
The funny business starts the next time I call appCheck(); (which happens when one of either two buttons is clicked) if the other application has been opened, then closed.
While debugging (via Visual Studio 2017), the variable I assign the MessageBox() call to equals 0 when the other application has been opened, then closed, then the following:
Push button to call appCheck();
getProcessHandleAndPID(); is then called within the if statement because the window can't be found
AppCheckMessageBox(); is then called within the while loop because the window can't be found
The debugger then points to the first line inside of AppCheckMessageBox();, which is the entire int msgboxID = MessageBox(); bit
Pressing F11 (Step Into), no window shows and the application exists after the default choice in the switch statement is triggered since the value of msgboxID is 0 (indicating the MessageBox() call failed, so I tried calling GetLastError() before exit(EXIT_FAILURE), but to no avail).
I'm not sure where my error lies, but I've sought many solutions--none of which have panned out. Finally, if you see any variables below that look misnamed or undeclared, it's solely due to my modification of the code for this post to try to generalize/ shorten it. I may have left out some global variable declarations, etc.
Thank you for any help/guidance you can provide! I'm at my wit's end with this right now...lol.
//--------------------------------------------------
// Function to get process handle and PID of app /
//------------------------------------------------
void getProcessHandleAndPID()
{
hWndApp = FindWindow(NULL, _T("NameOfApplication"));
while (!hWndApp) {
AppCheckMessageBox();
}
//Much more code here
}
//---------------------------------
// Function to show message box /
//-------------------------------
int AppCheckMessageBox()
{
int msgboxID = MessageBox(
NULL, //I tried making this hWndApp as well, but no difference
(LPCWSTR)L"Cancel to exit or start the app and click Retry.",
(LPCWSTR)L"Application Not Found!",
MB_ICONSTOP | MB_RETRYCANCEL | MB_SYSTEMMODAL | MB_SETFOREGROUND
);
switch (msgboxID)
{
case IDCANCEL:
exit(EXIT_FAILURE);
case IDRETRY:
getProcessHandleAndPID();
break;
default:
//GetLastError();
exit(EXIT_FAILURE);
}
return msgboxID;
}
//------------------------------------------------
// Function to check if application is running /
//----------------------------------------------
void appCheck() {
if (!FindWindow(NULL, _T("NameOfApplication"))) {
getProcessHandleAndPID();
}
}
//--------------------------------------------------
// Function to get process handle and PID of app /
//------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (!hWndApp) {
appCheck();
}
switch (message)
{
case WM_PAINT:
//Code here
break;
case WM_CREATE:
//Code here
break;
case WM_COMMAND:
switch (HIWORD(wParam))
{
case BN_CLICKED:
if (LOWORD(wParam) == BTN_ENABLE) {
appCheck();
//Do stuff with button press
}
if (LOWORD(wParam) == BTN_DISABLE) {
appCheck();
//Do stuff with button press
}
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
Not really an answer, but too long for comments:
This isn't your real code. Many things are missing, there are mismatched braces which would prevent compilation, etc. Always show your real code if you want help.
As David says, calling appCheck() every time you receive a message is the wrong approach. If you want to call it once after your window opens, do that before entering your message loop.
Your code is needlessly recursive (getProcessHandleAndPID() calls AppCheckMessageBox() which calls getProcessHandleAndPID() which calls...) and will potentially lead to a stack overflow.

Windows Journal playback hook (WH_JOURNALPLAYBACK) ignores EVENTMSG HWND parameter

I am working a program to simulate keyboard and mouse clicks programmatically. It need to send the clicks to a target window handle (ex: notepad edit control). I am getting the handle of notepad window and generating generating WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP, WM_SYSKEYUP messages for that window. The events are stored in queue, and later on played using a WH_JOURNALPLAYBACK hook.
For the code snippet below, the target hwnd in the playback proc though set correctly, messages never reach to the target handle. If I bring the notepad to foreground, it does receive the messages.
I am not sure why WH_JOURNALPLAYBACK ignores the handle parameter. I would have liked to generate a series of automation messages for various handles and played it back so that even without bringing the window into focus we can send keyboard and mouse events.
Please let me know
if messages to various target handles can be sent using a journal
playback hook
why in code below hwnd is ignored
..
#include <queue>
#include <iostream>
#include <windows.h>
using std::cout;
using std::endl;
using std::error;
struct Event
{
UINT msg;
UINT wparam;
UINT lparam;
HWND hwnd;
Event(UINT m, UINT wp, UINT lp, HWND h)
:msg(m),
wparam(wp),
lparam(lp),
hwnd(h)
{}
};
HHOOK jhook= NULL;
std::queue<Event> events;
bool gotoNextMsg = false;
LRESULT CALLBACK JournalPlaybackProc(int code, WPARAM wParam, LPARAM lParam)
{
switch( code )
{
case HC_SKIP:
cout<<"skip: "<<endl;
if(!events.empty())
{
events.pop();
}
break;
case HC_GETNEXT:
{
cout<<"next: "<<events.size()<<endl;
gotoNextMsg = true;
EVENTMSG * evm = (EVENTMSG*) lParam;
Event e = events.front();
switch(e.msg)
{
case WM_KEYDOWN:
cout<<"WM_KEYDOWN"<<endl;
break;
case WM_KEYUP:
cout<<"WM_KEYUP"<<endl;
break;
case WM_SYSKEYDOWN:
cout<<"WM_SYSKEYDOWN"<<endl;
break;
case WM_SYSKEYUP:
cout<<"WM_SYSKEYUP"<<endl;
break;
}
cout<<"handle: "<<e.hwnd<<endl;
cout<<"handle1:"<<evm->hwnd<<endl;
evm->message = e.msg;
evm->paramL = e.wparam;
evm->paramH = e.lparam;
evm->hwnd = e.hwnd;
evm->time = ::GetTickCount();
}
break;
default:
if( code < 0 )
::CallNextHookEx(jhook, code, wParam, lParam);
break;
}
if(events.empty())
{
cout<<"uinstalled"<<endl;
::UnhookWindowsHookEx(jhook);
::PostMessage(NULL, WM_USER+100, 0, 0);
}
return 0;
}
A journal hook injects events into the system message queue. For keyboard and mouse messages, the system dispatches them to the current focused window, same as if the user had input them manually. The HWND you specify in the event is not used, it gets replaced during dispatching.
And if you consider that a recorded journal can be played multiple times, and its data can persist across application instances and even reboots, and that HWNDs can be reused for different things over time, it should make sense why a journal playback cannot make use of an event's HWND even if the system message queue were not involved.
So, you cannot use WH_JOURNALPLAYBACK to target a specific window that is not in the foreground. You would have to send the recorded messages yourself. But be aware of some caveats that Raymond Chen has blogged about:
You can't simulate keyboard input with PostMessage
Simulating input via WM_CHAR messages may fake out the recipient but it won't fake out the input system

Handling Windows messages so that my application responds correctly

I had an old piece of code that I wrote about 15 years ago to do some file manipulation, which runs through a script to process 1/2 sourcefiles and output to 1/2 outputfiles and I've been trying to write it 'properly' so that it will run under Windows 7/8 as a scheduled task.
I've ported it to Visual Studio 2013 Express, and managed to get it to work (execute and generate the desired results) pretty quickly, processing my text input file, stripping rubbish out of it, and generating a formatted CSV file in about 38 seconds, however it Ghosts, and goes non-responsive until such time as the processing of the file completes, which is okish for user execution, but Windows 7 and 8 don't like running it as a scheduled task, and close it as soon as it ghosts.
I've tried re-writing the large chunk of processing code so that it returns to the main message handling loop after each line of script, and this functions, albeit about ten-twenty times slower (depending on whether I'm using GetMessage or PeekMessage, however I'm still struggling with the application ghosting, despite each line of script only taking a few milliseconds to run.
My Main Window code is currently;
while (msg.message != WM_QUIT)
{
while ((PeekMessage(&msg, NULL, 0, WM_COMMAND - 1, PM_REMOVE) > 0) ||
(PeekMessage(&msg, NULL, WM_COMMAND+1, 0xFFFF, PM_REMOVE) > 0))
// While there are any system messages with a value <> WM_COMMAND,
// Process these first
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
// Process one WM_COMMAND message i.e. one of mine.
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
where my WndProc function has a giant case statement that processes all my posted messages to perform one sub-task of my file processing and all the windows system-type responses. I've cut out some of the 'doing stuff' commands, but you'll get the gist
it's a;
until we reach my iteration bit in the scriptfile;
process phase 1
until we finish processing the sourcefile or go round enough iterations;
process phase 2
until we reach the end of the sourcefile
process phase 3
end
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
//////////////////////////////
/* Start of my menu uptions */
//////////////////////////////
case MI_FILE_EXIT:
DestroyWindow(hWnd);
return(0);
case MI_RUN_EXECUTE:
// * Open Necessary Files * //
// * Start Processing ScriptFile * //
phase = 1;
command = 'A';
PostMessage(hWnd, WM_COMMAND, MI_PHASE_1, lParam);
return(0);
case MI_PHASE_1:
nextcommand = ProcessCommand(command);
if (ScriptFileComplete)
{
// We've reached the end of the script - stop processing
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
else if (nextcommand = '<')
{
// prep for start of phase 2
phase = 2;
tiptr = tptr;
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_2, lParam);
break;
}
else
{
// process the nextcommand
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_1, lParam);
break;
}
return(0);
case MI_PHASE_2:
nextcommand = ProcessCommand(command);
redrawscreen(hWnd);
if (nextcommand == '>')
{
// we're at the end of the iteration
if (UseIterationCount)
{
IterationCount--;
if (IterationCount <= 0)
{
phase = 3;
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_3, lParam);
break;
}
}
}
else if (ScriptFileComplete)
{
// We've reached the end of the script - stop processing
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
else if (SourceFileAComplete)
// We've reached the end of the Source File - stop processing
{
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
else // All's normal and we're just processing the next command
{
command = nextcommand;
PostMessage(hWnd, WM_COMMAND, MI_PHASE_2, lParam);
break;
}
return(0);
case MI_PHASE_3:
nextcommand = ProcessCommand(command);
command = nextcommand;
// test to see if we go round phase 3 loop again
if ((!ScriptFileComplete) && (!SourceFileAComplete))
{
PostMessage(hWnd, WM_COMMAND, MI_PHASE_3, lParam);
break;
}
else // we've cleared that and we're at scriptfile EOF
{
PostMessage(hWnd, WM_COMMAND, MI_SCRIPT_COMPLETE, lParam);
break;
}
return(0);
case MI_SCRIPT_COMPLETE:
// We're at the end of the script - close things down.
CloseFiles();
DrawMenuBar(hWnd);
if (AutoExit)
PostMessage(hWnd, WM_QUIT, wParam, lParam);
return(0);
case MI_DO_NOTHING: // blank code for initial entry to main message loop
return(0);
default: // somehow an invalid message was posted
log("invalid message was posted");
return(0);
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
redrawscreen(hWnd);
EndPaint(hWnd, &ps);
return(0);
case WM_DESTROY:
PostQuitMessage(0);
return(0);
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return(0);
}
So the idea is that after each call to processCommand (i.e. carry out one line of my script processing), return to the main message handle, respond to any events (like someone moving the window or clicking on the close button), and then process the next line of my script.
I'm clearly missing something (or lots of things) regarding which messages I should be checking and processing on a regular basis, so if anyone can offer suggestions/advice as to;
What messages should I be handling before all others?
How often should my application be checking for system messages?
Am I going about this completely wrong?
e.g. should I be threading the processing code? - the app shouldn't require any user interaction while it's running, but it would be good practise to allow a user to move/resize/quit it, which I was hoping to achieve through posting messages back to WM_COMMAND
Thank you very much for even reading this far. Any and all advice no matter how sharp (if it helps) appreciated.
Richard.
- UPDATE -
Thanks both for the pointers - it's clear that this does warrant threading my slow file access bits of code, so I've re-written to do this, but now I'm just a bit stuck as to where I should do fire off the thread / join afterwards - There's lots of examples where the thread is fired off in the main window and then joined straight afterwards e.g.;
void My_Slow_Task(){
; // Process lots of data
}
int main(){
std::thread t1(My_Slow_Task);
t1.join();
return 0;
}
but as pointed out below doing this in my message handling block just means it sits there like a lemon until the thread finishes, but I need a user to be able to make changes to the outputfiles etc. before they kick off the file manipulation process (it can be automated, but it needs to be able to not be as well), so at the moment, I'm after something like;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// one of these messages is the menuitem for 'Run_my_big_chunk_of_processing' and sets 'ExecutingScript' to TRUE
// another will be to change the location of the output file or edit the script etc.
if (ExecutingScript == TRUE)
{
ExecutingScript = FALSE;
std::thread t1(Run_my_big_chunk_of_processing);
t1.join();
PostMessage(hWnd, WM_COMMAND, MI_RUN_COMPLETE, lParam);
// to do the close files, tidy up and feed back to the user.
}
}
If anyone's knows how I can handle the request from the user to start the slow process and fire it off, without the GUI having to wait for it to finish before handling other messages, then that'll be it sorted.
- SOLUTION? -
Use an outer control loop for user interaction while the thread isn't running, and an inner one for while it is;
_twinMain()
{
// Initialise Stuff
// Pre-exec message loop
// Outer messagehandling loop
while (!AllDone)
// we're !AllDone on entry, and AllDone when the app gets
// a WM_QUIT or other triggered abort e.g. script failure
{
// Pre/post-exec message loop
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (ExecutingScript)
// this will be set by auto-run in the ini file,
// or manually by a user clicking the menu option
{
std::thread t1(RunThread);
// Exec message loop
while (ExecutingScript)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
// There may be no messages, as we could be in auto-run
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
t1.join();
PostMessage(hWnd, WM_COMMAND, MI_RUN_COMPLETE, lParam);
}
}
return (int) msg.wParam;
}
Thanks for all your help
VS2013 has the C++11 <thread> stuff, no need for non-standard libraries. std::aync(std::launch::async) will run a background task, std::future::wait_for allows you to check from the messsage loop whether the operation has finished. Of course, you can also use a old-style PostQuitMessage(WM_APP) from the processing thread. Either way, after the message loops exits, call .join() on the worked thread to clean it up, then exit the main thread.

Using DirectInput to receive signal after plugging in joystick

I have a C++ program that enumerates all the input devices (using direct input) at the start of the program. If the program is started, and then I plug in another controller, this controller won't be recognized until the program is restarted. Anyone know of an event I can use that will cause my program to enumerate all of the devices after a new one is plugged in?
This article discusses how to detect game pad changes. First of all, you can handle the WM_DEVICECHANGE message and check wParam for DBT_DEVICEARRIVAL or DBT_DEVICEREMOVECOMPLETE. It seems that in order to receive these as WPARAMs, though, you need to call RegisterDeviceNotification first.
The article's example of how to do this is as follows:
DEV_BROADCAST_DEVICEINTERFACE notificationFilter;
ZeroMemory(&notificationFilter, sizeof(notificationFilter));
notificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
notificationFilter.dbcc_size = sizeof(notificationFilter);
HDEVNOTIFY hDevNotify;
hDevNotify = RegisterDeviceNotification(m_hWnd, &notificationFilter,
DEVICE_NOTIFY_WINDOW_HANDLE |
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
if(hDevNotify == NULL) {
// do some error handling
}
The only other thing to watch out for is that the minimum supported OS for this is XP, so you need to put in the appropriate #define for that before including the Windows headers.
Depending on what you want to do, you might not even have to call this function first. Instead, you can just check DBT_DEVNODES_CHANGED to not differentiate between a device being plugged or unplugged. That could save some code if you don't care.
Got it working. When any device is removed or added just dispose all 'IDirectInputDevice8' and re-create them. This avoids bugs and keeps things simple.
Hook WinProc method to watch for add/remove events
bool refreshInputDevices = false;
LRESULT SubWndProc(int code, WPARAM wParam, LPARAM lParam)
{
// invalid code skip
if (code < 0) return CallNextHookEx(NULL, code, wParam, lParam);
// check if device was added/removed
PCWPSTRUCT pMsg = PCWPSTRUCT(lParam);
if (pMsg->message == WM_DEVICECHANGE)
{
switch (pMsg->wParam)
{
case DBT_DEVNODES_CHANGED:
refreshInputDevices = true;
break;
case DBT_DEVICEARRIVAL:
refreshInputDevices = true;
break;
case DBT_DEVICEREMOVECOMPLETE:
refreshInputDevices = true;
break;
}
}
// continue as normal
return CallNextHookEx(NULL, code, wParam, lParam);
}
Here is how you can hook on the input thread
// hook WinProc to watch for device changes
HMODULE module = GetModuleHandleW(NULL);
DWORD threadID = GetCurrentThreadId();
HHOOK hook = SetWindowsHookExW(WH_CALLWNDPROC, (HOOKPROC)&SubWndProc, module, threadID);

Making and using hotkeys in a DLL GTA SA

I made a little DLL in C++ that I inject into the GTA San Andreas game. Now I want to create hotkeys that work in-game. Like when I press F10 it sets the player's health to maximum. I already know how to set the health and all but I don't know how to make hotkeys.
Here is some code I found but it isn't for DLL usage I suppose:
bool customKeyHook(HWND hWnd, UINT uMsg ,WPARAM wParam, LPARAM lParam)
{
switch(wParam)
{
case VK_F10:
*playerHP = 200;
return true;
}
}
Create a Thread with CreateThread an then create an infinite loop and wait for the keypress:
if (GetAsyncKeyState(VK_F10) & 1)
{
}