Capture buttons pressed in video game control reliably

I want to use an XBox controller to control a program. It's not a game, it's just an application Windows Forms. I don't want to use XNA because I don't want to force the Redistributables to be downloaded when I'm using my application on another machine.

I'm doing some experiments messing with DirectX, using some libraries that encapsulate it. From the documentation, it seems to me that there is no button tightening event.

So I'm looking for a alternative. I tried using a timer (with Class System.Windows.Forms.Timer ), in whose event I read the state of the control like this:

private void timer_tick(object sender, EventArgs e)
{
    State s = controller.GetState();
    stateLabel.Text = s.Gamepad.Buttons == GamepadButtonFlags.A ? "A" : "";
}

Problem: between two runs of this method, I have no way of knowing if the user pressed the button twice, or if he was holding the button the whole time. Even using the packet number information sent by the control does not help, because a packet is sent to the smallest contact with the analog directional or with the triggers on the shoulders of control.

Does anyone know of a more reliable way to do this?

 8
Author: Maniero, 2014-03-23

1 answers

Instead of implementing this on a timer, why not use another thread, and continuously check the state of the control, firing an event in the form when a button is pressed and when it is released.

Form Code:

public partial class FormWithExternalEvents : Form
{
    private GamepadEvents gpe;

    public FormWithExternalEvents()
    {
        InitializeComponent();
    }

    protected override void OnLoad(EventArgs e)
    {
        gpe = new GamepadEvents();
        gpe.JoystickButtonDown += b =>
        {
            if (this.InvokeRequired) this.Invoke((GamepadButtonEvent) gpe_JoystickButtonDown);
            else gpe_JoystickButtonDown(b);
        };
        gpe.JoystickButtonUp += b =>
        {
            if (this.InvokeRequired) this.Invoke((GamepadButtonEvent)gpe_JoystickButtonUp);
            else gpe_JoystickButtonUp(b);
        };
        var thread = new Thread(gpe.Run);
        thread.Start();

        base.OnLoad(e);
    }

    void gpe_JoystickButtonUp(SharpDX.XInput.GamepadButtonFlags button)
    {
        throw new NotImplementedException();
    }

    void gpe_JoystickButtonDown(SharpDX.XInput.GamepadButtonFlags button)
    {
        throw new NotImplementedException();
    }
}

Code of the class that will be running on another thread:

public delegate void GamepadButtonEvent(GamepadButtonFlags button);

public class GamepadEvents
{
    public event GamepadButtonEvent JoystickButtonUp;
    public event GamepadButtonEvent JoystickButtonDown;

    private bool[] buttonsBools = new bool[32];

    public void Run()
    {
        while (true)
        {
            var controller = new Controller();
            State s = controller.GetState();

            ButtonSignal(0, GamepadButtonFlags.DPadUp, (s.Gamepad.Buttons & GamepadButtonFlags.DPadUp) != 0);
            ButtonSignal(1, GamepadButtonFlags.DPadDown, (s.Gamepad.Buttons & GamepadButtonFlags.DPadDown) != 0);
            ButtonSignal(2, GamepadButtonFlags.DPadLeft, (s.Gamepad.Buttons & GamepadButtonFlags.DPadLeft) != 0);
            ButtonSignal(3, GamepadButtonFlags.DPadRight, (s.Gamepad.Buttons & GamepadButtonFlags.DPadRight) != 0);
            ButtonSignal(4, GamepadButtonFlags.Start, (s.Gamepad.Buttons & GamepadButtonFlags.Start) != 0);
            ButtonSignal(5, GamepadButtonFlags.Back, (s.Gamepad.Buttons & GamepadButtonFlags.Back) != 0);
            ButtonSignal(6, GamepadButtonFlags.LeftThumb, (s.Gamepad.Buttons & GamepadButtonFlags.LeftThumb) != 0);
            ButtonSignal(7, GamepadButtonFlags.RightThumb, (s.Gamepad.Buttons & GamepadButtonFlags.RightThumb) != 0);
            ButtonSignal(8, GamepadButtonFlags.LeftShoulder, (s.Gamepad.Buttons & GamepadButtonFlags.LeftShoulder) != 0);
            ButtonSignal(9, GamepadButtonFlags.RightShoulder, (s.Gamepad.Buttons & GamepadButtonFlags.RightShoulder) != 0);
            ButtonSignal(10, GamepadButtonFlags.A, (s.Gamepad.Buttons & GamepadButtonFlags.A) != 0);
            ButtonSignal(11, GamepadButtonFlags.B, (s.Gamepad.Buttons & GamepadButtonFlags.B) != 0);
            ButtonSignal(12, GamepadButtonFlags.X, (s.Gamepad.Buttons & GamepadButtonFlags.X) != 0);
            ButtonSignal(13, GamepadButtonFlags.Y, (s.Gamepad.Buttons & GamepadButtonFlags.Y) != 0);

            Thread.Sleep(1);
        }
    }

    private void ButtonSignal(int btnIdx, GamepadButtonFlags gamepadButton, bool pressed)
    {
        bool wasPressed = buttonsBools[btnIdx];
        buttonsBools[btnIdx] = pressed;

        if (wasPressed && !pressed)
            this.JoystickButtonUp(gamepadButton);

        if (!wasPressed && pressed)
            this.JoystickButtonDown(gamepadButton);
    }
}
 5
Author: Miguel Angelo, 2014-03-24 17:41:22