游戏场景鼠标减速代码实现及失效问题修复咨询
解决游戏中鼠标速度无法降低的问题
问题原因
你的代码通过SystemParametersInfo修改系统鼠标速度,但多数游戏会直接读取原始鼠标硬件输入(如Raw Input/DirectInput),完全绕过系统的鼠标速度缩放逻辑,导致系统层面的设置无法影响游戏内的鼠标移动。
修复方案
使用**低级全局鼠标钩子(LowLevelMouseHook)**拦截所有鼠标移动事件,手动调整鼠标的位移量,这种方式可以覆盖包括游戏在内的所有场景,因为它直接处理硬件级的鼠标输入。
修改后的完整代码
using System; using System.Runtime.InteropServices; using System.Windows.Forms; namespace MouseSpeedDesktop { public partial class Form1 : Form { // 钩子相关常量 private const int WH_MOUSE_LL = 14; private const int WM_MOUSEMOVE = 0x0200; // 钩子句柄 private IntPtr _mouseHookHandle = IntPtr.Zero; // 减速标志 private bool _isSpeedReduced = false; // 减速比例(比如设为0.3,就是原始速度的30%) private readonly float _speedReductionFactor = 0.3f; // 原始鼠标速度备份(用于恢复) private int _originalMouseSpeed; // 鼠标钩子结构体 [StructLayout(LayoutKind.Sequential)] private struct MSLLHOOKSTRUCT { public POINT pt; public uint mouseData; public uint flags; public uint time; public IntPtr dwExtraInfo; } [StructLayout(LayoutKind.Sequential)] private struct POINT { public int x; public int y; } // 导入钩子API [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern IntPtr GetModuleHandle(string lpModuleName); // 系统鼠标速度相关API(用于备份原始速度) private const UInt32 SPI_GETMOUSESPEED = 0x0070; private const UInt32 SPI_SETMOUSESPEED = 0x0071; [DllImport("User32.dll")] private static extern Boolean SystemParametersInfo( UInt32 uiAction, UInt32 uiParam, IntPtr pvParam, UInt32 fWinIni); // 钩子回调委托 private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); private LowLevelMouseProc _mouseProc; public Form1() { InitializeComponent(); // 备份原始鼠标速度 IntPtr speedPtr = Marshal.AllocHGlobal(4); SystemParametersInfo(SPI_GETMOUSESPEED, 0, speedPtr, 0); _originalMouseSpeed = Marshal.ReadInt32(speedPtr); Marshal.FreeHGlobal(speedPtr); } private void Form1_Load(object sender, EventArgs e) { // 注册全局鼠标钩子 _mouseProc = MouseHookCallback; using (var curProcess = System.Diagnostics.Process.GetCurrentProcess()) using (var curModule = curProcess.MainModule) { _mouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL, _mouseProc, GetModuleHandle(curModule.ModuleName), 0); } // 注册键盘钩子(用于触发减速/恢复) HookManager.KeyDown += KeyPressed; HookManager.KeyUp += KeyRemoved; } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // 释放钩子 UnhookWindowsHookEx(_mouseHookHandle); // 恢复原始鼠标速度 SystemParametersInfo(SPI_SETMOUSESPEED, 0, new IntPtr(_originalMouseSpeed), 0); // 注销键盘钩子 HookManager.KeyDown -= KeyPressed; HookManager.KeyUp -= KeyRemoved; } private void KeyPressed(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Q) { _isSpeedReduced = true; } } private void KeyRemoved(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Q) { _isSpeedReduced = false; } } private IntPtr MouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0 && wParam == (IntPtr)WM_MOUSEMOVE && _isSpeedReduced) { var hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); // 获取当前光标位置并按比例调整位移 Cursor.Position = new System.Drawing.Point( Cursor.Position.X + (int)((hookStruct.pt.x - Cursor.Position.X) * _speedReductionFactor), Cursor.Position.Y + (int)((hookStruct.pt.y - Cursor.Position.Y) * _speedReductionFactor) ); // 返回非0值拦截原始鼠标事件,避免重复移动 return (IntPtr)1; } // 传递事件给下一个钩子 return CallNextHookEx(_mouseHookHandle, nCode, wParam, lParam); } } }
关键说明
- 钩子拦截逻辑:通过
LowLevelMouseHook捕获所有鼠标移动事件,当_isSpeedReduced为true时,按比例缩放鼠标位移,手动设置光标位置并拦截原始事件,避免重复移动。 - 原始速度备份:程序启动时备份系统原始鼠标速度,退出时自动恢复,避免遗留设置影响日常使用。
- 减速比例调整:修改
_speedReductionFactor的值可以调整减速程度,比如0.2就是原始速度的20%,数值越小速度越慢。
注意事项
- 必须以管理员权限运行程序,否则可能无法拦截游戏的鼠标输入。
- 部分反作弊系统可能会检测全局钩子,使用前请确认游戏的反作弊政策,避免账号风险。
- 确保程序退出时正确释放钩子,否则可能导致系统鼠标异常(重启系统也可恢复)。
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

