MSDN TV Holiday Episode III, WinFX, and XBOX 360

Don Box's Spoutlet

Syndication

ChrisAn and I filmed the third annual MSDN TV episode yesterday at my house.  The first two episodes are here and here.
 
In addition to the usual mix of code, song, and holiday cheer, this one included the must-have WinFX accessory this season: an XBOX 360 controller.
 
Even if you don't have an XBOX 360, you owe it to yourself to go pick up a controller and program it from DirectX 9.0.
 
Here's the managed code for talking to the controller, including the ability to ramp up force feedback for that special vibrating action every WinFX app needs.
 
namespace Microsoft.XInput
{
    using System;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
 
    public enum XInputDeviceType : byte
    {
        GamePad = 1
    }
    public enum XInputDeviceSubtype : byte
    {
        GamePad = 1
    }
    [Flags]
    public enum XInputCapabilityFlags : ushort
    {
        VoiceSupported = 4
    }
 
    [Flags]
    public enum XInputButtons : ushort
    {
        DPadUp = 0x1,
        DPadDown = 0x2,
        DPadLeft = 0x4,
        DPadRight = 0x8,
        Start = 0x10,
        Back = 0x20,
        LeftThumb = 0x40,
        RightThumb = 0x80,
        LeftShoulder = 0x100,
        RightShoulder = 0x200,
        A = 0x1000,
        B = 0x2000,
        X = 0x4000,
        Y = 0x8000
    }
 
    [Serializable]
    public struct XInputCapabilities
    {
        public XInputDeviceType Type;
        public XInputDeviceSubtype SubType;
        public XInputCapabilityFlags Flags;
        public XInputGamepad Gamepad;
        public XInputVibration Vibration;
 
        public override string ToString()
        {
            return string.Format("({0} {1} {2} {3} {4})", Type, SubType, Flags, Gamepad, Vibration);
        }
    }
 
    [Serializable]
    public struct XInputGamepad
    {
        public XInputButtons Buttons;
        public byte LeftTrigger;
        public byte RightTrigger;
        public short LeftThumbX;
        public short LeftThumbY;
        public short RightThumbX;
        public short RightThumbY;
 
        public bool IsAButtonDown
        {
            get { return (Buttons & XInputButtons.A) != 0; }
        }
        public bool IsBButtonDown
        {
            get { return (Buttons & XInputButtons.B) != 0; }
        }
        public bool IsXButtonDown
        {
            get { return (Buttons & XInputButtons.X) != 0; }
        }
        public bool IsYButtonDown
        {
            get { return (Buttons & XInputButtons.Y) != 0; }
        }
        public bool IsStartButtonDown
        {
            get { return (Buttons & XInputButtons.Start) != 0; }
        }
        public bool IsBackButtonDown
        {
            get { return (Buttons & XInputButtons.Back) != 0; }
        }
        public bool IsDPadLeftButtonDown
        {
            get { return (Buttons & XInputButtons.DPadLeft) != 0; }
        }
        public bool IsDPadRightButtonDown
        {
            get { return (Buttons & XInputButtons.DPadRight) != 0; }
        }
        public bool IsDPadUpButtonDown
        {
            get { return (Buttons & XInputButtons.DPadUp) != 0; }
        }
        public bool IsDPadDownButtonDown
        {
            get { return (Buttons & XInputButtons.DPadDown) != 0; }
        }
 
        public bool IsLeftShoulderButtonDown
        {
            get { return (Buttons & XInputButtons.LeftShoulder) != 0; }
        }
 
        public bool IsRightShoulderButtonDown
        {
            get { return (Buttons & XInputButtons.RightShoulder) != 0; }
        }
 

        public override bool Equals(object obj)
        {
            if (obj is XInputGamepad)
                return this.Equals((XInputGamepad)obj);
            return false;
        }
 
        public override int GetHashCode()
        {
            return (int)Buttons + LeftTrigger + RightTrigger;
        }
 
        public bool Equals(XInputGamepad rhs)
        {
            return
                Buttons == rhs.Buttons
                && LeftTrigger == rhs.LeftTrigger
                && RightTrigger == rhs.RightTrigger
                && LeftThumbX == rhs.LeftThumbX
                && LeftThumbY == rhs.LeftThumbY
                && RightThumbX == rhs.RightThumbX
                && RightThumbY == rhs.RightThumbY;
        }
 
