Index: code/trunk/src/ois/win32/Win32ForceFeedback.cpp
===================================================================
--- code/trunk/src/ois/win32/Win32ForceFeedback.cpp	(revision 2710)
+++ code/trunk/src/ois/win32/Win32ForceFeedback.cpp	(revision 5695)
@@ -25,6 +25,11 @@
 #include <Math.h>
 
-#if defined (_DEBUG)
+// 0 = No trace; 1 = Important traces; 2 = Debug traces
+#define OIS_WIN32_JOYFF_DEBUG 1
+
+#if (defined (_DEBUG) || defined(OIS_WIN32_JOYFF_DEBUG))
+  #include <iostream>
   #include <sstream>
+  using namespace std;
 #endif
 
@@ -32,7 +37,12 @@
 
 //--------------------------------------------------------------//
-Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* joy) :
-	mHandles(0), mJoyStick(joy)
-{
+Win32ForceFeedback::Win32ForceFeedback(IDirectInputDevice8* pDIJoy, const DIDEVCAPS* pDIJoyCaps) :
+  mHandles(0), mJoyStick(pDIJoy), mFFAxes(0), mpDIJoyCaps(pDIJoyCaps)
+{
+#if (OIS_WIN32_JOYFF_DEBUG > 0)
+  cout << "FFSamplePeriod      : " << mpDIJoyCaps->dwFFSamplePeriod << " mu-s, "
+	   << "FFMinTimeResolution : " << mpDIJoyCaps->dwFFMinTimeResolution << " mu-s,"
+	   << "" << endl;
+#endif
 }
 
@@ -45,8 +55,39 @@
 		LPDIRECTINPUTEFFECT dxEffect = i->second;
 		if( dxEffect )
+		{
 			dxEffect->Unload();
+			dxEffect->Release();
+		}
 	}
 
 	mEffectList.clear();
+}
+
+//--------------------------------------------------------------//
+short Win32ForceFeedback::getFFAxesNumber()
+{
+	return mFFAxes;
+}
+
+//--------------------------------------------------------------//
+unsigned short Win32ForceFeedback::getFFMemoryLoad()
+{
+    DIPROPDWORD dipdw;  // DIPROPDWORD contains a DIPROPHEADER structure. 
+	dipdw.diph.dwSize       = sizeof(DIPROPDWORD); 
+	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
+	dipdw.diph.dwObj        = 0; // device property 
+	dipdw.diph.dwHow        = DIPH_DEVICE;
+	dipdw.dwData            = 0; // In case of any error.
+
+	const HRESULT hr = mJoyStick->GetProperty(DIPROP_FFLOAD, &dipdw.diph);
+	if(FAILED(hr))
+	{
+	    if (hr == DIERR_NOTEXCLUSIVEACQUIRED)
+		    OIS_EXCEPT(E_General, "Can't query FF memory load as device was not acquired in exclusive mode");
+		else
+		    OIS_EXCEPT(E_General, "Unknown error querying FF memory load ->..");
+	}
+
+	return (unsigned short)dipdw.dwData;
 }
 
@@ -86,5 +127,8 @@
 			//have been unlaoded
 			if( SUCCEEDED(dxEffect->Unload()) )
+			{
+			    dxEffect->Release();
 				mEffectList.erase(i);
+			}
 		}
 		else
@@ -111,5 +155,15 @@
 	DIPropGain.dwData            = gain_level;
 
-	mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph);
+#if (OIS_WIN32_JOYFF_DEBUG > 0)
+	cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting master gain to " 
+		 << level << " => " << DIPropGain.dwData << endl;
+#endif
+
+	const HRESULT hr = mJoyStick->SetProperty(DIPROP_FFGAIN, &DIPropGain.diph);
+
+#if defined (_DEBUG)
+	if(FAILED(hr))
+	    cout << "Failed to change master gain" << endl;
+#endif
 }
 
