Click here to Skip to main content
15,892,809 members
Articles / Multimedia / DirectX

Using XInput to access an Xbox 360 Controller in Managed Code

Rate me:
Please Sign up or sign in to vote.
4.58/5 (9 votes)
11 Nov 2012CPOL8 min read 81.2K   5.9K   21  
Using the XInput library to interface with the Xbox 360 controller.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace J2i.Net.XInputWrapper
{
    public class XboxController
    {
        int _playerIndex;
        static bool keepRunning;
        static int  updateFrequency;
        static int waitTime;
        static bool isRunning;
        static object SyncLock;
        static Thread pollingThread;

        bool _stopMotorTimerActive;
        DateTime _stopMotorTime;
        XInputBatteryInformation _batteryInformationGamepad;
        XInputBatteryInformation _batterInformationHeadset;
        //XInputCapabilities _capabilities;

        XInputState gamepadStatePrev = new XInputState();
        XInputState gamepadStateCurrent = new XInputState();

        public static int UpdateFrequency
        {
            get { return updateFrequency; }
            set
            {
                updateFrequency = value;
                waitTime = 1000 / updateFrequency;
            }
        }

        public XInputBatteryInformation BatteryInformationGamepad
        {
            get { return _batteryInformationGamepad; }
            internal set  {  _batteryInformationGamepad = value;   }
        }

        public XInputBatteryInformation BatteryInformationHeadset
        {
            get { return _batterInformationHeadset; }
            internal set  {  _batterInformationHeadset = value;   }
        }

        public const int MAX_CONTROLLER_COUNT = 4;
        public const int FIRST_CONTROLLER_INDEX = 0;
        public const int LAST_CONTROLLER_INDEX = MAX_CONTROLLER_COUNT-1;

        static XboxController[] Controllers;
        

        static XboxController()
        {
            Controllers = new XboxController[MAX_CONTROLLER_COUNT];
            SyncLock = new object();
            for (int i = FIRST_CONTROLLER_INDEX; i <= LAST_CONTROLLER_INDEX; ++i)
            {
                Controllers[i] = new XboxController(i);
            }
            UpdateFrequency = 25;
        }

        public event EventHandler<XboxControllerStateChangedEventArgs> StateChanged = null;

        public static XboxController RetrieveController(int index)
        {
            return Controllers[index];
        }

        private XboxController(int playerIndex)
        {
            _playerIndex = playerIndex;
            gamepadStatePrev.Copy(gamepadStateCurrent);
        }

        public void UpdateBatteryState()
        {
            XInputBatteryInformation headset = new XInputBatteryInformation(),
            gamepad = new XInputBatteryInformation();

            XInput.XInputGetBatteryInformation(_playerIndex, (byte)BatteryDeviceType.BATTERY_DEVTYPE_GAMEPAD, ref gamepad);
            XInput.XInputGetBatteryInformation(_playerIndex, (byte)BatteryDeviceType.BATTERY_DEVTYPE_HEADSET, ref headset);

            BatteryInformationHeadset = headset;
            BatteryInformationGamepad = gamepad;
        }

        protected void OnStateChanged()
        {
            if (StateChanged != null)
                StateChanged(this, new XboxControllerStateChangedEventArgs() { CurrentInputState = gamepadStateCurrent, PreviousInputState = gamepadStatePrev });
        }

        public XInputCapabilities GetCapabilities()
        {
            XInputCapabilities capabilities = new XInputCapabilities();
            XInput.XInputGetCapabilities(_playerIndex, XInputConstants.XINPUT_FLAG_GAMEPAD, ref capabilities);
            return capabilities;
        }


        #region Digital Button States
        public bool IsDPadUpPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_DPAD_UP); }
        }

        public bool IsDPadDownPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_DPAD_DOWN); }
        }

        public bool IsDPadLeftPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_DPAD_LEFT); }
        }

        public bool IsDPadRightPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_DPAD_RIGHT); }
        }

        public bool IsAPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_A); }
        }

        public bool IsBPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_B); }
        }

        public bool IsXPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_X); }
        }

        public bool IsYPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_Y); }
        }


        public bool IsBackPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_BACK); }
        }


        public bool IsStartPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_START); }
        }


        public bool IsLeftShoulderPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_LEFT_SHOULDER); }
        }


        public bool IsRightShoulderPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_RIGHT_SHOULDER); }
        }

        public bool IsLeftStickPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_LEFT_THUMB); }
        }

        public bool IsRightStickPressed
        {
            get { return gamepadStateCurrent.Gamepad.IsButtonPressed((int)ButtonFlags.XINPUT_GAMEPAD_RIGHT_THUMB); }
        }
        #endregion

        #region Analogue Input States
        public int LeftTrigger
        {
            get { return (int)gamepadStateCurrent.Gamepad.bLeftTrigger;  }
        }

        public int RightTrigger
        {
            get  {  return (int)gamepadStateCurrent.Gamepad.bRightTrigger; }
        }

        public Point LeftThumbStick
        {
            get
            {
                Point p = new Point()
                {
                    X = gamepadStateCurrent.Gamepad.sThumbLX,
                    Y = gamepadStateCurrent.Gamepad.sThumbLY
                };
                return p;
            }
        }

        public Point RightThumbStick
        {
            get
            {
                Point p = new Point()
                {
                    X = gamepadStateCurrent.Gamepad.sThumbRX,
                    Y = gamepadStateCurrent.Gamepad.sThumbRY
                };
                return p;
            }
        }

        #endregion

        bool _isConnected;
        public bool IsConnected
        {
            get { return _isConnected; }
            internal set { _isConnected = value; }
        }

        #region Polling
        public static void StartPolling()
        {
            if (!isRunning)
            {
                lock (SyncLock)
                {
                    if (!isRunning)
                    {
                        pollingThread = new Thread(PollerLoop);
                        pollingThread.Start();
                    }
                }
            }
        }

        public static void StopPolling()
        {
            if (isRunning)
                keepRunning = false;
        }

        static void PollerLoop()
        {
            lock (SyncLock)
            {
                if (isRunning == true)
                    return;
                isRunning = true;
            }
            keepRunning = true;
            while(keepRunning)
            {
                for (int i = FIRST_CONTROLLER_INDEX; i <= LAST_CONTROLLER_INDEX; ++i)
                {
                    Controllers[i].UpdateState();
                }
                Thread.Sleep(updateFrequency);
            }
            lock (SyncLock)
            {
                isRunning = false;
            }
        }

        public void UpdateState()
        {
            XInputCapabilities X = new XInputCapabilities();
            int result = XInput.XInputGetState(_playerIndex, ref gamepadStateCurrent);
            IsConnected = (result == 0);
            
            UpdateBatteryState();
            if (gamepadStateCurrent.PacketNumber!=gamepadStatePrev.PacketNumber)
            {
                OnStateChanged();
            }
            gamepadStatePrev.Copy(gamepadStateCurrent);

            if (_stopMotorTimerActive && (DateTime.Now >= _stopMotorTime))
            {
                XInputVibration stopStrength = new XInputVibration() { LeftMotorSpeed = 0, RightMotorSpeed = 0 };
                XInput.XInputSetState(_playerIndex, ref stopStrength);
            }
        }
        #endregion

        #region Motor Functions
        public void Vibrate(double leftMotor, double rightMotor)
        {
            Vibrate(leftMotor, rightMotor, TimeSpan.MinValue);
        }

        public void Vibrate(double leftMotor, double rightMotor, TimeSpan length)
        {
            leftMotor = Math.Max(0d, Math.Min(1d, leftMotor));
            rightMotor = Math.Max(0d, Math.Min(1d, rightMotor));

            XInputVibration vibration = new XInputVibration() { LeftMotorSpeed = (ushort)(65535d * leftMotor), RightMotorSpeed = (ushort)(65535d * rightMotor) };
            Vibrate(vibration, length);
        }
        

        public void Vibrate(XInputVibration strength)
        {
            _stopMotorTimerActive = false;
            XInput.XInputSetState(_playerIndex, ref strength);
        }

        public void Vibrate(XInputVibration strength, TimeSpan length)
        {
            XInput.XInputSetState(_playerIndex, ref strength);
            if (length != TimeSpan.MinValue)
            {
                _stopMotorTime = DateTime.Now.Add(length);
                _stopMotorTimerActive = true;
            }
        }
        #endregion
      
        public override string ToString()
        {
            return _playerIndex.ToString();
        }

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
I attended Southern Polytechnic State University and earned a Bachelors of Science in Computer Science and later returned to earn a Masters of Science in Software Engineering. I've largely developed solutions that are based on a mix of Microsoft technologies with open source technologies mixed in. I've got an interest in astronomy and you'll see that interest overflow into some of my code project articles from time to time.



Twitter:@j2inet

Instagram: j2inet


Comments and Discussions