如何在WinUI 3应用中锁定鼠标位置实现3D物体旋转
解决方案
CapturePointer仅负责捕获指针事件,不会限制光标物理移动或隐藏光标。要实现锁定光标位置+隐藏光标的需求,需要结合Win32 API控制光标行为,同时在指针移动时重置光标位置。
步骤1:引入Win32 API声明
在窗口类中添加以下DllImport声明,用于直接控制系统光标:
[DllImport("user32.dll")] private static extern bool SetCursorPos(int X, int Y); [DllImport("user32.dll")] private static extern bool ShowCursor(bool bShow); [DllImport("user32.dll")] private static extern bool GetCursorPos(out POINT lpPoint); // 辅助结构体,用于存储光标坐标 [StructLayout(LayoutKind.Sequential)] private struct POINT { public int X; public int Y; }
步骤2:添加状态变量
在MainWindow类中添加变量,记录光标锁定状态和初始锁定位置:
private bool _isCursorLocked = false; private POINT _lockedCursorPos;
步骤3:修改指针事件处理逻辑
替换原有事件代码,实现光标锁定、重置、隐藏的完整逻辑:
public MainWindow() { InitializeComponent(); View3dControl.PointerPressed += View3dControl_PointerPressed; View3dControl.PointerMoved += View3dControl_PointerMoved; View3dControl.PointerReleased += View3dControl_PointerReleased; View3dControl.PointerExited += View3dControl_PointerExited; // 处理光标意外移出面板的情况 } private void View3dControl_PointerPressed(object sender, PointerRoutedEventArgs e) { var panel = (SwapChainPanel)sender; // 捕获指针,确保事件仅由当前面板接收 panel.CapturePointer(e.Pointer); // 记录当前光标在屏幕上的位置 GetCursorPos(out _lockedCursorPos); // 隐藏系统光标 ShowCursor(false); _isCursorLocked = true; e.Handled = true; } private void View3dControl_PointerMoved(object sender, PointerRoutedEventArgs e) { if (!_isCursorLocked) return; // 获取当前光标位置 GetCursorPos(out POINT currentPos); // 计算光标移动偏移量,用于控制3D物体旋转 int deltaX = currentPos.X - _lockedCursorPos.X; int deltaY = currentPos.Y - _lockedCursorPos.Y; // 此处添加你的3D物体旋转逻辑,示例: // Rotate3DObject(deltaX * 0.1f, deltaY * 0.1f); // 强制将光标重置回初始锁定位置,避免光标移动到屏幕边界 SetCursorPos(_lockedCursorPos.X, _lockedCursorPos.Y); e.Handled = true; } private void View3dControl_PointerReleased(object sender, PointerRoutedEventArgs e) { var panel = (SwapChainPanel)sender; panel.ReleasePointerCapture(e.Pointer); // 恢复光标显示 ShowCursor(true); _isCursorLocked = false; e.Handled = true; } // 可选:光标意外移出面板时,强制恢复正常状态 private void View3dControl_PointerExited(object sender, PointerRoutedEventArgs e) { if (_isCursorLocked) { ShowCursor(true); _isCursorLocked = false; ((SwapChainPanel)sender).ReleasePointerCapture(null); } }
关键说明
SetCursorPos强制重置光标位置,解决屏幕边界限制问题ShowCursor控制光标显示/隐藏,提升3D操作的沉浸感deltaX/deltaY是旋转3D物体的核心输入,可根据需求乘以灵敏度系数调整旋转速度PointerExited事件处理用于避免光标意外移出面板后无法恢复的异常情况
内容的提问来源于stack exchange,提问作者Peter Grundmann
相关产品推荐
相关产品推荐

