C# reading joystick input without blocking UI

4.1k views Asked by At

This will probably sound strange for some of you, but I can not figure out right way to read joystick input without blocking my UI form. I have found this example on internet:

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 have installed sharpdx and I can see joystick axis output in console.

Now I want to display each axis data in separate textbox on my UI. So I changed few lines of code:

joystick.Poll();
var data = joystick.GetBufferedData();
foreach (var state in data) 
{
    if (state.Offset == JoystickOffset.X)
    {
       textBox1.Text = state.Value.ToString();
    }
}

So this should pass data to textbox. If I write here Console.Writeline(state.Value) I will get data I want to display. Problem is, that this while loop blocks UI.

I would like to put this while loop in private void timer_tick and set maybe 10 milliseconds refresh rate. But I don't know how to access variables like var joystick in separate function. I have also read that this can be done with asynchronous programming. Sadly I am stuck now.

Can anybody help me with as simple solution as possible to this problem? Code example would be great.

1

There are 1 answers

0
kennyzx On BEST ANSWER

Suppose you code with WinForm (deduced from blocking my UI form in your question).

Add a timer to your Form from the designer.

And add these lines in the Form's .ctor:

public partial class JoyStickForm : Form
{
    public JoyStickForm()
    {
        InitializeComponent();

        // ...Other initialization code has been stripped...

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

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

        timer1.Interval = 100; 
        timer1.Tick += (s, e) =>
            {
                joystick.Poll();
                var lastState = joystick.GetBufferedData().Last(); //only show the last state

                if (lastState != null)
                {
                    if (lastState.Offset == JoystickOffset.X)
                    {
                        textBox1.Text = lastState.Value.ToString();
                    }
                }
            };

        //start the timer
        timer1.Enabled = true;
    }
}

Explanations:

  1. A refreshing rate of 100 times per second is unnecessarily fast, remember the refreshing rate of most monitors is about 60 Hz. I set it as 100 ms (10 refreshes per second), which is acceptable.

  2. Using lambda expression, you have access to the variables like var joystick from the timer's tick handler.

  3. In each freshing, only the last state in the data is displayed to the TextBox.