        public override string ToString()
        {
            return string.Format("({0} {1} {2} {3} {4} {5} {6})", Buttons, LeftTrigger, RightTrigger, LeftThumbX, LeftThumbY, RightThumbX, RightThumbY);
        }
    }
 
    [Serializable]
    public struct XInputState
    {
        public uint PacketNumber;
        public XInputGamepad Gamepad;
 
        public bool Equals(XInputState rhs)
        {
            return PacketNumber == rhs.PacketNumber
                    && Gamepad.Equals(rhs.Gamepad);
        }
 
        public override bool Equals(object obj)
        {
            if (obj is XInputState)
                return this.Equals((XInputState)obj);
            return false;
        }
 
        public override int GetHashCode()
        {
            return (int)PacketNumber;
        }
 
        public override string ToString()
        {
            return string.Format("({0} {1})", PacketNumber, Gamepad);
        }
    }
 
    [Serializable]
    public struct XInputVibration
    {
        public ushort LeftMotorSpeed;
        public ushort RightMotorSpeed;
 
        public XInputVibration(ushort left, ushort right)
        {
            this.LeftMotorSpeed = left;
            this.RightMotorSpeed = right;
        }
    }
 

    public static class XInputMethods
    {
        // Get the capabilities of controller 0, 1, 2, or 3
        public static void GetCapabilities(int controllerNumber, out XInputCapabilities caps)
        {
            XInputMethods.ProcessResult(
                XInputMethods.XInputGetCapabilities(controllerNumber, 0, out caps)
                );
        }
 
        // Poll the state of the controller's buttons, thumbsticks, and triggers
        public static void GetState(int controllerNumber, out XInputState state)
        {
            XInputMethods.ProcessResult(
                XInputMethods.XInputGetState(controllerNumber, out state)
                );
        }
 
        // Set the vibration speed of a controller
        public static void SetVibration(int controllerNumber, ushort leftSpeed, ushort rightSpeed)
        {
            XInputVibration vibe = new XInputVibration(leftSpeed, rightSpeed);
            XInputMethods.ProcessResult(
                XInputMethods.XInputSetState(controllerNumber, ref vibe)
                );
        }
 
        // Get the DirectSound guids for sending/receiving audio to the controller's headset
        public static void GetAudioGuids(int controllerNumber, out Guid renderGuid, out Guid captureGuid)
        {
            XInputMethods.ProcessResult(XInputMethods.XInputGetDSoundAudioDeviceGuids(controllerNumber, out renderGuid, out captureGuid));
        }
 
 
 
        static void ProcessResult(uint err)
        {
            if (err != 0)
                throw new Win32Exception((int)err);
        }
 

        const string DllName = "XInput9_1_0.dll";
 
        [DllImport(DllName)]
        extern static uint XInputGetState(
            int index,  // [in] Index of the gamer associated with the device
            out XInputState state // [out] Receives the current state
        );
 
        [DllImport(DllName)]
        extern static uint XInputSetState(
            int index,  // [in] Index of the gamer associated with the device
            ref XInputVibration vibration// [in, out] The vibration information to send to the controller
        );
 
        [DllImport(DllName)]
        extern static uint XInputGetCapabilities(
            int dwUserIndex,   // [in] Index of the gamer associated with the device
            uint dwFlags,       // [in] Input flags that identify the device type
            out XInputCapabilities capabilities  // [out] Receives the capabilities
        );
 
        [DllImport(DllName)]
        extern static uint XInputGetDSoundAudioDeviceGuids(
            int dwUserIndex,          // [in] Index of the gamer associated with the device
            out Guid soundRenderGuid,    // [out] DSound device ID for render
            out Guid SoundCaptureGuid    // [out] DSound device ID for capture
        );
    }
}

Posted Dec 10 2005, 02:50 PM by don-box

Comments

Mikael Söderström wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-10-2005 10:16 AM
Great!

When will it be uploaded?

Cheers,
Mikael Söderström
casey chesnut wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-10-2005 11:20 AM
hey Don, i did a .NET 1.1 wrapper over here to control my MediaCenter PC :

http://www.brains-N-brawn.com/mcexinput/
Alan Cobb wrote .NET-less Vista - Just a short-term hiccup or something worse?
on 12-10-2005 12:57 PM
Hi Don,