@@ -117,5 +171,4 @@
 void Win32ForceFeedback::setAutoCenterMode( bool auto_on )
 {
-	//DI Property DIPROPAUTOCENTER_OFF = 0, 1 is on
 	DIPROPDWORD DIPropAutoCenter;
 	DIPropAutoCenter.diph.dwSize       = sizeof(DIPropAutoCenter);
@@ -123,8 +176,17 @@
 	DIPropAutoCenter.diph.dwObj        = 0;
 	DIPropAutoCenter.diph.dwHow        = DIPH_DEVICE;
-	DIPropAutoCenter.dwData            = auto_on;
-
-	//hr =
-	mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph);
+	DIPropAutoCenter.dwData            = (auto_on ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF);
+
+#if (OIS_WIN32_JOYFF_DEBUG > 0)
+	cout << "Win32ForceFeedback("<< mJoyStick << ") : Setting auto-center mode to " 
+		 << auto_on << " => " << DIPropAutoCenter.dwData << endl;
+#endif
+
+	const HRESULT hr = mJoyStick->SetProperty(DIPROP_AUTOCENTER, &DIPropAutoCenter.diph);
+
+#if defined (_DEBUG)
+	if(FAILED(hr))
+	    cout << "Failed to change auto-center mode" << endl;
+#endif
 }
 
@@ -132,6 +194,9 @@
 void Win32ForceFeedback::_updateConstantEffect( const Effect* effect )
 {
+	ConstantEffect *eff = static_cast<ConstantEffect*>(effect->getForceEffect());
+
 	DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
 	LONG            rglDirection[2] = { 0, 0 };
+	DIENVELOPE      diEnvelope;
 	DICONSTANTFORCE cf;
 	DIEFFECT        diEffect;
@@ -139,7 +204,12 @@
 	//Currently only support 1 axis
 	//if( effect->getNumAxes() == 1 )
-	cf.lMagnitude = static_cast<ConstantEffect*>(effect->getForceEffect())->level;
-
-	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICONSTANTFORCE), &cf, effect);
+	cf.lMagnitude = eff->level;
+
+#if (OIS_WIN32_JOYFF_DEBUG > 1)
+	cout << "  Level : " << eff->level
+		 << " => " << cf.lMagnitude << endl;
+#endif
+
+	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONSTANTFORCE), &cf, effect, &eff->envelope);
 	_upload(GUID_ConstantForce, &diEffect, effect);
 }
@@ -148,14 +218,17 @@
 void Win32ForceFeedback::_updateRampEffect( const Effect* effect )
 {
+	RampEffect *eff = static_cast<RampEffect*>(effect->getForceEffect());
+
 	DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
 	LONG            rglDirection[2] = { 0, 0 };
+	DIENVELOPE      diEnvelope;
 	DIRAMPFORCE     rf;
 	DIEFFECT        diEffect;
 
 	//Currently only support 1 axis
-	rf.lStart = static_cast<RampEffect*>(effect->getForceEffect())->startLevel;
-	rf.lEnd = static_cast<RampEffect*>(effect->getForceEffect())->endLevel;
-
-	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DIRAMPFORCE), &rf, effect);
+	rf.lStart = eff->startLevel;
+	rf.lEnd = eff->endLevel;
+
+	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIRAMPFORCE), &rf, effect, &eff->envelope );
 	_upload(GUID_RampForce, &diEffect, effect);
 }
@@ -164,16 +237,19 @@
 void Win32ForceFeedback::_updatePeriodicEffect( const Effect* effect )
 {
+	PeriodicEffect *eff = static_cast<PeriodicEffect*>(effect->getForceEffect());
+
 	DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
 	LONG            rglDirection[2] = { 0, 0 };
+	DIENVELOPE      diEnvelope;
 	DIPERIODIC      pf;
 	DIEFFECT        diEffect;
 
 	//Currently only support 1 axis
-	pf.dwMagnitude = static_cast<PeriodicEffect*>(effect->getForceEffect())->magnitude;
-	pf.lOffset = static_cast<PeriodicEffect*>(effect->getForceEffect())->offset;
-	pf.dwPhase = static_cast<PeriodicEffect*>(effect->getForceEffect())->phase;
-	pf.dwPeriod = static_cast<PeriodicEffect*>(effect->getForceEffect())->period;
-
-	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DIPERIODIC), &pf, effect);
+	pf.dwMagnitude = eff->magnitude;
+	pf.lOffset = eff->offset;
+	pf.dwPhase = eff->phase;
+	pf.dwPeriod = eff->period;
+
+	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DIPERIODIC), &pf, effect, &eff->envelope );
 
 	switch( effect->type )
