C# joystick tracking via winmm.dll

Some code that I made to test how (and if) getting joystick\gamepad state via winmm would work in C#.
Contains required structs, functions, and fallback to joyGetPos if joyGetPosEx does not work for some reason.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security;

namespace One
{
    public partial class Form1 : Form
    {
        private const String WINMM_NATIVE_LIBRARY = "winmm.dll";
        private const CallingConvention CALLING_CONVENTION = CallingConvention.StdCall;
        //
        [StructLayout(LayoutKind.Sequential)]
        public struct JOYINFOEX
        {
            public Int32 dwSize; // Size, in bytes, of this structure.
            public Int32 dwFlags; // Flags indicating the valid information returned in this structure.
            public Int32 dwXpos; // Current X-coordinate.
            public Int32 dwYpos; // Current Y-coordinate.
            public Int32 dwZpos; // Current Z-coordinate.
            public Int32 dwRpos; // Current position of the rudder or fourth joystick axis.
            public Int32 dwUpos; // Current fifth axis position.
            public Int32 dwVpos; // Current sixth axis position.
            public Int32 dwButtons; // Current state of the 32 joystick buttons (bits)
            public Int32 dwButtonNumber; // Current button number that is pressed.
            public Int32 dwPOV; // Current position of the point-of-view control (0..35,900, deg*100)
            public Int32 dwReserved1; // Reserved; do not use.
            public Int32 dwReserved2; // Reserved; do not use.
        }
        //
        [StructLayout(LayoutKind.Sequential)]
        public struct JOYINFO
        {
            public Int32 wXpos; // Current X-coordinate.
            public Int32 wYpos; // Current Y-coordinate.
            public Int32 wZpos; // Current Z-coordinate.
            public Int32 wButtons; // Current state of joystick buttons.
        }
        //
        [DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
        public static extern Int32 joyGetNumDevs();
        [DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
        public static extern Int32 joyGetPos(Int32 uJoyID, ref JOYINFO pji);
        [DllImport(WINMM_NATIVE_LIBRARY, CallingConvention = CALLING_CONVENTION), SuppressUnmanagedCodeSecurity]
        public static extern Int32 joyGetPosEx(Int32 uJoyID, ref JOYINFOEX pji);
        //
        public JOYINFO js = new JOYINFO();
        public JOYINFOEX jsx = new JOYINFOEX();
        public Boolean joyEx = false;
        public Int32 joyId = 0;
        public Form1() {
            InitializeComponent();
            for (Int32 i = 0, l = joyGetNumDevs(); i < l; i++ ){
                if (joyGetPos(i, ref js) == 0) {
                    joyId = i;
                    joyEx = false;
                }
                if (joyGetPosEx(i, ref jsx) == 0) {
                    joyId = i;
                    joyEx = true;
                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            Int32 result, i = joyId;
            if (joyEx) {
                result = joyGetPosEx(joyId, ref jsx);
                if (result != 0) return;
                label1.Text = "(getPosEx)"
                    + "\nButtons: " + jsx.dwButtons.ToString()
                    + "\nX: " + jsx.dwXpos.ToString()
                    + "\nY: " + jsx.dwYpos.ToString()
                    + "\nZ: " + jsx.dwZpos.ToString();
            } else {
                result = joyGetPos(i, ref js);
                if (result != 0) return;
                label1.Text = "(getPos)"
                    + "\nButtons: " + js.wButtons.ToString()
                    + "\nX: " + js.wXpos.ToString()
                    + "\nY: " + js.wYpos.ToString()
                    + "\nZ: " + js.wZpos.ToString();
            }

        }
    }
}
 

Related posts:

4 thoughts on “C# joystick tracking via winmm.dll

    • Seemingly you’re also meant to “initialize” JOYINFOEX structure by setting it’s dwFlags after creation. Flag values can be found at relevant MSDN article.
      Looking at the code now, I’m not completely sure how JoyGetPosEx worked for me when writing this post. Might have been luck.

      • You also have to initialize dwSize, passing the size of the struct in bytes or EX will always fail.

        In the constructor:
        jsx.dwSize = (UInt32)Marshal.SizeOf(typeof(JOYINFOEX)); // size should be 52 bytes, 14x 4 byte DWORDs

        Also, all the Int32’s in your structs should be UInt32, because it expects an unsigned DWORD.

        As for the flags, I can’t figure out how to access those from C#… Passing nothing for dwFlags seems to cause it to return some data, but since I can’t figure out the binary values of the flags, I can’t set them specifically.

        • Hi, these flags are taken from mmsystem.h.
          const uint JOY_RETURNX = 1;
          const uint JOY_RETURNY = 2;
          const uint JOY_RETURNZ = 4;
          const uint JOY_RETURNR = 8;
          const uint JOY_RETURNU = 16;
          const uint JOY_RETURNV = 32;
          const uint JOY_RETURNPOV= 64;
          const uint JOY_RETURNBUTTONS= 128;
          const uint JOY_RETURNALL = (JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNR | JOY_RETURNU | JOY_RETURNV | JOY_RETURNPOV | JOY_RETURNBUTTONS);

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.