Supporting advanced joysticks.

Hi all,

I need to be able to support joysticks like the Saitek Rhino.

At the moment Monogame does not even detect one is connected yet I have no problem working with the joystick outside of Monogame.

Is there a way of getting to Xinput directly and writing my own handlers?

If I cannot add support for devices like this, I am going to have to drop Monogame. It’s that important to me.

You won’t be able to interface with joysticks with a DirectX project through the MG API. XInput won’t work because it’s for gamepads (and it’s what MG itself uses), but you could try using DirectInput. There’s a SharpDX package for it on NuGet.

If you create a MonoGame cross-platfrom desktop project, you can use the JoyStick API.

DirectInput is deprecated and no longer available on NuGet.

XInput is useless.

This is a real mess, looks like all support for anything other than a useless gamepad has been dropped.

There must be a way of doing it. Will dig deeper.

No.
Looks like Microshaft have done it again.

DirectInput — deprecated
XInput — gamepad only
Windows.Gaming.Input — UWP only

So my options are…

  1. Stop developing games for windows
  2. Spend months writing HID code for every device I want to support.

Brilliant…

Option 1 sound good now.

Just in case anyone else is watching this thread.

Do not try to use NuGet to install DirectInput.

It install version 4 of sharpdx which kills Monogame.

Even removing it with NuGet leaves your project broken. You have to manually edit the packages file and copy the sharpds dll’s by hand to get it back.

1 Like

Doesn’t sdl2 support joysticks itself ?
I would ask this on the github page for monogame and open it as a issue.

Yes SDL does support joysticks (using DInput on Windows), that’s why I said:
“If you create a MonoGame cross-platfrom desktop project, you can use the JoyStick API.”

@Jjagg can’t do a cross platform game. My terrain rendering is very directx

I have solved the problem by downloading and rewriting a HID library.

Using this I am able to poll the joystick and receive an array of bytes back.

The mapping for the X56 Rhino stick is…

    /// <summary>
    /// Byte 0 - 3 Joystick position 16 bit centre 8000
    /// Byte 4 - 5  Joystick twist position 12 bit centre 800
    /// Byte 5 top 4 bits POV 8 directions
    /// Byte 6 
    /// Bit  1 = Fire
    /// Bit  2 = A button
    /// Bit  4 = B button
    /// Bit  8 = Thumbstick depressed
    /// Bit  16 = 
    /// Bit  32 = Pinky
    /// Bit  64 = H1 Up
    /// Bit 128 = H1 right
    /// Byte 7
    /// Bit  1 = H1 down
    /// Bit  2 = H1 left
    /// Bit  4 = H2 up
    /// Bit  8 = H2 right
    /// Bit 16 = H2 down
    /// Bit 32 = H2 left
    /// Bit 64 = 
    /// Bit 128 =
    /// Byte 9 and 10 Thumbstick position (8 bit centre 80)

I am now moving on to the Throttle, damn that’s a lot of buttons to process though

Mapping for the throttle module, annoyingly the mode wheel does nothing

///


/// Byte 0 Left throttle 0 = forward
/// Byte 1 - 2 Right throttle 12 bits 0 = forward
///
/// Byte 2
/// Bit 16 E button
/// Bit 128 I button
///
/// Byte 3
/// Bit 1 H button
/// Bit 2 Sw1
/// Bit 4 Sw2
/// Bit 8 Sw3
/// Bit 16 Sw4
/// Bit 32 Sw5
/// Bit 64 Sw6
/// Bit 128 tgl 1 up
///
/// Byte 4
/// Bit 1 tgl 1 down
/// Bit 2 tgl 2 up
/// Bit 4 tgl 2 down
/// Bit 8 tgl 3 up
/// Bit 16 tgl 3 down
/// Bit 32 tgl 4 up
/// Bit 64 tgl 4 down
/// Bit 128 H3 up
///
/// Byte 5
/// Bit 1 H3 forward
/// Bit 2 H3 down
/// Bit 4 H3 back
/// Bit 8 H4 up
/// Bit 16 H4 forward
/// Bit 32 H4 down
/// Bit 64 h4 back
///
/// Bit 128 K1 up
///
/// Byte 6
/// Bit 1 K1 down
/// Bit 2 Click wheel up
/// Bit 4 Click wheel down
/// Bit 16 SLD forward
///
/// Byte 7 Wheel F
/// Byte 8 Thumbstick X
/// Byte 9 Wheel g
/// Byte 10 Thumbstick Y
/// Byte 11 RTY 4
/// Byte 12 RTY 3
///
///

Has anyone got a working example for getting this joystick input working? I’m also using a Rhino x56 and would really like to get this control into a game.

I’m not interested in cross platform, Windows only.

Many thanks.

I have support for the x56, but I cannot upload zip files here.

Guys what’s the approved way to share code ?

Okay so I realised I had a generic system already on my website

http://southseagamesgurus.co.uk/downloads.html

HID device handling for Monogame

I got DirectInput working with SharpDX in MonoGame! @StainlessTobii, if you want to try this out, make sure your code works with MonoGame 3.7.1, as that’s what I tested with.

-Open Visual Studio (I used the 2017 version) and either make a new MonoGame Windows Project or use your existing 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.
-Make sure the “Default project” is set to your WindowsDX project. This should only change if you’re using a MonoGame Shared 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;

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; //it's unlikely there are DInput gamepads, but test for it anyway
        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 || Microsoft.Xna.Framework.Input.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 with 0 joysticks 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 demonstrated in the code at line 44:

  1. Adding SharpDX.DirectInput creates ambiguity between i.e. “Microsoft.Xna.Framework.Input.Keyboard” and “SharpDX.DirectInput.Keyboard”. I recommend using XNA’s handling for everything except DirectInput devices.
  2. This 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.