@@ -191,17 +267,20 @@
 void Win32ForceFeedback::_updateConditionalEffect( const Effect* effect )
 {
+	ConditionalEffect *eff = static_cast<ConditionalEffect*>(effect->getForceEffect());
+
 	DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
 	LONG            rglDirection[2] = { 0, 0 };
+	DIENVELOPE      diEnvelope;
 	DICONDITION     cf;
 	DIEFFECT        diEffect;
 
-	cf.lOffset = static_cast<ConditionalEffect*>(effect->getForceEffect())->deadband;
-	cf.lPositiveCoefficient = static_cast<ConditionalEffect*>(effect->getForceEffect())->rightCoeff;
-	cf.lNegativeCoefficient = static_cast<ConditionalEffect*>(effect->getForceEffect())->leftCoeff;
-	cf.dwPositiveSaturation = static_cast<ConditionalEffect*>(effect->getForceEffect())->rightSaturation;
-	cf.dwNegativeSaturation = static_cast<ConditionalEffect*>(effect->getForceEffect())->leftSaturation;
-	cf.lDeadBand = static_cast<ConditionalEffect*>(effect->getForceEffect())->deadband;
-
-	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICONDITION), &cf, effect);
+	cf.lOffset = eff->deadband;
+	cf.lPositiveCoefficient = eff->rightCoeff;
+	cf.lNegativeCoefficient = eff->leftCoeff;
+	cf.dwPositiveSaturation = eff->rightSaturation;
+	cf.dwNegativeSaturation = eff->leftSaturation;
+	cf.lDeadBand = eff->deadband;
+
+	_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICONDITION), &cf, effect, 0 );
 
 	switch( effect->type )
@@ -218,6 +297,9 @@
 void Win32ForceFeedback::_updateCustomEffect( const Effect* /*effect*/ )
 {
+    //CustomEffect *eff = static_cast<CustomEffect*>(effect->getForceEffect());
+    //
 	//DWORD           rgdwAxes[2]     = { DIJOFS_X, DIJOFS_Y };
 	//LONG            rglDirection[2] = { 0, 0 };
+	//DIENVELOPE      diEnvelope;
 	//DICUSTOMFORCE cf;
 	//DIEFFECT        diEffect;
@@ -226,5 +308,5 @@
 	//cf.cSamples = 0;
 	//cf.rglForceData = 0;
-	//_setCommonProperties(&diEffect, rgdwAxes, rglDirection, sizeof(DICUSTOMFORCE), &cf, effect);
+	//_setCommonProperties(&diEffect, rgdwAxes, rglDirection, &diEnvelope, sizeof(DICUSTOMFORCE), &cf, effect, &eff->envelope);
 	//_upload(GUID_CustomForce, &diEffect, effect);
 }
