如何通过SharpDX DirectInput检测游戏摇杆上的滑块?
解决SharpDX.DirectInput判断摇杆实际滑块数量的问题
我太懂这个坑了——DirectInput的JoystickState.Sliders数组不管设备有没有实际滑块,都会硬返回两个元素的数组,靠值是否为0判断根本不靠谱(毕竟真滑块也可能停在0位),反射的路子还容易抛异常。正确的做法是直接查询设备硬件定义的输入对象,从根源上确认哪些滑块是真实存在的。
核心思路
DirectInput设备的所有可输入元素都能通过GetObjects方法枚举,我们只需要筛选出属于「滑块」类型的对象,就能准确拿到设备实际的滑块数量,以及每个滑块对应的硬件偏移量,完全避开预设数组的干扰。
具体实现代码
先写个工具方法来获取设备的真实滑块列表:
using SharpDX.DirectInput; using System.Collections.Generic; using System.Linq; public List<DeviceObjectInstance> GetActualSliders(Joystick joystick) { // 枚举设备所有轴类输入对象,筛选出滑块类型的元素 return joystick.GetObjects(DeviceObjectTypeFlags.Axis) .Where(obj => obj.UsagePage == HIDUsagePage.Generic && obj.Usage == HIDUsage.GenericSlider) .ToList(); }
然后把你代码里原来靠Sliders数组值判断的逻辑替换掉:
// 移除原来的if (currentState.Sliders[0] != 0 || ...) 代码块,替换成以下内容 var actualSliders = GetActualSliders(usbjoysticks[k]); joystickmap.jsSliders = new int[actualSliders.Count]; for (int i = 0; i < actualSliders.Count; i++) { var sliderObj = actualSliders[i]; // 直接通过硬件ID读取对应滑块的当前值 int sliderValue = currentState.GetAxisById(sliderObj.ObjectId); if (i == 0) { joystickmap.SLD1 = "Slider1"; joystickmap.sld1 = sliderValue; // 获取该滑块的范围最大值 var sliderProps = usbjoysticks[k].GetObjectPropertiesById(sliderObj.ObjectId); joystickmap.axisRangeMax = sliderProps.Range.Maximum; } else if (i == 1) { joystickmap.SLD2 = "Slider2"; joystickmap.sld2 = sliderValue; } joystickmap.jsSliders[i] = sliderValue; }
为什么这个方法靠谱?
- 直接从设备的硬件描述中查询滑块,完全不依赖
JoystickState的预设数组,彻底避免了“假0值”的误判。 - 能准确获取实际存在的滑块数量,不管是0个、1个还是2个(甚至更多特殊设备的情况)。
- 每个滑块对应的
ObjectId可以直接用来读取状态,比依赖Sliders[0]/Sliders[1]更精准。
额外延伸
如果需要判断其他轴(比如Z轴、旋转轴)是否真实存在,也可以用同样的思路,只需要替换对应的Usage值:
- Z轴:
obj.Usage == HIDUsage.GenericZ - X旋转轴:
obj.Usage == HIDUsage.GenericRx - Y旋转轴:
obj.Usage == HIDUsage.GenericRy - Z旋转轴:
obj.Usage == HIDUsage.GenericRz
这样你就能彻底抛弃原来靠状态值是否为0的判断逻辑,再也不会出现误判了。
内容的提问来源于stack exchange,提问作者taterfudge
相关产品推荐
相关产品推荐

