0

I'm trying to make an application that just detects if the left mouse button is held down. In trying to do this, as well as learn mouse hooks, I copy-pasted a hook from an example source (https://cboard.cprogramming.com/windows-programming/119909-setwindowshookex-lowlevelmouseproc.html) just to see what it would do. The problem is that it lags my computer. Why is this, and how can I fix it?

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <iostream>
#include <cstdio>
using namespace std;

HHOOK g_Hook;
HANDLE g_evExit;

LRESULT CALLBACK LowLevelMouseProc (int code, WPARAM wParam, LPARAM lParam)
{
    if (code == HC_ACTION)
    {
        const char *msg;
        char msg_buff[128];
        switch (wParam)
        {
            case WM_LBUTTONDOWN: msg = "WM_LBUTTONDOWN"; break;
            case WM_LBUTTONUP: msg = "WM_LBUTTONUP"; break;
            case WM_RBUTTONDOWN: msg = "WM_RBUTTONDOWN"; break;
            case WM_RBUTTONUP: msg = "WM_RBUTTONUP"; break;
            default: 
                sprintf(msg_buff, "Unknown msg: %u", wParam); 
                msg = msg_buff;
                break;
        }//switch

        const MSLLHOOKSTRUCT *p = 
            reinterpret_cast<const MSLLHOOKSTRUCT*>(lParam);
        cout << msg << " - [" << p->pt.x << ',' << p->pt.y << ']' << endl;

        static bool left_down = false;
        static bool right_down = false;
        switch (wParam)
        {
            case WM_LBUTTONDOWN: left_down = true; break;
            case WM_LBUTTONUP:   left_down = false; break;
            case WM_RBUTTONDOWN: right_down = true; break;
            case WM_RBUTTONUP:   right_down = false; break;
        }//switch

        if (left_down && right_down)
            SetEvent(g_evExit);
    }//if

    return CallNextHookEx(g_Hook, code, wParam, lParam); 
}//LowLevelMouseProc


int main()
{
    g_evExit = CreateEvent(0, TRUE, FALSE, 0);
    if (!g_evExit)
    {
        cerr << "CreateEvent failed, le = " << GetLastError() << endl;
        return 1;
    }//if

    g_Hook = SetWindowsHookEx(WH_MOUSE_LL, &LowLevelMouseProc, 
                              GetModuleHandle(0), 0);
    if (!g_Hook)
    {
        cerr << "SetWindowsHookEx() failed, le = " << GetLastError() << endl;
        return 1;
    }//if

    cout << "Press both left and right mouse buttons to exit..." << endl;

    MSG msg;
    DWORD status;
    while (1)
    {
        while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
            DispatchMessage(&msg);

        status = MsgWaitForMultipleObjects(1, &g_evExit, FALSE, 
                                           INFINITE, QS_ALLINPUT);
        if (status == (WAIT_OBJECT_0 + 1))
        {
            // there are messages to process, eat em up
            continue;
        }//if
        else
        {
            // assume g_evExit is signaled
            break;
        }//else
    }//while

    cout << "Exiting..." << endl;
    UnhookWindowsHookEx(g_Hook);
    CloseHandle(g_evExit);
    return 0;
}//main
  • What have you tried so far to try to resolve your problem? – Water Nov 15 '19 at 05:50
  • I think it's a problem with how I'm removing the hook. I've tried playing with the remove mechanism a little bit, but nothing major. It didn't help, though. – Pjpuffs Nov 15 '19 at 16:19

1 Answers1

0

You need a message pump. The code you posted uses PeekMessage in combination with MsgWaitForMultipleObjects, but it's probably a better idea to use GetMessage along with TranslateMessage and DispatchMessage, as showcased in How to manually run message pump in C++:

MSG msg;
while (GetMessage(&msg, NULL, 0, 0) > 1) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

With this loop, I was able to set up a WH_MOUSE_LL hook with SetWindowsHookExA without having the mouse input lag, and correctly receiving all events.

Make sure the hook is installed on the same thread that will pump the messages.

Lonami
  • 5,945
  • 2
  • 20
  • 38