@@ -233,6 +315,6 @@
 void Win32ForceFeedback::_setCommonProperties(
 		DIEFFECT* diEffect, DWORD* rgdwAxes,
-		LONG* rglDirection, DWORD struct_size,
-		LPVOID struct_type, const Effect* effect )
+		LONG* rglDirection, DIENVELOPE* diEnvelope, DWORD struct_size,
+		LPVOID struct_type, const Effect* effect, const Envelope* envelope )
 {
 	ZeroMemory(diEffect, sizeof(DIEFFECT));
@@ -240,16 +322,71 @@
 	diEffect->dwSize                  = sizeof(DIEFFECT);
 	diEffect->dwFlags                 = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
+	diEffect->dwGain                  = DI_FFNOMINALMAX;
+
+	diEffect->dwTriggerButton         = DIEB_NOTRIGGER; // effect->trigger_button; // TODO: Conversion
+	diEffect->dwTriggerRepeatInterval = effect->trigger_interval;
+
+#if (OIS_WIN32_JOYFF_DEBUG > 1)
+	cout << "  Trigger :" << endl
+		 << "    Button   : " << effect->trigger_button 
+		 << " => " << diEffect->dwTriggerButton << endl
+		 << "    Interval : " << effect->trigger_interval 
+		 << " => " << diEffect->dwTriggerRepeatInterval << endl;
+#endif
+
+	diEffect->cAxes                   = 1; // effect->getNumAxes();
+	diEffect->rgdwAxes                = rgdwAxes;
+
+	diEffect->rglDirection            = rglDirection; // TODO: conversion from effect->direction
+
+#if (OIS_WIN32_JOYFF_DEBUG > 1)
+	cout << "  Direction : " << Effect::getDirectionName(effect->direction)
+		 << " => {";
+	for (int iDir=0; iDir < (int)diEffect->cAxes; iDir++)
+	  cout << " " << diEffect->rglDirection[iDir];
+	cout << "}" << endl;
+#endif
+
+	if (diEnvelope && envelope && envelope->isUsed())
+	{
+	    diEnvelope->dwSize = sizeof(DIENVELOPE);
+	    diEnvelope->dwAttackLevel = envelope->attackLevel;
+	    diEnvelope->dwAttackTime  = envelope->attackLength;
+	    diEnvelope->dwFadeLevel   = envelope->fadeLevel;
+	    diEnvelope->dwFadeTime    = envelope->fadeLength;
+	    diEffect->lpEnvelope = diEnvelope;
+	}
+	else
+	    diEffect->lpEnvelope = 0;
+
+#if (OIS_WIN32_JOYFF_DEBUG > 1)
+	if (diEnvelope && envelope && envelope->isUsed())
+	{
+		cout << "  Enveloppe :" << endl
+			 << "    AttackLen : " << envelope->attackLength
+			 << " => " << diEnvelope->dwAttackTime << endl 
+			 << "    AttackLvl : " << envelope->attackLevel
+			 << " => " << diEnvelope->dwAttackLevel << endl 
+			 << "    FadeLen   : " << envelope->fadeLength
+			 << " => " << diEnvelope->dwFadeTime << endl
+			 << "    FadeLvl   : " << envelope->fadeLevel
+			 << " => " << diEnvelope->dwFadeLevel << endl;
+	}
+#endif
+
+	diEffect->dwSamplePeriod          = 0;
 	diEffect->dwDuration              = effect->replay_length;
-	diEffect->dwSamplePeriod          = 0;
-	diEffect->dwGain                  = DI_FFNOMINALMAX;
-	diEffect->dwTriggerButton         = DIEB_NOTRIGGER;
-	diEffect->dwTriggerRepeatInterval = 0;
-	diEffect->cAxes                   = effect->getNumAxes();
-	diEffect->rgdwAxes                = rgdwAxes;
-	diEffect->rglDirection            = rglDirection;
-	diEffect->lpEnvelope              = 0;
+	diEffect->dwStartDelay            = effect->replay_delay;
+
+#if (OIS_WIN32_JOYFF_DEBUG > 1)
+	cout << "  Replay :" << endl
+		 << "    Length : " << effect->replay_length 
+		 << " => " << diEffect->dwDuration << endl
+		 << "    Delay  : " << effect->replay_delay 
+		 << " => " << diEffect->dwStartDelay << endl;
+#endif
+
 	diEffect->cbTypeSpecificParams    = struct_size;
 	diEffect->lpvTypeSpecificParams   = struct_type;
-	diEffect->dwStartDelay            = effect->replay_delay;
 }
 
