使用C# .NET从游戏手柄接收输入信号

28

我在谷歌上搜索了这个问题,但是找到的所有内容都过时了并且无法使用。

请问有没有关于如何使用C# .NET获取游戏手柄数据的信息?


写那个的人是我的朋友。他说它不能在现代.NET上运行。我正在通过即时通讯与他交谈。 - chris12892
我从来没有编写过操纵杆作为接口设备的程序,但作为一个用户,我的理解是操纵杆控制映射到键盘和鼠标控制(例如:当我为HL2配置我的Logitech USB PS2风格控制器时,我将控制器上的每个按钮映射到一个键或鼠标按钮)。 - Brian Driscoll
1
多么讽刺啊,5年后的今天,当我谷歌同样的问题时,我发现这个问题提到已过时且不起作用。 :| - Spiked3
2
9年过去了,这仍然非常相关。有更新吗?我不想再次发布同样的问题。我正在使用罗技F710无线控制器。 - A. Vieira
5个回答

33

由于这是我在研究C#中的操纵杆/游戏手柄输入时在谷歌上得到的最佳结果,所以我认为我应该发布一个回复供其他人查看。

我发现的最简单的方法是使用SharpDX和DirectInput。您可以通过NuGet(SharpDX.DirectInput)安装它。

之后,只需要调用几个方法:

从SharpDX获取的示例代码

static void Main()
{
    // Initialize DirectInput
    var directInput = new DirectInput();

    // Find a Joystick Guid
    var joystickGuid = Guid.Empty;

    foreach (var deviceInstance in directInput.GetDevices(DeviceType.Gamepad, 
                DeviceEnumerationFlags.AllDevices))
        joystickGuid = deviceInstance.InstanceGuid;

    // If Gamepad not found, look for a Joystick
    if (joystickGuid == Guid.Empty)
        foreach (var deviceInstance in directInput.GetDevices(DeviceType.Joystick, 
                DeviceEnumerationFlags.AllDevices))
            joystickGuid = deviceInstance.InstanceGuid;

    // If Joystick not found, throws an error
    if (joystickGuid == Guid.Empty)
    {
        Console.WriteLine("No joystick/Gamepad found.");
        Console.ReadKey();
        Environment.Exit(1);
    }

    // Instantiate the joystick
    var joystick = new Joystick(directInput, joystickGuid);

    Console.WriteLine("Found Joystick/Gamepad with GUID: {0}", joystickGuid);

    // Query all suported ForceFeedback effects
    var allEffects = joystick.GetEffects();
    foreach (var effectInfo in allEffects)
        Console.WriteLine("Effect available {0}", effectInfo.Name);

    // Set BufferSize in order to use buffered data.
    joystick.Properties.BufferSize = 128;

    // Acquire the joystick
    joystick.Acquire();

    // Poll events from joystick
    while (true)
    {
        joystick.Poll();
        var datas = joystick.GetBufferedData();
        foreach (var state in datas)
            Console.WriteLine(state);
    }
}

我希望这可以帮到你。

我甚至成功地使用了DualShock3和MotioninJoy驱动程序。


2
这是最容易实现的。谢谢! - Jerdine Sabio

13

一:使用SlimDX

二:它看起来像这样(其中GamepadDevice是我的包装器,代码简化为仅涉及相关部分)。

查找游戏手柄/手柄的GUID:

    public virtual IList<GamepadDevice> Available()
    {
        IList<GamepadDevice> result = new List<GamepadDevice>();
        DirectInput dinput = new DirectInput();
        foreach (DeviceInstance di in dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly))
        {
            GamepadDevice dev = new GamepadDevice();
            dev.Guid = di.InstanceGuid;
            dev.Name = di.InstanceName;
            result.Add(dev);
        }
        return result;
    }

用户从列表中选择后,获取游戏手柄:

   private void acquire(System.Windows.Forms.Form parent)
    {
        DirectInput dinput = new DirectInput();

        pad = new Joystick(dinput, this.Device.Guid);
        foreach (DeviceObjectInstance doi in pad.GetObjects(ObjectDeviceType.Axis))
        {
            pad.GetObjectPropertiesById((int)doi.ObjectType).SetRange(-5000, 5000);
        }

        pad.Properties.AxisMode = DeviceAxisMode.Absolute;
        pad.SetCooperativeLevel(parent, (CooperativeLevel.Nonexclusive | CooperativeLevel.Background));
        pad.Acquire();
    }
轮询手柄的代码如下所示:
        JoystickState state = new JoystickState();

        if (pad.Poll().IsFailure)
        {
            result.Disconnect = true;
            return result;
        }

        if (pad.GetCurrentState(ref state).IsFailure)
        {
            result.Disconnect = true;
            return result;
        }

        result.X = state.X / 5000.0f;
        result.Y = state.Y / 5000.0f;
        int ispressed = 0;
        bool[] buttons = state.GetButtons();

5
既然人们仍在阅读这个答案,我应该指出我后来切换到了RawInput:http://stackoverflow.com/a/12988935/184998 - Adrian Cox
到目前为止,我已经成功地完成了获取部分,我跳过了设置协作级别的调用。我使用的是Windows 7操作系统。在Stack Overflow上的其他答案说微软建议您使用RawInput而不是DirectInput。 - Maslow

4
谷歌将我带到这里,虽然这个问题不需要,但是在Windows和Linux(使用mono)上支持OpenTK是一个不错的选择。

根据OpenTK文档,以下代码适用于Raspberry Pi + Raspbian + Mono 3.12.0:

for (int i = 0; i < 4; i++)
{
    var state = Joystick.GetState(i);
    if (state.IsConnected)
    {
        float x = state.GetAxis(JoystickAxis.Axis0);
        float y = state.GetAxis(JoystickAxis.Axis1);

        // Print the current state of the joystick
        Console.WriteLine(state);
    }
}

2
在2020年仍然非常好用,与其他任何东西相比,这篇文章的工作如此轻松(但也因为OpenTK使其变得简单!) - Water

4
坏消息是,微软似乎停止支持他们的NET库用于DirectX,并开始专注于XNA。我不从事游戏开发,所以不需要使用XNA,但如果你正在开发计算机游戏,可以尝试一下。好消息是,还有其他方法。其中一个是SlimDX,这是一个新框架,可以帮助你使用C#处理DirectX。另一种方法是直接将“Microsoft.DirectX.dll”和“Microsoft.DirectX.DirectInput.dll”的引用添加到项目中。你可以在“..\Windows\Microsoft.NET\DirectX for Managed Code\”中找到它们。如果你要使用后一种方法,请查看codeproject链接,了解如何使用操纵杆。 编辑: 如果你的应用程序基于.NET版本高于2.0,则可能会出现卡顿问题。为解决此问题,请更改配置文件并添加以下内容:

<startup useLegacyV2RuntimeActivationPolicy="true"> 

0

这个问题虽然有点老,但似乎至今仍然活跃,所以我还是要发表一下意见。

如果你需要仅从XInput获取输入,请看看XInputium。这是一个专门针对XInput控制器的.NET库。它非常简单明了,并且有许多代码示例供您参考。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接