Index: code/branches/kicklib2/src/external/ois/win32/Win32JoyStick.cpp
===================================================================
--- code/branches/kicklib2/src/external/ois/win32/Win32JoyStick.cpp	(revision 8282)
+++ code/branches/kicklib2/src/external/ois/win32/Win32JoyStick.cpp	(revision 8284)
@@ -21,11 +21,39 @@
     3. This notice may not be removed or altered from any source distribution.
 */
-#include "Win32/Win32JoyStick.h"
-#include "Win32/Win32InputManager.h"
-#include "Win32/Win32ForceFeedback.h"
+#include "win32/Win32JoyStick.h"
+#include "win32/Win32InputManager.h"
+#include "win32/Win32ForceFeedback.h"
 #include "OISEvents.h"
 #include "OISException.h"
 
+// (Orxonox): Required for MinGW to compile properly
+#ifdef __MINGW32__
+#  include <oaidl.h>
+#  ifndef __MINGW_EXTENSION
+#    define __MINGW_EXTENSION __extension__
+#  endif
+#endif
+
 #include <cassert>
+#include <wbemidl.h>
+#include <oleauto.h>
+//#include <wmsstd.h>
+#ifndef SAFE_RELEASE
+#define SAFE_RELEASE(x) \
+   if(x != NULL)        \
+   {                    \
+      x->Release();     \
+      x = NULL;         \
+   }
+#endif
+
+// (Orxonox): MinGW doesn't have swscanf_s
+#ifdef __MINGW32__
+#	define swscanf_s swscanf
+#endif
+
+#ifdef OIS_WIN32_XINPUT_SUPPORT
+#	pragma comment(lib, "xinput.lib")
+#endif
 
 //DX Only defines macros for the JOYSTICK not JOYSTICK2, so fix it
@@ -40,18 +68,18 @@
 #define DIJOFS_SLIDER3(n) (FIELD_OFFSET(DIJOYSTATE2, rglFSlider)+(n) * sizeof(LONG))
 
+#define XINPUT_TRANSLATED_BUTTON_COUNT 12
+#define XINPUT_TRANSLATED_AXIS_COUNT 6
+
 using namespace OIS;
 
 //--------------------------------------------------------------------------------------------------//
-Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI,
-	bool buffered, DWORD coopSettings, const JoyStickInfo &info )
-	: JoyStick(info.vendor, buffered, info.devId, creator)
-{
-	mDirectInput = pDI;
-	coopSetting = coopSettings;
-	mJoyStick = 0;
-
-	deviceGuid = info.deviceID;
-
-	ff_device = 0;
+Win32JoyStick::Win32JoyStick( InputManager* creator, IDirectInput8* pDI, bool buffered, DWORD coopSettings, const JoyStickInfo &info ) :
+	JoyStick(info.vendor, buffered, info.devId, creator),
+	mDirectInput(pDI),
+	coopSetting(coopSettings),
+	mJoyStick(0),
+	mJoyInfo(info),
+	mFfDevice(0)
+{
 }
 
@@ -59,5 +87,5 @@
 Win32JoyStick::~Win32JoyStick()
 {
-	delete ff_device;
+	delete mFfDevice;
 
 	if(mJoyStick)
@@ -69,9 +97,5 @@
 
 	//Return joystick to pool
-	JoyStickInfo js;
-	js.deviceID = deviceGuid;
-	js.devId = mDevID;
-	js.vendor = mVendor;
-	static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(js);
+	static_cast<Win32InputManager*>(mCreator)->_returnJoyStick(mJoyInfo);
 }
 
@@ -79,43 +103,45 @@
 void Win32JoyStick::_initialize()
 {
-	//Clear old state
-	mState.mAxes.clear();
-
-	if (ff_device)
-	{
-		delete ff_device;
-		ff_device = 0;
-	}
-
-	// Create direct input joystick device.
-	if(FAILED(mDirectInput->CreateDevice(deviceGuid, &mJoyStick, NULL)))
-		OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
-
-	// Set DIJoystick2 data format.
-	if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
-		OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
-
-	// Set cooperative level as specified when creating input manager.
-	HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
-	if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
-		OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
-
-	// Set buffer size.
-	DIPROPDWORD dipdw;
-	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
-	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
-	dipdw.diph.dwObj        = 0;
-	dipdw.diph.dwHow        = DIPH_DEVICE;
-	dipdw.dwData            = JOYSTICK_DX_BUFFERSIZE;
-
-	if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
-		OIS_EXCEPT( E_General, "Win32JoyStick::_initialize >> Failed to set buffer size property" );
-
-	// Enumerate all axes/buttons/sliders/force feedback/etc before aquiring
-	_enumerate();
-
-	mState.clear();
-
-	capture();
+    if (mJoyInfo.isXInput)
+    {
+        _enumerate();
+    }
+    else
+    {
+	    //Clear old state
+	    mState.mAxes.clear();
+
+	    delete mFfDevice;
+	    mFfDevice = 0;
+
+	    DIPROPDWORD dipdw;
+
+	    dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
+	    dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+	    dipdw.diph.dwObj        = 0;
+	    dipdw.diph.dwHow        = DIPH_DEVICE;
+	    dipdw.dwData            = JOYSTICK_DX_BUFFERSIZE;
+
+	    if(FAILED(mDirectInput->CreateDevice(mJoyInfo.deviceID, &mJoyStick, NULL)))
+		    OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> Could not initialize joy device!");
+
+	    if(FAILED(mJoyStick->SetDataFormat(&c_dfDIJoystick2)))
+		    OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> data format error!");
+
+	    HWND hwin = ((Win32InputManager*)mCreator)->getWindowHandle();
+
+	    if(FAILED(mJoyStick->SetCooperativeLevel( hwin, coopSetting)))
+		    OIS_EXCEPT( E_General, "Win32JoyStick::_initialize() >> failed to set cooperation level!");
+
+	    if( FAILED(mJoyStick->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)) )
+		    OIS_EXCEPT( E_General, "Win32Mouse::Win32Mouse >> Failed to set buffer size property" );
+
+	    //Enumerate all axes/buttons/sliders/etc before aquiring
+	    _enumerate();
+
+	    mState.clear();
+
+	    capture();
+    }
 }
 
@@ -123,24 +149,32 @@
 void Win32JoyStick::_enumerate()
 {
-	// Get joystick capabilities.
-	mDIJoyCaps.dwSize = sizeof(DIDEVCAPS);
-	if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) )
-		OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" );
-
-	// => Number of POVs
-	mPOVs = (short)mDIJoyCaps.dwPOVs;
-
-	// => Number of buttons and axes.
-	mState.mButtons.resize(mDIJoyCaps.dwButtons);
-	mState.mAxes.resize(mDIJoyCaps.dwAxes);
-
-	// Enumerate all Force Feedback effects (if any)
-	mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
-
-	//Reset the axis mapping enumeration value
-	_AxisNumber = 0;
-
-	// Enumerate and set axis constraints (and check FF Axes)
-	mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
+    if (mJoyInfo.isXInput)
+    {
+        mPOVs = 1;
+
+        mState.mButtons.resize(XINPUT_TRANSLATED_BUTTON_COUNT);
+	    mState.mAxes.resize(XINPUT_TRANSLATED_AXIS_COUNT);
+    }
+    else
+    {
+		// Get joystick capabilities.
+		mDIJoyCaps.dwSize = sizeof(DIDEVCAPS);
+		if( FAILED(mJoyStick->GetCapabilities(&mDIJoyCaps)) )
+			OIS_EXCEPT( E_General, "Win32JoyStick::_enumerate >> Failed to get capabilities" );
+
+	    mPOVs = (short)mDIJoyCaps.dwPOVs;
+
+	    mState.mButtons.resize(mDIJoyCaps.dwButtons);
+	    mState.mAxes.resize(mDIJoyCaps.dwAxes);
+
+	    //Reset the axis mapping enumeration value
+	    _AxisNumber = 0;
+
+	    //Enumerate Force Feedback (if any)
+	    mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
+
+	    //Enumerate and set axis constraints (and check FF Axes)
+	    mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
+    }
 }
 