@@ -295,31 +432,97 @@
 void Win32ForceFeedback::_addEffectSupport( LPCDIEFFECTINFO pdei )
 {
-	//Determine what the effect is and how it corresponds to our OIS's Enums
-	//We could save the GUIDs too, however, we will just use the predefined
-	//ones later
+#if (OIS_WIN32_JOYFF_DEBUG > 0)
+    // Dump some usefull information about the effect type.
+    cout << "Adding support for '" << pdei->tszName << "' effect type" << endl;
+	cout << "  Supported static params: ";
+	if (pdei->dwStaticParams & DIEP_AXES) cout << " Axes";
+	if (pdei->dwStaticParams & DIEP_DIRECTION) cout << " Direction";
+	if (pdei->dwStaticParams & DIEP_DURATION) cout << " Duration";
+	if (pdei->dwStaticParams & DIEP_ENVELOPE) cout << " Envelope";
+	if (pdei->dwStaticParams & DIEP_GAIN) cout << " Gain";
+	if (pdei->dwStaticParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod";
+	if (pdei->dwStaticParams & DIEP_STARTDELAY) cout << " StartDelay";
+	if (pdei->dwStaticParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton";
+	if (pdei->dwStaticParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval";
+	if (pdei->dwStaticParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams";
+	cout << endl;
+	cout << "  Supported dynamic params: ";
+	if (pdei->dwDynamicParams & DIEP_AXES) cout << " Axes";
+	if (pdei->dwDynamicParams & DIEP_DIRECTION) cout << " Direction";
+	if (pdei->dwDynamicParams & DIEP_DURATION) cout << " Duration";
+	if (pdei->dwDynamicParams & DIEP_ENVELOPE) cout << " Envelope";
+	if (pdei->dwDynamicParams & DIEP_GAIN) cout << " Gain";
+	if (pdei->dwDynamicParams & DIEP_SAMPLEPERIOD) cout << " SamplePeriod";
+	if (pdei->dwDynamicParams & DIEP_STARTDELAY) cout << " StartDelay";
+	if (pdei->dwDynamicParams & DIEP_TRIGGERBUTTON) cout << " TriggerButton";
+	if (pdei->dwDynamicParams & DIEP_TRIGGERREPEATINTERVAL) cout << " TriggerRepeatInterval";
+	if (pdei->dwDynamicParams & DIEP_TYPESPECIFICPARAMS) cout << " TypeSpecificParams";
+	cout << endl;
+	cout << "  More details about supported parameters support: ";
+	if (pdei->dwEffType & DIEFT_STARTDELAY) cout << " StartDelay";
+	if (pdei->dwEffType & DIEFT_FFATTACK) cout << " Attack";
+	if (pdei->dwEffType & DIEFT_FFFADE) cout << " Fade";
+	if (pdei->dwEffType & DIEFT_DEADBAND) cout << " DeadBand";
+	if (pdei->dwEffType & DIEFT_SATURATION) cout << " Saturation";
+	if (pdei->dwEffType & DIEFT_POSNEGSATURATION) cout << " PosNegaturation";
+	if (pdei->dwEffType & DIEFT_POSNEGCOEFFICIENTS) cout << " PosNegCoefficients";
+	if (pdei->dwEffType & DIEFT_HARDWARE) cout << " HardwareSpecific";
+	cout << endl;
+#endif
+
+    Effect::EForce eForce;
+	switch (DIEFT_GETTYPE(pdei->dwEffType))
+	{
+	    case DIEFT_CONSTANTFORCE:
+		    eForce = Effect::ConstantForce;
+			break;
+	    case DIEFT_RAMPFORCE:
+		    eForce = Effect::RampForce;
+			break;
+	    case DIEFT_PERIODIC:
+		    eForce = Effect::PeriodicForce;
+			break;
+	    case DIEFT_CONDITION:
+		    eForce = Effect::ConditionalForce;
+			break;
+	    case DIEFT_CUSTOMFORCE:
+		    eForce = Effect::CustomForce;
+			break;
+	    default:
+		    eForce = Effect::UnknownForce;
+#if defined (_DEBUG)
+			cout << "Win32ForceFeedback: DirectInput8 Effect type support not implemented: " 
+				 << "DIEFT_GETTYPE="<< (int)DIEFT_GETTYPE(pdei->dwEffType) << endl;
+#endif
+			return;
+	}
+
+	//Determine what the effect type is and how it corresponds to our OIS's Enums
+	//We could save the GUIDs too, however, we will just use the predefined ones later
 	if( pdei->guid == GUID_ConstantForce )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Constant );
+		_addEffectTypes(eForce, Effect::Constant );
 	else if( pdei->guid == GUID_Triangle )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Triangle );
+		_addEffectTypes(eForce, Effect::Triangle );
 	else if( pdei->guid == GUID_Spring )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Spring );
+		_addEffectTypes(eForce, Effect::Spring );
 	else if( pdei->guid == GUID_Friction )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Friction );
+		_addEffectTypes(eForce, Effect::Friction );
 	else if( pdei->guid == GUID_Square )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Square );