Any chance you could do a post responding to
Richard Grimes' latest articles questioning the
level of MS's commitment to .NET?

(See: http://www.grimes.demon.co.uk/)

In particular he is alarmed by 1) how little .NET seems
to be used in the latest Vista Betas and 2) how he
seems an increasing amount of unmanaged code in .NET.

Before reading Richard's latest articles I had
performed a similar independent analysis of the
Vista 5231 beta, and was also bothered by how
little .NET seemed to be there.

Ironically some of the current UI of the Vista Beta
seems to be the best argument for why we need Avalon :).
For example, right clicking on the desktop brings up
the same kind of infuriatingly unscalable Display
Properties dialog. I had hoped Vista would be a
showcase for what Avalon was capable of.

Thanks,
Alan Cobb

www.alancobb.com
(I'm currently doing user group talks on .NET
debugging).
OPC Diary wrote XBOX 360 コントローラ入出力インターフェイス
on 12-10-2005 6:06 PM
MSDN TV Holiday Episode III, WinFX, and ...
Rob Burke wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-13-2005 8:35 AM
So cool :) :)

Couldn't resist, picked up a wired XBox360 controller and got it vibrating across the floor. Anyone else find that the left vibrator is a lot stronger than the right one?

Rob
casey chesnut wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-14-2005 6:08 AM
regarding motor strength, from the documentation : "Note that the right motor is the high-frequency motor, the left motor is the low-frequency motor. They do not always need to be set to the same amount, as they provide different effects."
Minh wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-19-2005 10:45 AM
I seem to be having some trouble with viewing the video. The visual is great, but the audio is shifting half an octave up or down at random interval. Especially at the end. Can someone help? Cool stuff though.

BTW, that's probably the worse CAPTCHA I've ever seen.

Nishith Pathak wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-25-2005 7:59 PM
Video is really great

regards
Nishith Pathak
droid wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-27-2005 11:12 AM
What about the MIDI code? I only watched the video to see how that would go in managed code - guess it does not without interop.
Robert Swirsky wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-27-2005 1:26 PM
Great episode! I can't wait to try it on my Disklavier C-7 Pro!
天空 息乐园 wrote Microsoft免费软件列表(5) - Microsoft Hardware Drivers
on 01-23-2006 7:54 PM
&lt;span id=&quot;_ctl2_lblPermalink&quot;&gt;&lt;p&gt;&lt;font size=&quot;1&quot; face=&quot;Tahoma&quot;&gt;&lt;span style=&quot;font-size: 8.5pt; font-family: Tahoma;&quot;&gt;Even though you won’t find these files listed in the <strong>&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;a href=&quot;http://www.m</strong> ...
Miquel Moncunill wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 01-25-2006 1:28 AM
Me gustaria actualizar mi sistema operativo ya que la ultima vez que tuve reinstalar el sistema Windows XP fue en una empresa de reparaciones de PC's y no esta registrado y tampoco dispongo de dico para realizar mis actualizaciones. Los que tenia auyenticos con su codigo y numeración los extravie y no puedo recuperarlos. Que haria Uds. sin tener que gastar dinero. Afectuosamente: Mikel Moncunill
Font wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 02-28-2006 4:22 AM
What is the font name that you are using in the VS 2005 in this demo?
Don Box wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 03-16-2006 6:21 AM
Consolas was the font.

It ships with Vista.
Travis Pettijohn wrote Program the XBox 360 Controller
on 09-08-2006 12:10 PM
Don Box posted
some managed code to interface with the XBox 360 Controller on Windows.
Interesting....
Arunaa wrote re: MSDN TV Holiday Episode III, WinFX, and XBOX 360
on 12-20-2006 3:13 PM
Truly exciting, motivating and inspiring!! Am looking at similar out of the box ways to use WinFX with Windows.Thanks!
Full Xbox 360 Gamepad Support In C#, Without XNA | The Instruction Limit wrote Full Xbox 360 Gamepad Support In C#, Without XNA | The Instruction Limit
on 06-30-2009 8:17 AM

Pingback from  Full Xbox 360 Gamepad Support In C#, Without XNA | The Instruction Limit

Add a Comment

(required)  
(optional)
(required)  
Remember Me?