C#双屏触摸场景下用LowLevelMouseProc阻止触摸转鼠标及光标跳转问题求助
问题根因
你当前使用的LowLevelMouseHook仅能拦截上层窗口分发的模拟鼠标消息,Windows触摸输入栈会在输入预处理阶段直接修改系统光标位置,该操作不走Hook监听的消息流,因此只能拦截后续点击消息,无法阻止光标跳转至触摸位置,导致后续真实鼠标点击触发在触摸坐标上。
可行实现方案
通过缓存真实鼠标坐标+触摸时强制复位光标的逻辑即可解决,具体实现如下:
- 提前引入需要的Win32 API声明:
[DllImport("user32.dll")] static extern bool SetCursorPos(int X, int Y); [DllImport("user32.dll")] static extern bool GetCursorPos(out Point lpPoint); // 补充需要用到的常量定义 private const int WM_MOUSEMOVE = 0x0200; private const int WM_LBUTTONDOWN = 0x0201; private const int WM_RBUTTONDOWN = 0x0204; private const ulong MOUSEEVENTF_FROMTOUCH = 0xFF515700; private const ulong MOUSEEVENTF_MASK = 0xFFFFFF00;
- 新增两个全局变量存储状态:
// 存储真实鼠标操作的最后坐标 private static Point _lastRealMousePos; // 标记当前是否正在处理触摸输入 private static bool _isProcessingTouch = false;
- 修改Hook回调逻辑,增加光标复位逻辑:
static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) { if (nCode >= 0) { var info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); var extraInfo = (ulong)info.dwExtraInfo.ToInt64(); // 检测为触摸产生的模拟鼠标事件 if ((extraInfo & MOUSEEVENTF_MASK) == MOUSEEVENTF_FROMTOUCH) { _isProcessingTouch = true; // 强制将光标复位到上一次真实鼠标的位置,覆盖系统自动修改的触摸坐标 SetCursorPos(_lastRealMousePos.X, _lastRealMousePos.Y); // 拦截消息不再向下分发 return new IntPtr(1); } else { // 真实鼠标操作时更新缓存坐标 if (wParam == (IntPtr)WM_MOUSEMOVE || wParam == (IntPtr)WM_LBUTTONDOWN || wParam == (IntPtr)WM_RBUTTONDOWN) { if (!_isProcessingTouch) { GetCursorPos(out _lastRealMousePos); } // 触摸结束后重置状态标记 _isProcessingTouch = false; } } } return UnsafeNativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam); }
注意事项
- 程序需要以管理员权限运行,否则LowLevelMouseHook可能没有足够权限拦截所有系统级消息
- 如果需要兼容笔输入,可以增加额外的
extraInfo判断逻辑,仅过滤触摸输入,不要屏蔽笔操作 - 如果上述方案仍存在偶发的光标跳转问题,可以改用Windows原始输入API(Raw Input)处理,该API优先级高于LowLevelHook,可直接从输入源头区分触摸、鼠标、笔等不同输入设备,完全规避系统模拟鼠标事件的干扰。
内容的提问来源于stack exchange,提问作者justsoso程序员
相关产品推荐
相关产品推荐