+		_addEffectTypes(eForce, Effect::Square );
 	else if( pdei->guid == GUID_Sine )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Sine );
+		_addEffectTypes(eForce, Effect::Sine );
 	else if( pdei->guid == GUID_SawtoothUp )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::SawToothUp );
+		_addEffectTypes(eForce, Effect::SawToothUp );
 	else if( pdei->guid == GUID_SawtoothDown )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::SawToothDown );
+		_addEffectTypes(eForce, Effect::SawToothDown );
 	else if( pdei->guid == GUID_Damper )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Damper );
+		_addEffectTypes(eForce, Effect::Damper );
 	else if( pdei->guid == GUID_Inertia )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Inertia );
+		_addEffectTypes(eForce, Effect::Inertia );
 	else if( pdei->guid == GUID_CustomForce )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Custom );
+		_addEffectTypes(eForce, Effect::Custom );
 	else if( pdei->guid == GUID_RampForce )
-		_addEffectTypes((Effect::EForce)DIEFT_GETTYPE(pdei->dwEffType), Effect::Ramp );
+		_addEffectTypes(eForce, Effect::Ramp );
+
 #if defined (_DEBUG)
 	//Only care about this for Debugging Purposes
@@ -333,2 +536,8 @@
 #endif
 }
+
+//--------------------------------------------------------------//
+void Win32ForceFeedback::_addFFAxis()
+{
+	mFFAxes++;
+}
Index: code/trunk/src/ois/win32/Win32ForceFeedback.h
===================================================================
--- code/trunk/src/ois/win32/Win32ForceFeedback.h	(revision 2710)
+++ code/trunk/src/ois/win32/Win32ForceFeedback.h	(revision 5695)
@@ -34,5 +34,5 @@
 		Win32ForceFeedback() {}
 	public:
-		Win32ForceFeedback(IDirectInputDevice8* joy);
+		Win32ForceFeedback(IDirectInputDevice8* pDIJoy, const DIDEVCAPS* pDIJoyCaps);
 		~Win32ForceFeedback();
 
@@ -52,8 +52,9 @@
 		void setAutoCenterMode( bool auto_on );
 
-		/** @copydoc ForceFeedback::getFFAxesNumber 
-			xxx todo - Actually return correct number
-		*/
-		short getFFAxesNumber() {return 1;}
+		/** @copydoc ForceFeedback::getFFAxesNumber */
+		short getFFAxesNumber();
+
+		/** @copydoc ForceFeedback::getFFMemoryLoad */
+		unsigned short getFFMemoryLoad();
 
 		/**
@@ -64,5 +65,13 @@
 		void _addEffectSupport( LPCDIEFFECTINFO pdei );
 
+		/**
+			@remarks
+			Internal use.. Used during axis enumeration to get number of FF axes
+			support effects.
+		*/
+		void _addFFAxis();
+
 	protected:
