Manually changing the mouse sensitivity with windows hooks

William Hemsworth 1 Tallied Votes 3K Views Share

Heres a code that allows you to manually change the sensitivity of the mouse by using windows hooks.

/*
 *  Make sure project type is windows application
 */

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

float sensitivity = 0.1f;


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

   // Let windows handle mouse clicks
   if (wParam != WM_MOUSEMOVE) {
      return CallNextHookEx(NULL, nCode, wParam, lParam);
   }

   // Get event information
   PMSLLHOOKSTRUCT p = reinterpret_cast<PMSLLHOOKSTRUCT>( lParam );

   // Old mouse location
   static float ox = static_cast<float>( p->pt.x );
   static float oy = static_cast<float>( p->pt.y );

   // Mouse location without sensitivity changed
   float x = static_cast<float>( p->pt.x );
   float y = static_cast<float>( p->pt.y );
   
   // New mouse location
   float nx = ox + (x - ox) * sensitivity;
   float ny = oy + (y - oy) * sensitivity;

   // Set cursor position
   SetCursorPos(
      static_cast<int>( nx ),
      static_cast<int>( ny )
   );

   // Set old location ready for next time
   ox = nx;
   oy = ny;

   return 1;
}

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

   // Set mouse hook
   HHOOK mouseHook = SetWindowsHookEx(
                  WH_MOUSE_LL,      /* Type of hook */
                  mouseHookProc,    /* Hook process */
                  hInstance,        /* Instance */
                  NULL);

   // Wait for user to exit
   MessageBox(NULL, "Press OK to close.", "", MB_OK);
   return 0;
}

Dani AI

Generated

Nice snippet, @William Hemsworth. Two quick hardening tips for anyone tweaking sensitivity via WH_MOUSE_LL:

  • Ignore your own injected moves to prevent feedback loops, and keep the hook fast. A minimal pattern is below. It scales the delta, posts a synthetic move, swallows the original, and skips any injected events to avoid jitter.
LRESULT CALLBACK mouseHookProc(int code, WPARAM wp, LPARAM lp) {
    if (code != HC_ACTION) return CallNextHookEx(NULL, code, wp, lp);
    const MSLLHOOKSTRUCT* m = reinterpret_cast<const MSLLHOOKSTRUCT*>(lp);
    if (m->flags & LLMHF_INJECTED) return CallNextHookEx(NULL, code, wp, lp);

    static POINT last = m->pt;
    if (wp == WM_MOUSEMOVE) {
        const double scale = 1.5;              // your sensitivity
        double dx = (m->pt.x - last.x) * (scale - 1.0);
        double dy = (m->pt.y - last.y) * (scale - 1.0);
        if (dx || dy) {
            INPUT in{}; in.type = INPUT_MOUSE;
            in.mi.dx = (LONG)lround(dx); in.mi.dy = (LONG)lround(dy);
            in.mi.dwFlags = MOUSEEVENTF_MOVE;
            SendInput(1, &in, sizeof(in));
            last = m->pt;
            return 1; // consume original
        }
        last = m->pt;
    }
    return CallNextHookEx(NULL, code, wp, lp);
}

The hook runs on the thread that installed it, so you need a message loop and you should return quickly or Windows may remove the hook (LowLevelHooksTimeout). Low-level hooks are global and can be called alongside 32-bit/64-bit hooks in the chain. (learn.microsoft.com)

Build notes:

  • , your C2664 is Unicode vs ANSI. Either call MessageBoxW with wide literals (L"...") or wrap strings in TEXT() instead of disabling Unicode. The API aliases map MessageBox to A/W based on UNICODE, which is why the mismatch occurs. (learn.microsoft.com)
  • , rather than casting to HOOKPROC, ensure the exact signature: LRESULT CALLBACK mouseHookProc(int, WPARAM, LPARAM); This matches HOOKPROC across compilers. Also remember WH_MOUSE_LL callbacks are not injected into target processes. (learn.microsoft.com)

If you just want system-wide pointer speed, prefer SystemParametersInfo(SPI_SETMOUSESPEED) instead of a hook; and when synthesizing movement, use SendInput (supersedes mouse_event). (learn.microsoft.com)

William Hemsworth 1,339 Posting Virtuoso

Small bug when using a higher sensitivity, to fix it, add this function at the beginning. (line 10)

int round(float a) {
   return int(a + 0.5f);
}

and on line 36 & 37, change them to this.

round( nx ),
round( ny )

Now the mouse doesn't jump about unexpectedly.

mksafi 0 Newbie Poster

This doesn't even compile in Visual C++ Express.

1>c:\path\visual studio 2008\projects\two\two\two.cpp(63) : error C2664: 'MessageBoxW' : cannot convert parameter 2 from 'const char [19]' to 'LPCWSTR'

William Hemsworth 1,339 Posting Virtuoso

That's because you've not set up your compiler properly, don't blame the code. Turn off UNICODE then try compiling again.

CppBuilder2006 -5 Junior Poster

Thanks. I needed such a program!
but it has an error in my Borland compiler. to fix the error instead of:

HHOOK mouseHook = SetWindowsHookEx(
                  WH_MOUSE_LL,      /* Type of hook */
                 mouseHookProc,    /* Hook process */
                  hInstance,        /* Instance */
				  NULL);

write:

HHOOK mouseHook = SetWindowsHookEx(
                  WH_MOUSE_LL,      /* Type of hook */
                  (HOOKPROC)mouseHookProc,    /* Hook process */
                  hInstance,        /* Instance */
				  NULL);

And do you have a program for hooking keyboard? or the shell?

Freaky_Chris 299 Master Poster

@CppBuilder

I'd recommend getting an upto date compiler. You might find that they work properly then ;)

CppBuilder2006 -5 Junior Poster

I'd recommend getting an upto date compiler

I have a 2006 version! ;)

William Hemsworth 1,339 Posting Virtuoso

And do you have a program for hooking keyboard? or the shell?

Look at my other snippets, indeed I do ;]

I dont mind any changes people make to the code if it makes it compatiable with a wider range of compilers.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.