So I am trying to make a message box appear when a user presses a button on his/her keyboard using Hooks.
The hook is getting installed correctly because there are no errors, but it seems like the KeyboardProc Callback function is not getting called because the message box that is supposed to show up when it is called never shows up.
There are no errors btw that show up and I am programming this in a desktop app.
Here is the code regarding the hook and the callback function:
LRESULT CALLBACK KeyboardProc(
int nCode, WPARAM keyState, LPARAM keyInfo) {
LRESULT reValue = 0;
MessageBox(hWnd, L"Testing", L"Test", MB_OK);//This is the msg box that isnt showing up
if (nCode < 0) {
reValue = CallNextHookEx(keyboardHook, nCode, keyState, keyInfo);
}
return reValue;
};
keyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, hInstance, 0);
You need to run a message loop to process the calls. From the remakrs on the KeyboardProc callback function description: "The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop."
Related
I am using the Windows API on Windows7 with Visual Studio 2019.
I'm trying to set a low level keyboard hook and read the key input to the console, to do so I use the function: HHOOK SetWindowsHookExA( [in] int idHook, [in] HOOKPROC lpfn, [in] HINSTANCE hmod, [in] DWORD dwThreadId )
with the argument: WH_KEYBOARD_LL so I can monitor keyboard events.
This is my main function:
int main()
{
...
HHOOK keyBoardHook = SetWindowsHookExW(WH_KEYBOARD_LL, keyboardHook, NULL, 0);
MSG message;
while (true)
{
while(PeekMessage(&message, NULL, 0, 0, PM_REMOVE) != 0)
{
DispatchMessage(&message);
}
}
...
UnhookWindowsHookEx(keyBoardHook);
return 0;
}
And this is the callback implementation:
LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
KBDLLHOOKSTRUCT* keyData = (KBDLLHOOKSTRUCT*)lParam;
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
{
fileHandler.addStr(keyHandler.translate(keyData,true,topWindowThreadId));
}
else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
{
fileHandler.addStr(keyHandler.translate(keyData,false,topWindowThreadId));
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
How both variables work is not the issue here but just know that
in the callback keyHandler translates the message and fileHandler prints the result to a file.
Here comes the issue. The callback receives:
a key down event when I press a key
a key up event when I release
a repeated key down event when I hold a key
a control key up event VK_LCONTROL when focused window changes
Why does that happen ? This behavior is never mentioned in the MSDN documentation as far as I know. If I switch from console window or any window to any other window this event is generated and a [left control up] message is printed by my keyHandler !
Now to make sure it's not a problem with my code I changed the Callback to this:
LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
KBDLLHOOKSTRUCT* keyData = (KBDLLHOOKSTRUCT*)lParam;
if (keyData->vkCode == VK_LCONTROL)
{
printf("CTRL");
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
And still CTRL is printed to the consol whenever I change the focused window, Note that only VK_LCONTROL is generated and wParam is always WM_KEYUP
This is not supposed to happen!
I tried analyzing and modifying my code, tried removing everything from the main function until it looked just like in the example above even rebooted the computer to check if it's an internal issue, nothing helps. and when searching the web for a similar post with a similar issue I found absolutely none, which makes it even more confusing.
Update
I tried compiling someone else's keyboard-hook related code from GitHub, same issue.. is this normal ? Why is it not documented ?
According to the description of the SetWindowsHookExA in the official Microsoft documentation.
The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread. All global hook functions must be in libraries. Global hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.
HHOOK SetWindowsHookExA(
[in] int idHook,
[in] HOOKPROC lpfn,
[in] HINSTANCE hmod,
[in] DWORD dwThreadId
);
For desktop apps, if this parameter(dwThreadId) is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread. That's why after you changed the focused window, CTRL still printed to the console. So it is recommended that you use hook in DLL.
I am trying to create a simple mouse hook to detect if the mouse is moving, but for some reason when I run the program, the mouse doesnt function at all until I stop the process.
Here is my code:
#include <windows.h>
HHOOK g_hMouse;
LRESULT CALLBACK MouseHook(int nCode, WPARAM wParam, LPARAM lParam)
{
printf("MOUSE EVENT!\n");
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
g_hMouse = SetWindowsHookEx(WH_MOUSE_LL, MouseHook, NULL, NULL);
while (1) {
Sleep(2);
}
return 0;
}
Any help would be appreciated.
Thanks.
WM_MOUSE_LL hooks require that the thread that installed it keeps pumping messages; so you'll need a GetMessage/DispatchMessage loop here. Details for this are in the MSDN docs for WM_MOUSE_LL:
This hook is called in the context of the thread that installed it. The call is made by sending a message to the thread that installed the hook. Therefore, the thread that installed the hook must have a message loop.
If you just want to try something quick when experimenting/debugging, replace your Sleep() with a call to MessageBox(...), which will block your code so you can do testing, but it runs its own message loop, so the hook will run.
I'm trying to create macro application that will start running certain operations when key is pressed (system wide shortcut). I did created Windows Form Application with Visual Studio 2012. When form is loaded keyboard hook is installed:
HookHandle = SetWindowsHookEx( WH_KEYBOARD_LL, (HOOKPROC)keyboardHookHandler, GetModuleHandle(NULL), NULL);
if( HookHandle == 0){
MessageBox::Show("Error setting hook!");
}
My hook callback function is:
public: static LRESULT CALLBACK keyboardHookHandler( int code, WPARAM wParam, LPARAM lParam ) {
if(code>=0 && wParam == WM_KEYDOWN){
MessageBox::Show("Key Down");
}
return CallNextHookEx( HookHandle, code, wParam, lParam);
}
When I do compile application and run it message box is never shown. More to say I know this call back function is fired but wParam always contains value 45 (I did checked and none of those WM constants that should be returned has value 45). Also after few key events application crashes.
What is the reason why this code doesn't work like it should to?
Update:
I did removed cast to HOOKPROC and changed it to delegated procedure:
private:
delegate LRESULT CALLBACK HOOKPROC( int code, WPARAM wParam, LPARAM lParam );
HOOKPROC^ keyboardHookProcedure;
And hook setting to:
keyboardHookProcedure = gcnew HOOKPROC(this, &MyForm::keyboardHookHandler);
HookHandle = SetWindowsHookEx( WH_KEYBOARD_LL, keyboardHookProcedure, GetModuleHandle(NULL), NULL);
But now I have this problem:
error C2664: 'SetWindowsHookExW' : cannot convert parameter 2 from 'WindowsFormTest::MyForm::HOOKPROC ^' to 'HOOKPROC'
If you're trying to catch a unique key combination globally, it might be simpler to use RegisterHotKey. It defines a system-wide hot key with no need for hooks or anything special. It is going to override the foreground process handling, so this won't be ideal if you're trying to register a common key combo.
I want to detect everytime I paste something. It's just something to make some data entry work simpler.
I set a global hook and then "wait" for the wm_paste. This is part of the code I have:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)//Do not process the message
return CallNextHookEx(msg_hook,nCode,wParam,lParam);
LPMSG m=(LPMSG)lParam;
if(m->message == WM_PASTE)
{
OutputString("Paste detected!\n");
}
if(m->message == WM_PASTE)
{
OutputString("Paste detected!\n");
}
return CallNextHookEx(msg_hook,nCode,wParam,lParam);
}
//DLL_ATTACH:
...
if(strstr(ProcName, LOADERNAME))
{
InitCommonControls();
if(!(msg_hook=SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hinstDLL, 0)))
{
ErrorExit(TEXT("SetWindowsHookEx"));
//MessageBox(0, "WH_GETMESSAGE", 0, 0);
//return -1;
}
}
WM_PASTE debug string never gets printed. I'm aware that not all applications use WM_PASTE. But at least notepad should work.
Any suggestions?
Thanks!
In GetMsgProc, the wParam parameter is not the message being intercepted, but a flag that indicates whether or not the message in lParam and been removed from the message queue.
You should be using m->wParam instead.
Wm_paste message is fired only in combo box and edit control. There is no easy way to capture paste, but you can get copy message by creating a tiny window and adding this window to the chain of clipboard viewers.
The following code works fine. It gives out the message when the user presses a key. But there are certain things I am not aware of. What is the role of Message Loop here ? I read that calling SetWindowsHookEx(...) registers a function with the windows and windows calls the appropriate function automatically when a event of registered type happens. No doubt that i don't see the output if don't give the message loop it's space.
#include<iostream>
#include <windows.h>
using namespace std;
HINSTANCE hinst = NULL;
static HHOOK handleKeyboardHook = NULL;
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
void setWinHook() {
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc,NULL, 0);
if(handleKeyboardHook == NULL) {
cout << "is NULL";
} else {
cout << "is not NULL";
}
cout<<("Inside function setWinHook !");
}
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
cout << ("You pressed a key !\n");
return CallNextHookEx(handleKeyboardHook, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
handleKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
EDIT
Does exiting the program (closing the console window) unregister the hook ?
EDIT 2
what role does Dispatch Message play here ? According to doc it dispatches a message to window procedure,but here even if i exclude that,it doesn't effect the output.
All events in Windows, even the low-level keyboard event used in your example, is sent using the normal message events. So for the program to be able to sense keyboard events, it has to use an event loop processing messages.
Without a loop, the program would exit immediately, and the hook would be removed at once too. You cannot register a hook and exit — the system would become a mess if buggy programs were leaving too many forgotten hooks after them. Once your process dies, the hook is scheduled for removal.
I don't remember about low-level keyboard hook, but callbacks of many other hooks are only called inside GetMessage/PeekMessage, and not on some other thread, so just an infinite loop won't suffice — it has to be a message loop.
"what role does Dispatch Message play here ? According to doc it dispatches a message to window procedure,but here even if i exclude that,it doesn't effect the output."
DispatchMessage is pretty useless cos console window doesnt receive much messages.
Only message received is when window loses focus.