+
 		//Specific Effect Settings
 		void _updateConstantEffect( const Effect* effect );
@@ -71,18 +80,28 @@
 		void _updateConditionalEffect( const Effect* effect );
 		void _updateCustomEffect( const Effect* effect );
+
 		//Sets the common properties to all effects
 		void _setCommonProperties( DIEFFECT* diEffect, DWORD* rgdwAxes,
-									LONG* rglDirection, DWORD struct_size, 
-									LPVOID struct_type, const Effect* effect );
+									LONG* rglDirection, DIENVELOPE* diEnvelope, DWORD struct_size, 
+									LPVOID struct_type, const Effect* effect, const Envelope* envelope );
 		//Actually do the upload
 		void _upload( GUID, DIEFFECT*, const Effect* );
 
+		// Map of currently uploaded effects (handle => effect)
 		typedef std::map<int,LPDIRECTINPUTEFFECT> EffectList;
 		EffectList mEffectList;
-		//Simple unique handle creation - allows for upto 2+ million effects
+
+		//Simple unique handle creation - allows for upto 2+ billion effects
 		//during the lifetime of application. Hopefully, that is enough.
 		int mHandles;
 
+		// Joystick device descriptor.
 		IDirectInputDevice8* mJoyStick;
+		
+		// Joystick capabilities.
+		const DIDEVCAPS* mpDIJoyCaps;
+
+		// Number of axis supporting FF.
+		short mFFAxes;
 	};
 }
Index: code/trunk/src/ois/win32/Win32InputManager.cpp
===================================================================
--- code/trunk/src/ois/win32/Win32InputManager.cpp	(revision 2710)
+++ code/trunk/src/ois/win32/Win32InputManager.cpp	(revision 5695)
@@ -75,5 +75,5 @@
 	hInst = GetModuleHandle(0);
 
-	//Create the device
+	//Create the input system
 	hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&mDirectInput, NULL );
     if (FAILED(hr))	
@@ -82,4 +82,6 @@
 	//Ok, now we have DirectInput, parse whatever extra settings were sent to us
 	_parseConfigSettings( paramList );
+
+	// Enumerate devices ...
 	_enumerateDevices();
 }