@@ -191,7 +225,7 @@
 	if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
 	{
-		if( _this->ff_device )
+		if( _this->mFfDevice )
 		{
-			_this->ff_device->_addFFAxis();
+			_this->mFfDevice->_addFFAxis();
 		}
 	}
@@ -200,8 +234,8 @@
 	//as DInput has no API to query the device for these capabilities
 	//(the only way to know is to try them ...)
-	if( _this->ff_device )
-	{
-	    _this->ff_device->_setGainSupport(true);
-	    _this->ff_device->_setAutoCenterSupport(true);
+	if( _this->mFfDevice )
+	{
+	    _this->mFfDevice->_setGainSupport(true);
+	    _this->mFfDevice->_setAutoCenterSupport(true);
 	}
 
@@ -215,8 +249,8 @@
 
 	//Create the FF instance only after we know there is at least one effect type
-	if( _this->ff_device == 0 )
-	  _this->ff_device = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
-
-	_this->ff_device->_addEffectSupport( pdei );
+	if( _this->mFfDevice == 0 )
+		_this->mFfDevice = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
+
+	_this->mFfDevice->_addEffectSupport(pdei);
 
 	return DIENUM_CONTINUE;
@@ -226,4 +260,14 @@
 void Win32JoyStick::capture()
 {
+#ifdef OIS_WIN32_XINPUT_SUPPORT
+	//handle xbox controller differently
+    if (mJoyInfo.isXInput)
+	{
+		captureXInput();
+		return;
+	}
+#endif
+
+	//handle directinput based devices
 	DIDEVICEOBJECTDATA diBuff[JOYSTICK_DX_BUFFERSIZE];
 	DWORD entries = JOYSTICK_DX_BUFFERSIZE;
@@ -241,5 +285,5 @@
 
 		// Poll the device to read the current state
-	    mJoyStick->Poll();
+		mJoyStick->Poll();
 		hr = mJoyStick->GetDeviceData( sizeof(DIDEVICEOBJECTDATA), diBuff, &entries, 0 );
 		//Perhaps the user just tabbed away
@@ -353,4 +397,116 @@
 
 //--------------------------------------------------------------------------------------------------//
+void Win32JoyStick::captureXInput()
+{
+#ifdef OIS_WIN32_XINPUT_SUPPORT
+    XINPUT_STATE inputState;
+	if (XInputGetState((DWORD)mJoyInfo.xInputDev, &inputState) != ERROR_SUCCESS)
+        memset(&inputState, 0, sizeof(inputState));
+
+    //Sticks and triggers
+	int value;
+    bool axisMoved[XINPUT_TRANSLATED_AXIS_COUNT] = {false,false,false,false,false,false};
+
+	//LeftY
+	value = -(int)inputState.Gamepad.sThumbLY;
+	mState.mAxes[0].rel = value - mState.mAxes[0].abs;
+	mState.mAxes[0].abs = value;
+	if(mState.mAxes[0].rel != 0)
+        axisMoved[0] = true;
+
+	//LeftX
+    mState.mAxes[1].rel = inputState.Gamepad.sThumbLX - mState.mAxes[1].abs;
+    mState.mAxes[1].abs = inputState.Gamepad.sThumbLX;
+
+	if(mState.mAxes[1].rel != 0)
+        axisMoved[1] = true;
+
+	//RightY
+	value = -(int)inputState.Gamepad.sThumbRY;           
+    mState.mAxes[2].rel = value - mState.mAxes[2].abs;
+    mState.mAxes[2].abs = value;
+	if(mState.mAxes[2].rel != 0)
+        axisMoved[2] = true;
+
+	//RightX
+    mState.mAxes[3].rel = inputState.Gamepad.sThumbRX - mState.mAxes[3].abs;
+    mState.mAxes[3].abs = inputState.Gamepad.sThumbRX;
+	if(mState.mAxes[3].rel != 0)
+		axisMoved[3] = true;
+
+	//Left trigger
+    value = inputState.Gamepad.bLeftTrigger * 129;
+	if(value > JoyStick::MAX_AXIS)
+		value = JoyStick::MAX_AXIS;
+
+    mState.mAxes[4].rel = value - mState.mAxes[4].abs;
+    mState.mAxes[4].abs = value;
+	if(mState.mAxes[4].rel != 0)
+		axisMoved[4] = true;
+
+	//Right trigger
+    value = (int)inputState.Gamepad.bRightTrigger * 129;
+	if(value > JoyStick::MAX_AXIS)
+		value = JoyStick::MAX_AXIS;
+
+	mState.mAxes[5].rel = value - mState.mAxes[5].abs;
+    mState.mAxes[5].abs = value;
+	if(mState.mAxes[5].rel != 0)
+		axisMoved[5] = true;
+    
+    //POV
+    int previousPov = mState.mPOV[0].direction;        
+    int& pov = mState.mPOV[0].direction;
+    pov = Pov::Centered;        
+    if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP)
+        pov |= Pov::North;
+    else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN)
+        pov |= Pov::South;
+    if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT)
+        pov |= Pov::West;
+    else if (inputState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT)
+        pov |= Pov::East;
+    
+    //Buttons - The first 4 buttons don't need to be checked since they represent the dpad
+    bool previousButtons[XINPUT_TRANSLATED_BUTTON_COUNT];
+    std::copy(mState.mButtons.begin(), mState.mButtons.end(), previousButtons);
+    for (size_t i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
+        mState.mButtons[i] = (inputState.Gamepad.wButtons & (1 << (i + 4))) != 0;
+
+    //Send events
+    if (mBuffered && mListener)
+    {
+	    JoyStickEvent joystickEvent(this, mState);
+
+	    //Axes
+	    for (int i = 0; i < XINPUT_TRANSLATED_AXIS_COUNT; i++)
+        {
+		    if (axisMoved[i] && !mListener->axisMoved(joystickEvent, i))
+			    return;
+        }
+
+        //POV
+        if (previousPov != pov && !mListener->povMoved(joystickEvent, 0))
+            return;
+
+        //Buttons
+        for (int i = 0; i < XINPUT_TRANSLATED_BUTTON_COUNT; i++)
+        {
+            if (!previousButtons[i] && mState.mButtons[i])
+            {
+                if (!mListener->buttonPressed(joystickEvent, i))
+                    return;
+            }
+            else if (previousButtons[i] && !mState.mButtons[i])
+            {
+                if (!mListener->buttonReleased(joystickEvent, i))
+                    return;
+            }
+        }
+    }
+#endif
+}
+
+//--------------------------------------------------------------------------------------------------//
 bool Win32JoyStick::_doButtonClick( int button, DIDEVICEOBJECTDATA& di )
 {
@@ -410,10 +566,136 @@
 Interface* Win32JoyStick::queryInterface(Interface::IType type)
 {
-	//Thought about using covariant return type here.. however,
-	//some devices may allow LED light changing, or other interface stuff
-
-	if( ff_device && type == Interface::ForceFeedback )
-		return ff_device;
+	if( mFfDevice && type == Interface::ForceFeedback )
+		return mFfDevice;
 	else
 		return 0;
 }
+
+//--------------------------------------------------------------------------------------------------//
+void Win32JoyStick::CheckXInputDevices(JoyStickInfoList &joys)
+{
+    IWbemLocator*           pIWbemLocator  = NULL;
+    IEnumWbemClassObject*   pEnumDevices   = NULL;
+    IWbemClassObject*       pDevices[20]   = {0};
+    IWbemServices*          pIWbemServices = NULL;
+    BSTR                    bstrNamespace  = NULL;
+    BSTR                    bstrDeviceID   = NULL;
+    BSTR                    bstrClassName  = NULL;
+    DWORD                   uReturned      = 0;
+    bool                    bIsXinputDevice= false;
+	DWORD                   iDevice        = 0;
+	int                     xDevice        = 0;
+    VARIANT                 var;
+    HRESULT                 hr;
+
+	if(joys.size() == 0)
+		return;
+
+    // CoInit if needed
+    hr = CoInitialize(NULL);
+    bool bCleanupCOM = SUCCEEDED(hr);
+
+    // Create WMI
+    // (Orxonox): Fix for MinGW
+#ifdef __MINGW32__
+    hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pIWbemLocator);
+#else
+    hr = CoCreateInstance(__uuidof(WbemLocator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator);
+#endif
+    if( FAILED(hr) || pIWbemLocator == NULL )
+        goto LCleanup;
+
+    bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );
+	if( bstrNamespace == NULL )
+		goto LCleanup;
+
+    bstrClassName = SysAllocString( L"Win32_PNPEntity" );
+	if( bstrClassName == NULL )
+		goto LCleanup;
+
+    bstrDeviceID  = SysAllocString( L"DeviceID" );
+	if( bstrDeviceID == NULL )
+		goto LCleanup;
+    
+    // Connect to WMI 
+    hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &pIWbemServices );
+    if( FAILED(hr) || pIWbemServices == NULL )
+        goto LCleanup;
+
+    // Switch security level to IMPERSONATE. 
+    CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE );                    
+
+    hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices ); 
+    if( FAILED(hr) || pEnumDevices == NULL )
+        goto LCleanup;
+
+    // Loop over all devices
+    for( ;; )
+    {
+        // Get 20 at a time
+        hr = pEnumDevices->Next(5000, 20, pDevices, &uReturned);
+        if( FAILED(hr) )
+            goto LCleanup;
+
+        if( uReturned == 0 )
+            break;
+
+        for(iDevice = 0; iDevice < uReturned; iDevice++)
+        {
+            // For each device, get its device ID
+            hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, NULL, NULL);
+            if(SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != NULL)
+            {
+                // Check if the device ID contains "IG_".  If it does, then it's an XInput device - This information can not be found from DirectInput 
+                if(wcsstr(var.bstrVal, L"IG_"))
+                {
+                    // If it does, then get the VID/PID from var.bstrVal
+                    DWORD dwPid = 0, dwVid = 0;
+                    WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" );
+                    if(strVid && swscanf_s( strVid, L"VID_%4X", &dwVid ) != 1)
+						dwVid = 0;
+
+                    WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );
+                    if(strPid && swscanf_s( strPid, L"PID_%4X", &dwPid ) != 1)
+                        dwPid = 0;
+
+                    // Compare the VID/PID to the DInput device
+                    DWORD dwVidPid = MAKELONG(dwVid, dwPid);
+					for(JoyStickInfoList::iterator i = joys.begin(); i != joys.end(); ++i)
+					{
+						if(dwVidPid == i->productGuid.Data1)
+						{
+							i->isXInput = true;
+							i->xInputDev = xDevice;
+						}
+					}
+
+					if(joys.size() == 0)
+						goto LCleanup;
+                }
+            }
+
+            SAFE_RELEASE(pDevices[iDevice]);
+        }
+    }
+
+LCleanup:
+    if(bstrNamespace)
+        SysFreeString(bstrNamespace);
+
+    if(bstrDeviceID)
+        SysFreeString(bstrDeviceID);
+
+    if(bstrClassName)
+        SysFreeString(bstrClassName);
+
+    for(iDevice=0; iDevice < 20; iDevice++)
+        SAFE_RELEASE(pDevices[iDevice]);
+
+    SAFE_RELEASE(pEnumDevices);
+    SAFE_RELEASE(pIWbemLocator);
+    SAFE_RELEASE(pIWbemServices);
+
+    if(bCleanupCOM)
+        CoUninitialize();
+}
