0

I’m trying to remap the right mouse button to act as the middle mouse button in C++ on Windows.

What I did

  • I wrote code using Raw Input (see below).
  • My code successfully sends a middle click when I press the right button.
  • But the original right click action still happens at the same time, so I end up with both right click and middle click firing.

I also tried using a WH_MOUSE_LL low-level mouse hook:

  • This can block the right button completely.
  • However, it introduces a small delay, and the behavior does not feel as smooth or natural as AutoHotkey’s remapping.

What I want

  • When I press the right mouse button, I want to completely block the original right click.
  • Instead, it should act exactly like the middle mouse button.
  • It should feel instant (no noticeable delay), as natural as if I physically pressed the middle button.

My ultimate goal is to achieve AutoHotkey-level remapping in C++:

  • Right button is completely suppressed (never reaches applications).
  • Only middle button is sent instead.
  • The behavior should be instant and natural, with no noticeable delay, just like if I physically pressed the middle button.

My current code (Raw Input version)

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

// SendInput to simulate middle click
void SendMiddleClick(bool down) {
    INPUT input = { 0 };
    input.type = INPUT_MOUSE;
    input.mi.dwFlags = down ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP;
    SendInput(1, &input, sizeof(INPUT));
}

// Window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    if (msg == WM_INPUT) {
        UINT dwSize = 0;
        GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
        if (dwSize > 0) {
            BYTE* lpb = new BYTE[dwSize];
            if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) {
                RAWINPUT* raw = (RAWINPUT*)lpb;
                if (raw->header.dwType == RIM_TYPEMOUSE) {
                    auto flags = raw->data.mouse.usButtonFlags;
                    if (flags & RI_MOUSE_RIGHT_BUTTON_DOWN) SendMiddleClick(true);
                    if (flags & RI_MOUSE_RIGHT_BUTTON_UP)   SendMiddleClick(false);
                }
            }
            delete[] lpb;
        }
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

int main() {
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = TEXT("RawInputDemo");
    RegisterClass(&wc);

    HWND hwnd = CreateWindow(wc.lpszClassName, TEXT("Raw Input Window"),
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
        300, 200, NULL, NULL, wc.hInstance, NULL);

    RAWINPUTDEVICE rid;
    rid.usUsagePage = 0x01;
    rid.usUsage = 0x02;
    rid.dwFlags = RIDEV_INPUTSINK;
    rid.hwndTarget = hwnd;
    RegisterRawInputDevices(&rid, 1, sizeof(rid));

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}
4
  • Side note, changing the "default" expected mouse input behavior away from normal might surprise your users a lot. I recommend you don't do this at all. Commented Sep 22 at 8:00
  • Use WinMain instead of main. Commented Sep 22 at 9:56
  • Raw Input is fast and can monitor input, but not reject it. A low-level hook is slow, but it can filter input from being passed to the system for further processing. Commented Sep 22 at 12:02
  • Autohotkey is an open source tool written in C++. You can have a look on their source code to see how they solved this problem and get some inspiration. Though it may require some search to find the related pieces for the mouse handling. Commented Sep 23 at 9:33

1 Answer 1

2

Don't bother with raw input. Replace WM_RBUTTONDOWN with WM_MBUTTONDOWN:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    if (msg == WM_RBUTTONDOWN) {
        return DefWindowProc(hwnd, WM_MBUTTONDOWN, wParam, lParam);
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

You may need to do the same with WM_RBUTTONUP.

Sign up to request clarification or add additional context in comments.

1 Comment

The question is asking for a way to do this system-wide (not just for a single window).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.