Supporting advanced joysticks.

I got DirectInput working with SharpDX in MonoGame! @StainlessTobii and @MuntyScruntFundle, if you want to try this out, I recommend MonoGame 3.7.1 or newer, as I’ve only tested on 3.7.1 and 3.8.

-Open Visual Studio (I used the 2017 version) and your existing MonoGame Windows Project, or make a new one.
-Make sure you’re connected to the Internet, then go to Tools>NuGet Package Manager>Package Manager Console. The console will appear at the bottom of your VS window, replacing Output/Build/Debug.
-If you’re using a MonoGame Shared Project, make sure the console’s “Default project” is your WindowsDX project.
-Paste the following into the console and press Enter:
Install-Package SharpDX.DirectInput -Version 4.0.1
-You now have DInput! You can use the following complete code to test it out. I named my project DInputTest:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SharpDX.DirectInput;
using System;
using Keyboard = Microsoft.Xna.Framework.Input.Keyboard;
using Mouse = Microsoft.Xna.Framework.Input.Mouse;

namespace DInputTest
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        //DirectInput vars, partially copied from online sources
        DirectInput directInput = new DirectInput(); // Initialize DirectInput
        Guid gamepadGuid = Guid.Empty, joystickGuid = Guid.Empty; //there may be DInput gamepads out there (Logitech Dual Action Gamepad?), let's test for them
        SharpDX.DirectInput.Joystick joystick;
        bool noDInputsConnected = false, pressed = false;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            DInputChecker(); //this can be called from Update() as well whenever the user may have plugged in a new joystick, maybe good for the Options menu
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            if (!noDInputsConnected)
            {
                try
                {
                    joystick.Poll(); //ask the joystick for input
                    var state = joystick.GetCurrentState(); //return the state of all buttons, axes, etc.
                    if(state.Buttons[0]) pressed = true; else pressed = false;
                }
                catch {} //catches any odd SharpDX errors
            }

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            //Simple way to demonstrate that the joystick is connected without SpriteFonts:
            if(!pressed)
                GraphicsDevice.Clear(Color.CornflowerBlue); //standard blue background means Button 0 is not being pressed
            else
                GraphicsDevice.Clear(Color.Yellow); //light up to show that Button 0 has been read and is being pressed!

            base.Draw(gameTime);
        }

        private void DInputChecker()
        {
            foreach (var deviceInstance in directInput.GetDevices(DeviceType.Gamepad, DeviceEnumerationFlags.AllDevices)) //look for connected DInput gamepads
                gamepadGuid = deviceInstance.InstanceGuid;
            foreach (var deviceInstance in directInput.GetDevices(DeviceType.Joystick, DeviceEnumerationFlags.AllDevices)) //if, or even if none found, look for DInput joysticks
                joystickGuid = deviceInstance.InstanceGuid;

            if (gamepadGuid != Guid.Empty || joystickGuid != Guid.Empty)
            {
                noDInputsConnected = false;
                joystick = new SharpDX.DirectInput.Joystick(directInput, joystickGuid);
                joystick.Properties.BufferSize = 128; //allocate a buffer to hold the device's state
                joystick.Acquire(); //do this for every joystick that's plugged in, the user may have multiple joysticks plugged in
            }
            else
                noDInputsConnected = true; //if this variable did not exist, the game would crash when 0 joysticks are connected
        }
    }
}

Of course, this is just an example and you’ll want to check if more than one joystick is connected in a real game.

Two other caveats I’m aware of, one of which is fixed in the code at lines 6 & 7:

  1. Adding SharpDX.DirectInput creates ambiguity between i.e. “Microsoft.Xna.Framework.Input.Keyboard” and “SharpDX.DirectInput.Keyboard”. I recommend including those using statements at the top to associate Keyboard and Mouse only with XNA’s handling.
  2. On 3.7.1 at least, this reference can add several seconds to the game’s startup time compared to not using SharpDX.DirectInput in the project. On my mid-range PC from 2015, it adds about 5 seconds of Windows’ spinning cursor before the game opens.
1 Like