You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 15:22:19