1

I am trying to move the mouse (on Windows 10) using SendInput when I perform a physical mouse click. It works fine if I click once or twice, but if clicking for examples 6 times in quick succession the mouse lags for a few seconds then the program stops responding. Is there any obvious reason why this is happening?

(Edited)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

LRESULT CALLBACK MouseHook(int, WPARAM, LPARAM);

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int)
{
    HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, MouseHook, NULL, 0);
    MessageBox(NULL, L"Hello", L"Hello", MB_OK);
    UnhookWindowsHookEx(hook);

    return 0;
}

LRESULT CALLBACK MouseHook(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION) {
        switch (wParam) {
        case WM_RBUTTONUP:
            INPUT buffer;
            ZeroMemory(&buffer, sizeof(buffer));
            buffer.type = INPUT_MOUSE;
            buffer.mi.dx = 0;
            buffer.mi.dy = 10;
            buffer.mi.mouseData = 0;
            buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
            buffer.mi.time = 0;
            buffer.mi.dwExtraInfo = 0;
            SendInput(1, &buffer, sizeof(INPUT));
        }
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
  • I tried to add a minimal example above. I don't understand what you mean with the MessageBox dispatching messages though? – wild_strawberries Jun 30 '20 at 18:17
  • 1
    Your call to `CreateWindow()` is not passing `this` to the `lpParam` parameter, so when `MsgRouter()` calls `GetWindowLong(GWL_USERDATA)`, `window` will always be NULL, so calling `window->MsgProc()` has *undefined behavior*. And FYI, [`WM_NCCREATE` is not the 1st message a window receives](https://stackoverflow.com/questions/1741296/), so `MsgRouter()` needs to handle the case when `GWL_USERDATA` is NULL before `SetWindowLong()` is called. Just call `DefWindowProc()` when `window` is NULL. – Remy Lebeau Jun 30 '20 at 18:18
  • Remove all the windowing code, registering the window class, creating a window, the attempt to forward message handling to a class member. Leave only the `wWinMain` that registers the hook as well as the hook procedure, and a call to `MessageBox`. You need to dispatch messages on the calling thread so that your hook gets called. You could do this with a message loop, or just have the message box do it for you, and get a simple way to terminate your program for free. – IInspectable Jun 30 '20 at 18:24
  • Thank you both for your help and feedback! I have updated the code in the original post above as suggested @IInspectable with just a MessageBox and the hook, but it still produces the same issue sadly – wild_strawberries Jun 30 '20 at 19:52
  • Could you describe what you want to achieve, calling `SendInput` in the mouse hook will trigger the callback again, which may cause problems. In most cases where the application needs to use low level hooks, it should monitor [raw input](https://learn.microsoft.com/en-us/windows/win32/inputdev/raw-input) instead. – Drake Wu Jul 06 '20 at 06:27
  • I am trying to move the mouse 10 pixels whenever I click the right mouse button. I suppose it could be that the hook gets called again, but then that would make it difficult to use SendInput in any hooks? And it only moves the mouse once every time I click which I interpret as the hook only run once each time. I can try to use raw input instead and see how that works. Thanks! – wild_strawberries Jul 07 '20 at 11:28
  • Hi,did you solve this issue with raw input? You could check my sample if it help. – Drake Wu Jul 17 '20 at 06:08

1 Answers1

0

Using Raw Input sample:

#include <windows.h>
#include <iostream>

using namespace std;
BOOL registerTouchpadForInput(HWND hWnd)
{
    RAWINPUTDEVICE rid;
    rid.dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
    rid.usUsagePage = 1;                            
    rid.usUsage = 2;
    rid.hwndTarget = hWnd;
    return RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
void getinputdata(LPARAM lparam)
{
    HRAWINPUT hInput = (HRAWINPUT)lparam;
    RAWINPUT input = { 0 };

    UINT size = sizeof(RAWINPUT);
    GetRawInputData(hInput, RID_INPUT,&input, &size,sizeof(RAWINPUTHEADER));
    if (RIM_TYPEMOUSE == input.header.dwType)
    {
        if (input.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN)
        {
            INPUT buffer;
            ZeroMemory(&buffer, sizeof(buffer));
            buffer.type = INPUT_MOUSE;
            buffer.mi.dx = 0;
            buffer.mi.dy = 10;
            buffer.mi.mouseData = 0;
            buffer.mi.dwFlags = MOUSEEVENTF_MOVE;
            buffer.mi.time = 0;
            buffer.mi.dwExtraInfo = 0;
            SendInput(1, &buffer, sizeof(INPUT));
        }
    }
    return;
}

static LRESULT CALLBACK NVTouch_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    BOOL  registrationStatus = false;
    switch (message)
    {
    case WM_CREATE:
        registrationStatus = registerTouchpadForInput(hwnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_INPUT:
        getinputdata(lParam);
        return DefWindowProc(hwnd, message, wParam, lParam);
    default:
        return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

int main()
{
    WNDCLASSEX wndclass = {
        sizeof(WNDCLASSEX),
        CS_DBLCLKS,
        NVTouch_WindowProc,
        0,
        0,
        GetModuleHandle(0),
        LoadIcon(0,IDI_APPLICATION),
        LoadCursor(0,IDC_ARROW),
        HBRUSH(COLOR_WINDOW + 1),
        0,
        L"myclass",
        LoadIcon(0,IDI_APPLICATION)
    };
    bool isClassRegistered = false;
    isClassRegistered = RegisterClassEx(&wndclass);
    if (isClassRegistered)
    {
        HWND window = CreateWindow(wndclass.lpszClassName, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(0), NULL);
        if (window)
        {
            ShowWindow(window, SW_SHOWDEFAULT);
            MSG msg;
            while (GetMessage(&msg, 0, 0, 0))
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
}
Drake Wu
  • 6,927
  • 1
  • 7
  • 30
  • Your example works flawlessly, thank you so very much! I am still not sure what caused the odd behaviour in my original example but it does not matter now. Awesome! – wild_strawberries Jul 17 '20 at 20:43