@@ -116,11 +118,13 @@
 {
 	//Enumerate all attached devices
-	mDirectInput->EnumDevices(NULL, _DIEnumKbdCallback, this, DIEDFL_ATTACHEDONLY); 
-}
-
-//--------------------------------------------------------------------------------//
-BOOL CALLBACK Win32InputManager::_DIEnumKbdCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
+	mDirectInput->EnumDevices(NULL , _DIEnumDevCallback, this, DIEDFL_ATTACHEDONLY); 
+}
+
+//--------------------------------------------------------------------------------//
+BOOL CALLBACK Win32InputManager::_DIEnumDevCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
 {
 	Win32InputManager *_this_ = static_cast<Win32InputManager*>(pvRef);
+
+	// Register only game devices (keyboard and mouse are managed differently).
 	if( GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_JOYSTICK ||
 		GET_DIDEVICE_TYPE(lpddi->dwDevType) == DI8DEVTYPE_GAMEPAD ||
Index: code/trunk/src/ois/win32/Win32InputManager.h
===================================================================
--- code/trunk/src/ois/win32/Win32InputManager.h	(revision 2710)
+++ code/trunk/src/ois/win32/Win32InputManager.h	(revision 5695)
@@ -81,5 +81,5 @@
 
 		//! Used during device enumeration
-		static BOOL CALLBACK _DIEnumKbdCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
+		static BOOL CALLBACK _DIEnumDevCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
 
 		//! Keep a list of all joysticks enumerated, but not in use
Index: code/trunk/src/ois/win32/Win32JoyStick.cpp
===================================================================
--- code/trunk/src/ois/win32/Win32JoyStick.cpp	(revision 2710)
+++ code/trunk/src/ois/win32/Win32JoyStick.cpp	(revision 5695)
@@ -82,9 +82,25 @@
 	mState.mAxes.clear();
 
-	delete ff_device;
-	ff_device = 0;
-
+	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);
@@ -93,19 +109,8 @@
 	dipdw.dwData            = JOYSTICK_DX_BUFFERSIZE;
 
-	if(FAILED(mDirectInput->CreateDevice(deviceGuid, &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
+		OIS_EXCEPT( E_General, "Win32JoyStick::_initialize >> Failed to set buffer size property" );
+
+	// Enumerate all axes/buttons/sliders/force feedback/etc before aquiring
 	_enumerate();
 
@@ -118,21 +123,23 @@
 void Win32JoyStick::_enumerate()
 {
-	//We can check force feedback here too
-	DIDEVCAPS  DIJoyCaps;
-	DIJoyCaps.dwSize = sizeof(DIDEVCAPS);
-	mJoyStick->GetCapabilities(&DIJoyCaps);
-
-	mPOVs = (short)DIJoyCaps.dwPOVs;
-
-	mState.mButtons.resize(DIJoyCaps.dwButtons);
-	mState.mAxes.resize(DIJoyCaps.dwAxes);
+	// 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 Force Feedback (if any)
-	mJoyStick->EnumEffects(DIEnumEffectsCallback, this, DIEFT_ALL);
-
-	//Enumerate and set axis constraints (and check FF Axes)
+	// Enumerate and set axis constraints (and check FF Axes)
 	mJoyStick->EnumObjects(DIEnumDeviceObjectsCallback, this, DIDFT_AXIS);
 }
@@ -181,13 +188,22 @@
 		OIS_EXCEPT( E_General, "Win32JoyStick::_DIEnumDeviceObjectsCallback >> Failed to set min/max range property" );
 
-	//Check if FF Axes
+	//Check if FF Axes, and if so, increment counter
 	if((lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 )
 	{
 		if( _this->ff_device )
 		{
-			//todo - increment force feedback axis count
+			_this->ff_device->_addFFAxis();
 		}
 	}
 
+	//Force the flags for gain and auto-center support to true,
+	//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);
+	}
+
 	return DIENUM_CONTINUE;
 }
@@ -198,7 +214,7 @@
 	Win32JoyStick* _this = (Win32JoyStick*)pvRef;
 
-	//Create the FF class after we know there is at least one effect type
+	//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->ff_device = new Win32ForceFeedback(_this->mJoyStick, &_this->mDIJoyCaps);
 
 	_this->ff_device->_addEffectSupport( pdei );
Index: code/trunk/src/ois/win32/Win32JoyStick.h
===================================================================
--- code/trunk/src/ois/win32/Win32JoyStick.h	(revision 2710)
+++ code/trunk/src/ois/win32/Win32JoyStick.h	(revision 5695)
@@ -60,4 +60,6 @@
 		IDirectInput8* mDirectInput;
 		IDirectInputDevice8* mJoyStick;
+		DIDEVCAPS mDIJoyCaps;
+
 		DWORD coopSetting;
 		GUID deviceGuid;
Index: code/trunk/src/ois/win32/Win32KeyBoard.cpp
===================================================================
--- code/trunk/src/ois/win32/Win32KeyBoard.cpp	(revision 2710)
+++ code/trunk/src/ois/win32/Win32KeyBoard.cpp	(revision 5695)
@@ -238,8 +238,7 @@
 		return 0;
 
-	unsigned char buff[3] = {0,0,0};
-	int ascii = ToAsciiEx(vk, kc, keyState, (LPWORD) buff, 0, layout);
-	//WCHAR wide[3];
-	//int ascii = ToUnicodeEx(vk, kc, keyState, wide, 3, 0, layout);
+	WCHAR buff[3] = {0};
+	int ascii = ToUnicodeEx(vk, kc, keyState, buff, 3, 0, layout);
+
 	if(ascii == 1 && deadKey != '\0' )
 	{
