The ZBuffer - Managed DirectX resources
Search ZBuffer
Links


 

The current recommendation from Microsoft regarding gamepads is to use the simpler XInput API where ever possible. However, if your game also needs to support gamepads which do not support XInput then you have a choice of options:

  1. Use DirectInput for all gamepads. Some capabilities of XInput controllers will not be available.
  2. Choose to only support XInput controllers in your game
  3. Use XInput for controllers that support it and DirectInput for the rest.

The problem with #3 is that there is that DirectInput will see all the controllers as DirectInput devices and there is no DirectInput functionality to detect which controllers are also XInput devices. Microsoft provided code in the December 2005 SDK to use WMI queries to make this detection but it is all in C++. The code below shows how to do the same thing in managed code.

One thing to note is the amazing efficiency of managed code here - I have improved upon the C++ code by using a WMI query rather than iterating though the device list in code but look at how little setup there is to call WMI.

The code should be pasted into a console project with references to the Managed DirectX December beta and System.Management

using System;
using System.Text;

using Microsoft.DirectX.XInput;
using Microsoft.DirectX.DirectInput;

using System.Management;

namespace GamePad
{
    class Program
    {
        static void Main(string[] args)
        {
            //Enumerate the XInput devices...
            Console.WriteLine("XInput devices....");
            for (int controller = 0; controller < 4; controller++)
            {
                State state = Controller.GetState(controller);
                if (state.IsConnected)
                {
                    Console.WriteLine("XInput Controller " + controller.ToString());
                }
            }

            //Enumerate the DirectInput devices
            Console.WriteLine("\nDirectInput devices (not including XInput devices)....");
            foreach (DeviceInstance instance in Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly))
            {
                //We need to ignore any that are really XInput devices
                if (!isXInput(instance.Product)) //Pass in the *product* guid *NOT* instance guid because that won't work and 
                                                 //you will waste half an hour of your life that you will never get back
                {
                    Console.WriteLine(instance.ProductName);
                }
            }

            Console.WriteLine("\nPress a key to quit.");
            Console.ReadKey();
        }

        private static bool isXInput(Guid product)
        {
            //Query WMI for any plug and play devices with IG_ in their device name, this identifies XInputDevices
            //See http://msdn.microsoft.com/library/?url=/library/en-us/directx9_c/dx9_xinput_xinput_dinput.asp for original C++ code 
            //See http://www.microsoft.com/technet/scriptcenter/topics/win2003/like.mspx for how to use LIKE in WMI queries
            //See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/like_operator.asp for how to escape the 
            //_ character in WMI queries (hint - its not the same as SQL)
            ManagementObjectSearcher mos = new ManagementObjectSearcher("select DeviceID from Win32_PNPEntity where DeviceID like '%IG[_]%' ");
            foreach (ManagementObject mo in mos.Get())
            {
                //Example of what this query will return
                //   USB\VID_045E&PID_028E&IG_00\7&3A2AF9C4&0&00
                //   HID\VID_045E&PID_028E&IG_00\8&4FD6AF3&0&0000
                //Interesting note that the C++ original code doesn't distinguish between these 2 entries, it just compares the 1st one that it finds.

                //Algorithm:
                //Take the PID_ value as the 1st 4 characters and the VID_ value as the 2nd 4 characters and compare to the 1st 
                //8 characters of the GUID when converted to a hex string
                //  e.g. From above 028E045E
                //The C++ converts the string to an int to match the GUID, we will convert the GUID to a string to compare - same difference
                string deviceId = mo["DeviceID"].ToString();
                string vidPid = deviceId.Substring(deviceId.IndexOf("PID_") + 4, 4) + deviceId.Substring(deviceId.IndexOf("VID_") + 4, 4);

                if (vidPid.ToLower() == product.ToString().Substring(0, 8))  //Assumes Guid.ToString uses lower case which it seems to
                {
                    return true;
                }
            }

            return false;
        }
    }
}

Updated 2/6/2006 10:30:00 AM by Zman