Taking input from a joystick with C# .NET
Asked Answered
T

5

28

I searched around on Google for this, but the only things I came up with were outdated and did not work.

Does anyone have any information on how to get joystick data using C# .NET?

Tica answered 14/10, 2010 at 3:0 Comment(4)
The guy who wrote that is a friend of mine. He says it will not work with modern .NET. I'm talking to him over IM right now.Tica
I've never programmed for a joystick as an interface device, but my understanding as a user is that joystick controls map to keyboard and mouse controls (i.e.: when I configure my logitech USB PS2 style controller for HL2, I map each button on the controller to a key or mouse button)Hufuf
How Ironic, 5 years later, when I now google the same question, I find this question mentioning outdated and not working :|Wrand
9 years later and this is still quite pertinent. Any updates? I don't want to post the same question again. I'm using Logitech F710 wireless controller.Kevel
G
13

One: use SlimDX.

Two: it looks something like this (where GamepadDevice is my own wrapper, and the code is slimmed down to just the relevant parts).

Find the joystick / pad GUIDs:

    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;
    }

Once the user has selected from the list, acquire the gamepad:

   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();
    }

Polling the pad looks like this:

        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();
Glazing answered 9/3, 2011 at 15:50 Comment(2)
As people are still reading this answer, I should note that I later switched to RawInput: https://mcmap.net/q/503666/-slimdx-joystick-poll-succeeds-on-disconnected-gamepadGlazing
the part up to acquire works for me so far, I did skip the set cooperative level call. I'm on windows 7. answers elsewhere on SO say microsoft recommends you use RawInput instead of DirectInputPorta
E
33

Since this was the top hit I got on google while researching joystick / gamepad input in C#, I thought I should post a response for others to see.

The easiest way I found was to use SharpDX and DirectInput. You can install it via NuGet (SharpDX.DirectInput)

After that, it's simply a matter of calling a few methods:

Sample code from 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);
    }
}

I hope this helps.

I even got this to work with a DualShock3 and the MotioninJoy drivers.

Equisetum answered 5/12, 2012 at 23:58 Comment(1)
This is the easiest to implement. Thanks for this!Neisa
G
13

One: use SlimDX.

Two: it looks something like this (where GamepadDevice is my own wrapper, and the code is slimmed down to just the relevant parts).

Find the joystick / pad GUIDs:

    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;
    }

Once the user has selected from the list, acquire the gamepad:

   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();
    }

Polling the pad looks like this:

        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();
Glazing answered 9/3, 2011 at 15:50 Comment(2)
As people are still reading this answer, I should note that I later switched to RawInput: https://mcmap.net/q/503666/-slimdx-joystick-poll-succeeds-on-disconnected-gamepadGlazing
the part up to acquire works for me so far, I did skip the set cooperative level call. I'm on windows 7. answers elsewhere on SO say microsoft recommends you use RawInput instead of DirectInputPorta
C
4

The bad news is that Microsoft seems to stop supporting their NET libraries for DirectX and focus on XNA instead. I don't work in GameDev so I don't need to use XNA but you may try it if you developing computer games. The good news is that there are other approaches. One is SlimDX the new framework to help you to wok with DirectX from C#. The other way is to directly add references of "Microsoft.DirectX.dll" and "Microsoft.DirectX.DirectInput.dll" to your project. you can find them "..\Windows\Microsoft.NET\DirectX for Managed Code\". if you you are going to use last approach here is a link to codeproject where you can read how to work with a joystick.

EDIT: If your application is based on NET version newer then 2.0 the application may hang on. To fix this problem change config file and add this:

<startup useLegacyV2RuntimeActivationPolicy="true"> 
Caye answered 9/3, 2011 at 13:2 Comment(0)
E
4

Google led me here and while not a requirement of this question, OpenTK is a good option for Windows and Linux (under mono) support.

From the OpenTK docs, this code works on 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);
    }
}
Excision answered 14/2, 2015 at 10:5 Comment(1)
Still works great in 2020, this post worked so effortlessly compared to anything else (but also because OpenTK makes it simple too!)Biologist
M
1

This question is old, but it seems to be active even to this day, so I'm posting anyway.

If you need to get input from XInput only, take a look at XInputium. This is a .NET library that is specialized in XInput controllers. It is pretty straightforward, and has many code samples you can look at.

Marlenemarler answered 9/9, 2022 at 18:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.