Question:
I want to use an XBox control to control a program. It's not a game, it's just a Windows Forms application. I don't want to use XNA because I don't want to force download the redistributables when using my application on another machine.
I'm experimenting with DirectX, using some libraries that encapsulate it. From the documentation, it seems to me that there is no button press event.
So I'm looking for an alternative. I've tried using a timer (with the System.Windows.Forms.Timer class), in whose event I read the control's state 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 has pressed the button twice, or if he has been holding the button the entire time. Even using the information of the number of the packet sent by the control does not help, because a packet is sent at the slightest contact with the analog sticks or with the triggers on the shoulders of the control.
Does anyone know of a more reliable way to do this?
Answer:
Instead of implementing this in a timer, why not use another thread, and continuously check the state of the control, firing an event on 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();
}
}
Class code that will be running in 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);
}
}