WPF+SharpDX.DirectInput:如何监听摇杆状态变化替代轮询
解决SharpDX.DirectInput摇杆状态监听的CPU占用问题
SharpDX.DirectInput并没有提供类似Android的onStateChange()这类回调监听器,要替代高CPU占用的无限轮询,你可以用后台线程+可控延迟轮询的方案,既保证摇杆状态的响应性,又能大幅降低CPU使用率。
核心改进点
- 用后台线程执行轮询逻辑,避免阻塞WPF的UI线程
- 在轮询循环中加入短延迟(比如16ms,对应约60次/秒的轮询频率),减少CPU空转
- 通过WPF的
Dispatcher在后台线程中安全更新UI元素
修改后的完整代码
using System; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using SharpDX.DirectInput; namespace TestJoystick { public partial class MainWindow : Window { private Joystick joystick; private Slider slider; private TextBox textBox; public MainWindow() { InitializeComponent(); // 提前获取UI元素,避免重复FindName slider = (Slider)this.FindName("slider"); textBox = (TextBox)this.FindName("textBox"); // 初始化摇杆 joystick = InitJoystick(); // 启动后台轮询线程 Task.Run(() => PollJoystickState()); } private void PollJoystickState() { while (true) { try { joystick.Poll(); var datas = joystick.GetBufferedData(); foreach (var data in datas) { // 这里以X轴为例,根据你的摇杆轴类型调整 if (data.Offset == JoystickOffset.X) { // 将摇杆值映射到Slider的范围(假设Slider范围是0-100) // 摇杆X轴通常范围是-32768到32767,转换为0-100的比例 var mappedValue = ((data.Value + 32768) / 65535.0) * slider.Maximum; // 通过Dispatcher安全更新UI Dispatcher.Invoke(() => { slider.Value = mappedValue; textBox.Text = ((int)mappedValue).ToString(); }); } } // 加入16ms延迟,降低轮询频率,减少CPU占用 System.Threading.Thread.Sleep(16); } catch (SharpDX.SharpDXException ex) { // 处理摇杆断开等异常 if (ex.ResultCode == SharpDX.DirectInput.ResultCode.NotAcquired || ex.ResultCode == SharpDX.DirectInput.ResultCode.InputLost) { try { joystick.Acquire(); } catch { } } } } } private void OnSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { textBox.Text = ((int)e.NewValue).ToString(); } private Joystick InitJoystick() { var directInput = new DirectInput(); var joystickGuid = Guid.Empty; // 查找游戏手柄 foreach (var deviceInstance in directInput.GetDevices(DeviceType.Gamepad, DeviceEnumerationFlags.AllDevices)) joystickGuid = deviceInstance.InstanceGuid; // 没找到的话查找摇杆 if (joystickGuid == Guid.Empty) { foreach (var deviceInstance in directInput.GetDevices(DeviceType.Joystick, DeviceEnumerationFlags.AllDevices)) joystickGuid = deviceInstance.InstanceGuid; } if (joystickGuid == Guid.Empty) { MessageBox.Show("未找到摇杆/游戏手柄"); Environment.Exit(1); } var joystick = new Joystick(directInput, joystickGuid); Console.WriteLine($"找到设备,GUID: {joystickGuid}"); // 设置缓冲区大小 joystick.Properties.BufferSize = 128; joystick.Acquire(); return joystick; } } }
额外说明
- 延迟时间可以根据需求调整:16ms对应60Hz,33ms对应30Hz,平衡响应速度和CPU占用
- 要根据你的实际摇杆轴(X/Y/Z等)调整
data.Offset的判断逻辑 - 加入了异常处理,应对摇杆突然断开等情况,自动尝试重新获取设备
内容的提问来源于stack exchange,提问作者Yuan
相关产品推荐
相关产品推荐

