stavrop
stavrop

Reputation: 485

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

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?

Upvotes: 12

Views: 36360

Answers (4)

Enrique Wood
Enrique Wood

Reputation: 69

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

Upvotes: 6

user1309389
user1309389

Reputation:

LRESULT CALLBACK WndProc(...), as it name suggests is a (specific) window (message) processor where you can analyze and respond to messages on the queue that were deferred by the system to your custom definition of the callback for further processing.

Since you want to detect and act on mouse clicks anywhere on the screen, as chris suggested in the comments, one way is to hook yourself into the system by calling SetWindowsHookEx() which is quite verbose in its very definition - it allows you to track stuff happening on the system and relay that information back to your application.

This is the syntax which you need to employ in order to get yourself

HHOOK WINAPI SetWindowsHookEx(
  __in  int idHook,
  __in  HOOKPROC lpfn,
  __in  HINSTANCE hMod,
  __in  DWORD dwThreadId
);

It takes in a specific hook id, which are basically little #defines which tell the function what kind of messages you wish to receive from all over the system, you pass it a callback just like the WndProc, but this time it's meant to process the incoming messages regarding across the system. hMod simply refers to the handle to the application or the DLL in which the just mentioned proc function callback is located in. The last one relates to threads currently running on the system, setting this to 0 or NULL retrieves messages for all existing threads.

Important:

Do note that Aurus' example call to the SetWindowsHookEx is process-specific which a fancy word relating it to an actual application, instead of a DLL which can be appended to multiple processes across the system ( a global one ) and return information to your application. It would be prudent to take the time and effort to investigate Eugene's recommended method instead of this forceful approach useful only for experiments. It's a bit "harder", but the reward is worthwhile.

Less work is not always better or preferable.

Upvotes: 2

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.

Upvotes: 11

Aurus
Aurus

Reputation: 705

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;
}

Upvotes: 5

Related Questions