c++: How to catch mouse clicks wherever they happen

31,344

Solution 1

You need to set a mouse hook as described in MSDN.

Note that in your case the hook would need to be global. This means that you need to implement a handler function in a DLL, which will be loaded into all processes in the system which receive mouse message. Such DLL will communicate with your main application using some interprocess communication (IPC) mechanism like shared memory or via Windows messages posted (not sent) from the DLL to the main application.

You can use the source code from this CodeProject article as a guide.

Update: as per Chris' correction, I should note that above applies to "regular" mouse hook which is synchronous. Low-level hook doesn't need to be located in the DLL, but it has certain limitations which are described in the corresponding MSDN article.

Solution 2

well I don't really know if you solved your problem. I hope so. But I was in the same trouble today and searching I found a way really easy to do it.

So here you are:

int keyPressed(int key){
    return (GetAsyncKeyState(key) & 0x8000 != 0);
}

int main(){
    while(1){
        if(keyPressed(VK_LBUTTON)){
            printf("%s\n","Click izquierdo");
        }
        if(keyPressed(VK_RBUTTON)){
            printf("%s\n","Click Derecho");
        }
    }
    return 0;
}

the key of this solution is the function GetAsyncKeyState(key), where key anyone of the codes that appears here https://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx

Solution 3

You could use SetWindowsHookEx

Here's a small sample:

#define _WIN32_WINNT 0x0500
#include <windows.h>

HHOOK MouseHook;

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam){

        PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)(lParam);
        POINT p;


        if(wParam == WM_RBUTTONDOWN)
        { 
          // right button clicked 
          GetCursorPos(&p);
        }

}

void StayAlive(){
        while(_getch() != 27) { }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nShowCmd){
        FreeConsole();

        MouseHook = SetWindowsHookEx(WH_MOUSE_LL,MouseHookProc,hInstance,0);
        StayAlive();

        UnhookWindowsHookEx(MouseHook);
        return 0;
}
Share:
31,344
stavrop
Author by

stavrop

Updated on April 19, 2020

Comments

  • stavrop
    stavrop about 4 years

    I am stuck with an application I am writing where I need to monitor for mouse clicks.

    The clicks may happen anywhere on the screen and not inside the app window, and for each click I must pass a message (perform an action or something).

    I looked around and read some suggestions like using

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    

    but I was unsuccessful.

    Does anyone have an idea on how to implement what I need?

  • chris
    chris almost 12 years
    You don't need a dll if you use a low level one. I can confirm that from experience.
  • Eugene Mayevski 'Callback
    Eugene Mayevski 'Callback almost 12 years
    @chris and where did I write about low-level hook?
  • chris
    chris almost 12 years
    You didn't. I was suggesting it due to the greatly less amount of work needed to get it working.
  • Eugene Mayevski 'Callback
    Eugene Mayevski 'Callback almost 12 years
    @Chris Low-level hooks have an unpleasant drawback of time limit, which make it hard for a novice to manage right especially when time-consuming operation is involved. It might be easier to deal with a DLL. I agree with you that Low-level hook might be fine for quick-and-dirty tests or simple activity.
  • chris
    chris almost 12 years
    I see your point. I come from writing many of those "quick-and-dirty tests", so I'm used to just getting it working without wasting so much time on it.
  • BrendanMcK
    BrendanMcK almost 12 years
    With any sort of hook - low-level or otherwise - it's still good practice to keep the work in the hook minimal. Just do whatever basic triage/testing you need to do on the coordinates, and then post a message back to (or otherwise communicate with) the app mainline to let it know there's work do do. LL hooks do have one major advantage for the novice which is they avoid having to set up some out-of-proc communication mechanism; you can use global variables as-is - and they work across 32/64-bit, whereas inproc hooks require 32bit vs 64bit to be dealt with separately.
  • BrendanMcK
    BrendanMcK almost 12 years
    Curious, does this work? LL hooks require a message loop, and I can't recall offhand if _getch() pumps messages behind the scenes to allow the messages to get delivered - most console-style API's don't. MessageBox() is another quick and dirty alternative to use that definitely pumps messages and is useful when playing with these APIs initially.
  • Eugene Mayevski 'Callback
    Eugene Mayevski 'Callback almost 12 years
    @BrendanMcK Hook itself should be minimal of course, but in case of OP's task the hook would just notify the main code that some job needs to be done.
  • BrendanMcK
    BrendanMcK almost 12 years
    @EugeneMayevski'EldoSCorp; agree; I really just pointing out that with decently written code, the time limit for a LL hook shouldn't be an issue. (If someone's hitting that, they're doing hooks wrong in the first place!) My take is that in-proc can have better perf, but is trickier to write due to cross-proc issues; whereas LL has more overhead, but is far simpler to get up and running. For a novice, I'd recommend starting with a LL hook to play with the hook in the first place - otherwise with a separate DLL, they'll be spending quite some time figuring out the cross-proc stuff.
  • Noitidart
    Noitidart over 8 years
    Doing GetCursorPos within the mouse, hook is uneeded. The lParam is an address to a MSLLHOOKSTRUCT which contains a field pt which has the point info.
  • Mich
    Mich over 5 years
    E0167 argument of type "LRESULT (__stdcall OpenCVApp::*)(int nCode, WPARAM wParam, LPARAM lParam)" is incompatible with parameter of type "HOOKPROC"