#include "pch.hpp"
//===========================================================================//
// File:	 ControlManager.cpp												 //
// Project:  GameOS					                                         //
// Contents: Control Manager routines										 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             // 
// 11/15/97  JTR    Created													 //
// 12/04/97  JTR    Object-Oriented to C									 //
// 12/07/97  JTR    Added support for DI Mouse								 //
// 12/31/97  JTR    Added Documentation										 //
// 01/13/98  JTR    Fixed bug in mouse button clearing mechanism.			 //
//																			 //
//---------------------------------------------------------------------------//
// Copyright (C) 1999 Microsoft Corp.						                 //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
#include "Globals.hpp"
#include "ControlManager.hpp"
#include "ForceFeedback.hpp"
#include "DirectX.hpp"
#include "Windows.hpp"
#include "ErrorHandler.hpp"
#include "Debugger.hpp"

extern bool gActive;
extern bool gGotFocus;
extern DWORD ButtonsPressed;

extern int XPositionInternal;
extern int YPositionInternal;
extern float XPosition;
extern float YPosition;
extern DWORD gLanguageDLL;
extern HGOSFORCEEFFECT gForceEffects;
extern void SetExtended( BYTE vk, BOOL bState );
extern DWORD gNumLockMode;
extern DWORD gCapLockMode;
extern DWORD gScrollLockMode;

float XDelta,YDelta;
DWORD gNumberOfJoystickCounts;
extern DWORD gDisableForceFeedback;
extern DWORD gDisableJoystick;

bool DisablePolling=0;
void CMRestoreEffects( int stick );

// hyun begin
int g_bUseOrgJoy = TRUE;
void (__stdcall *g_pfnRIO_Joy)(DIJOYSTATE& js) = NULL; // Check out Test ..
bool g_bNoWeaponRangeCheck = false;
// hyun end
//
//
// Initialize the DirectInput devices
//
//
void CMInstall()
{
//
// Debugging information
//
	SPEW(( GROUP_GAMEOS, "ControlManagerInstall()" ));
//
// Create DirectInput device
//
	gos_MathExceptions( 0, 0 );					// No exceptions, double precision
	memset(&g_CMData, 0, sizeof(g_CMData));
	wDirectInputCreateEx(hInstance, 0x0700, IID_IDirectInput7, (void**)&g_CMData.m_lpDirectInput7, NULL); 
//
// Create keyboard
//
	CMCreateKeyboard();
//
// Create mouse
//
	CMCreateMouse();
//
// If joysticks enabled, create joysticks
//
	CMCreateJoysticks();

// clear the list of forceeffects
	gForceEffects = NULL;

// the numlock mode should be initialized to "don't care"
	gNumLockMode = 2;
	gCapLockMode = 2;    
	gScrollLockMode = 2; 
//
//
//
	gos_MathExceptions(1,0);
//
//
//
	CMAcquireControls();
//
//
	ReInitControlManager();
}







void ReInitControlManager()
{
//
// Clear keyboard data and cheat flags
//
	KeyCurrent=0;				// Where the next key to be read is
	KeyPressed=0;				// Where the next key pressed will go
	dbKeyCurrent=0;				// Where the next key to be read is
	dbKeyPressed=0;				// Where the next key pressed will go
	LastWMDown=0;
	gNumberOfJoystickCounts=0;
}






// Make the calls to release all memory relating to the control manager and DI devices.
void CMUninstall()
{
//
// Make sure all the devices are unacquired
//
	CMUnacquireControls();
//
// Remove any force feedback effects that that app has not released
//
	while (gForceEffects)
		delete gForceEffects;
//
// Release all controls
//
	CMReleaseControls();
//
// Release the directinput object an NULL it out
//
	if( g_CMData.m_lpDirectInput7 )
		wRelease( g_CMData.m_lpDirectInput7 );
	g_CMData.m_lpDirectInput7 = NULL;

	SPEW(( GROUP_GAMEOS, "ControlManagerUninstall()" ));
}





// Release the DI keyboard, DI mouse, and DI joysticks.
void CMReleaseControls()
{
	// release mouse if necessary, and null it out.
	if (g_CMData.m_lpSysMouse7) 
	{
		wRelease(g_CMData.m_lpSysMouse7);
		g_CMData.m_lpSysMouse7 = NULL;
	}
	// for each joystick, release and NULL out
	for(int i = 0; i < g_CMData.m_numJoysticks; i++)
	{
		if (g_CMData.m_lpJoystick7[i])
		{
			wRelease(g_CMData.m_lpJoystick7[i]);
			g_CMData.m_lpJoystick7[i] = NULL;
		}
	}
}


// If the DI controls get snatched away for some reason, try and get them back.
void CMAcquireControls()
{
	CMCreateKeyboard();			// Clear all pressed keys

	AllowFail=1;
	if( g_CMData.m_lpSysMouse7 )
		wAcquire( g_CMData.m_lpSysMouse7 );
	AllowFail=0;

	// we need all DirectInput objects to be acquired to use them, so....
  	if( LogMode==1 )
		return;

	if( gGotFocus==1 && !ProcessingError )
	{
		for( DWORD i=0; i < g_CMData.m_numJoysticks; i++ )
		{
			if( g_CMData.m_lpJoystick7[i] && ! g_CMData.m_disabled[i] )
			{
				AllowFail=1;
				HRESULT hr=wAcquire( g_CMData.m_lpJoystick7[i] );
				AllowFail=0;
				if( FAILED(hr) )
				{
					//
					// A non-focus-related error has occurred!
					// Disable this device for the duration of the application.
					//
					if( hr != DIERR_OTHERAPPHASPRIO )
					{
						g_CMData.m_disabled[i]=1;
					}
				}
			}
		}
	}
	if (gNumLockMode !=2)
		SetExtended(VK_NUMLOCK, gNumLockMode);
	if (gCapLockMode !=2)
		SetExtended(VK_CAPITAL, gNumLockMode);
	if (gScrollLockMode !=2)
		SetExtended(VK_SCROLL, gScrollLockMode);
}

// We need to be able to surrender the controls on demand
void CMUnacquireControls()
{
  	if (LogMode == 1)
		return;

	if (g_CMData.m_lpSysMouse7)
	{
		wUnacquire(g_CMData.m_lpSysMouse7);
	}

	for(int i = 0; i < g_CMData.m_numJoysticks; i++)
	{
		g_CMData.m_disabled[i]=0;
		if (g_CMData.m_lpJoystick7[i])
		{
			wUnacquire(g_CMData.m_lpJoystick7[i]);
		}
	}
}


//
// CLIENT VISIBLE
// Return the number of joysticks attached to the machine running the application.
//
DWORD __stdcall gosJoystick_CountJoysticks( bool ReDetect )
{
	SPEW(( "GameOS_LogFile", "gosJoystick_CountJoysticks() - Entered" ));
	#ifdef LAB_ONLY
	gNumberOfJoystickCounts++;
	#endif
//
// Playing back a log file
//
	if( 1==LogMode )
	{
		if( DebuggerActive && InDebugger )
		{
			SPEW(( "GameOS_LogFile", "gosJoystick_CountJoysticks() - Exited" ));
			return 0;
		}

		SPEW(( "GameOS_LogFile", "gosJoystick_CountJoysticks() - Exited" ));
		return ReadBitStream(8,Log_JoystickCount);
	}
//
// Release the effects again...
//
	if( ReDetect )
	{
		HGOSFORCEEFFECT itr = gForceEffects;
		while(itr)
		{
			FFEffectData * itr2 = itr->ffEffectData;
			while(itr2)
			{
				if( itr2->diEffect )
				{
					wRelease(itr2->diEffect);
				}
				itr2->diEffect = 0;;
				itr2 = itr2->pNextEffect;
			}
			itr = itr->pNext;
		}
//
// Release joysticks
//
		for(int i = 0; i < g_CMData.m_numJoysticks; i++)
		{
			if (g_CMData.m_lpJoystick7[i])
			{
				wUnacquire(g_CMData.m_lpJoystick7[i]);
				wRelease(g_CMData.m_lpJoystick7[i]);
				g_CMData.m_lpJoystick7[i] = NULL;
			}
		}
//
// Recreate joysticks
//
		CMCreateJoysticks();
	}
//
// Recording a log file
//		
	if( !InDebugger )
		WriteBitStream( g_CMData.m_numJoysticks, 8, Log_JoystickCount );

	SPEW(( "GameOS_LogFile", "gosJoystick_CountJoysticks() - Exited" ));

	return g_CMData.m_numJoysticks;
}


//////////////////////////////////////////////////////////////////////////////////
// CLIENT VISIBLE
// Return the current value of a particular joystick's particular axis. The
// value is mapped internally to range between -1.0f and 1.0f.
// except for POV which are at -1 when at rest, a %clockwise when engaged
float __stdcall gosJoystick_GetAxis(DWORD index, GOSJoystickAxis axis)
{
	float Value;

	if( 1==LogMode )
	{
//
// Playing back a log file
//
		if( DebuggerActive && InDebugger )
		{
			return 0;
		}
		
		*(DWORD*)&Value=ReadBitStream(32, Log_JoystickAxis);
		
		return Value;
	}
//
// Recording a log file
//		
	gosASSERT(index < g_CMData.m_numJoysticks);
	gosASSERT(g_CMData.m_validAxis[index][axis]);

	if (axis > JOY_SLIDER2)
	{
		if ( g_CMData.m_joyAxis[index][axis] >= 0)
			Value= ((float) g_CMData.m_joyAxis[index][axis] / 36000.0f);
		else
			Value= -1.0f;
	}
	else
		Value= ((float) g_CMData.m_joyAxis[index][axis] / 1000.0f);

	if( !InDebugger )
	{
		SPEW(( "GameOS_LogFile", "gosJoystick_GetAxis(%d,%d)",index,axis ));
		WriteBitStream( *(DWORD*)&Value, 32, Log_JoystickAxis );
	}

	return Value;
}


// CLIENT VISIBLE
// Returns whether or not a particular button on particular joystick
// is pressed.
bool __stdcall gosJoystick_ButtonStatus(DWORD index, DWORD button)
{
	if( 1==LogMode )
	{
//
// Playing back a log file
//
		if( DebuggerActive && InDebugger )
		{
			return 0;
		}
		
		return 0!=ReadBitStream(1,Log_JoystickButton);
	}
//
// Recording a log file
//		
	gosASSERT(index < g_CMData.m_numJoysticks);

	//
	// if there are more than 64 buttons on the stick,
	// return 64+ as always unpressed.
	//
	if (button >= g_CMData.m_numButtons[index])
		return false;

	DWORD Pressed=g_CMData.m_joyButton[index][button] & 0x80;

	if( !InDebugger )
	{
		SPEW(( "GameOS_LogFile", "gosJoystick_ButtonStatus(%d,%d)",index,button ));
		WriteBitStream( 0!=Pressed, 1, Log_JoystickButton );
	}

	return 0!=Pressed;
}




void __stdcall gosJoystick_SetPolling(DWORD index, bool yesNo, float howOften)
{
	if( 1!=LogMode )
	{
		gosASSERT(index < g_CMData.m_numJoysticks);

		g_CMData.m_pollMe[index] = yesNo;
		g_CMData.m_howOften[index] = howOften;
		g_CMData.m_nextPoll[index] = gos_GetElapsedTime();
	}
}





// Make the calls necessary to updating all the associated control manager handled
// input devices.
void CMUpdate()
{
//
// Controls need reaquiring?
//
	if (g_CMData.m_requiresAcquire)
	{
		CMAcquireControls();
		g_CMData.m_requiresAcquire = false;
	}
//
// Check windows messages read last frame.
//
	if( LastWMDown )
	{
		if( DebuggerActive )
		{
			if( ((dbKeyPressed+1)&255)!=dbKeyCurrent )
			{
				dbKeyBoardBuffer[dbKeyPressed] = LastWMDown;
				dbKeyPressed=(dbKeyPressed+1)&255;
			}
		}
		if( !DebuggerActive || (DebuggerActive && gControlsActive && !gStopSystem) )
		{
			AddKeyEvent(LastWMDown);
		}
		LastWMDown=0;
	}
//
// Update keyboard, mouse, joystick
//
	if (gActive && gGotFocus) // is Gos active?
	{
		CMUpdateMouse();

		if( !DisablePolling )
		{
			for(int i = 0; i < g_CMData.m_numJoysticks; i++)
				if (g_CMData.m_pollMe[i])
					CMReadJoystick(i);
		}
	}
#if 0 // def _DEBUG
extern int g_nCoinCount;

extern char DisplayInfoText[128];
extern DWORD EndDisplayInfoTime;
extern DWORD EnableDisplayInfo;

    if( EnableDisplayInfo==0 ) {
disp:
        sprintf(DisplayInfoText, "COIN: %d coins", g_nCoinCount);
        EnableDisplayInfo = 1;
    } else if (EnableDisplayInfo==2) {
        if( timeGetTime() < EndDisplayInfoTime+50 ) {
        } else {
            goto disp;
        }
    } else {
    }
#endif // _DEBUG
}


// Create all valid and attached joysticks via callback.
void CMCreateJoysticks()
{
	if (LogMode == 1)
		return;
    // jcem - begin
    if (g_bUseOrgJoy) {
    // jcem - end
	g_CMData.m_numJoysticks=0;
	if( !gDisableJoystick && g_CMData.m_lpDirectInput7 )
		wEnumDevices( g_CMData.m_lpDirectInput7, 0, CMCreateJoystick7, NULL, DIEDFL_ATTACHEDONLY);
    // jcem - begin
    } else {
        g_CMData.m_numJoysticks = 1;

        strncpy(g_CMData.m_joyName[0], "RIO Joystick Emulation", 64);
        g_CMData.m_lpJoystick7[0] = NULL;
        g_CMData.m_numSliders[0] = 1;
        g_CMData.m_disabled[0] = 0;
        g_CMData.m_bForceFeedback[0] = false;
        g_CMData.m_numButtons[0] = 8;
        g_CMData.m_numPOVs[0] = 1;

        memset(&g_CMData.m_validAxis[0][0], 0, sizeof(g_CMData.m_validAxis));
        g_CMData.m_validAxis[0][0] = 1;
        g_CMData.m_validAxis[0][1] = 1;
        g_CMData.m_validAxis[0][5] = 1;
        g_CMData.m_validAxis[0][6] = 1;
        g_CMData.m_validAxis[0][8] = 1;
        /*
         0(X) - 1, 1(Y) - 1, 2(Z) - 0
         3(RX) - 0, 4(RY) - 0
         5(RZ) - 1
         6-SLIDER(0) - 1
         7-SLIDER(1) - 0
         8->POV[i] - 1 0 0 0
        */
    }
    // jcem - end
}


// Each time a joystick is enumerated, control is passed to this function. Here the 
// joystick is analyzed and the resulting information is placed in the control manager
// data structure for later access.
BOOL WINAPI CMCreateJoystick7(LPCDIDEVICEINSTANCE pdinst, void* pvRef)
{
#ifdef DI8DEVCLASS_POINTER
	if( GET_DIDEVICE_TYPE(pdinst->dwDevType)==DI8DEVCLASS_POINTER || 
		GET_DIDEVICE_TYPE(pdinst->dwDevType)==DI8DEVCLASS_KEYBOARD )
		return DIENUM_CONTINUE;
#else
	if( GET_DIDEVICE_TYPE(pdinst->dwDevType)==DIDEVTYPE_MOUSE || 
		GET_DIDEVICE_TYPE(pdinst->dwDevType)==DIDEVTYPE_KEYBOARD )
		return DIENUM_CONTINUE;
#endif

	LPDIRECTINPUTDEVICE7 pdev;
	DIPROPRANGE diprg;

	if (g_CMData.m_numJoysticks == MAX_DI_DEVICES)
		return false;
//
// Create the joystick device

	AllowFail=1;
	HRESULT hr=wCreateDeviceEx(g_CMData.m_lpDirectInput7, pdinst->guidInstance, IID_IDirectInputDevice7, (void **) &pdev, NULL);
	AllowFail=0;
	if( DI_OK!=hr )
		return DIENUM_CONTINUE;
//
// Setup the cooperative level  (from the top level window)
//
	HWND tempHW=hWindow;
	while( GetParent( tempHW ) )
		tempHW=GetParent( tempHW );
	
	wSetCooperativeLevel(pdev, tempHW, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
//
// Set the data format
//
	if (wSetDataFormat(pdev, &c_dfDIJoystick) != DI_OK)
	{
		STOP(( "Couldn't set data format on joystick" ));
		wRelease(pdev);
		return DIENUM_CONTINUE;
	}

	DIDEVICEINSTANCE di;
	memset(&di,0,sizeof(di));
	di.dwSize = sizeof(di);
	wGetDeviceInfo(pdev, &di);
	strncpy(g_CMData.m_joyName[g_CMData.m_numJoysticks],di.tszProductName,64);
	wQueryInterface(pdev,IID_IDirectInputDevice7,(void**)&g_CMData.m_lpJoystick7[g_CMData.m_numJoysticks]);
	wRelease(pdev);

	DIDEVCAPS dcaps;
	memset(&dcaps,0,sizeof(dcaps));
	dcaps.dwSize = sizeof(dcaps);
	wGetCapabilities(g_CMData.m_lpJoystick7[g_CMData.m_numJoysticks], &dcaps);

	if (dcaps.dwAxes == 0 || dcaps.dwButtons == 0)
	{
		//
		// Microsoft Hardware is at it again. This will check against any misreported devices. I don't expect
		// there will every be any joysticks with 0 axes. Ignore if one is detect, it's not really a joystick.
		//
		wRelease(g_CMData.m_lpJoystick7[g_CMData.m_numJoysticks]);
		return DIENUM_CONTINUE;
	}

	g_CMData.m_numSliders[g_CMData.m_numJoysticks] = 0;
	g_CMData.m_disabled[g_CMData.m_numJoysticks]=0;
	g_CMData.m_bForceFeedback[g_CMData.m_numJoysticks] = (!gDisableForceFeedback && (dcaps.dwFlags & DIDC_FORCEFEEDBACK)) ? true : false;
	diprg.diph.dwSize = sizeof(diprg);
	diprg.diph.dwHeaderSize = sizeof(diprg.diph);
	diprg.diph.dwObj = DIJOFS_X;
	diprg.diph.dwHow = DIPH_BYOFFSET;
	diprg.lMin = -1000;
	diprg.lMax = 1000;

	// inquire as to which axes are valid on this joystick
	g_CMData.m_validAxis[g_CMData.m_numJoysticks][0] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][1] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][2] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][3] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][4] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][5] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][6] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][7] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][8] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][9] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][10] = 
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][11] = FALSE;

	AllowFail = true;
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][0] = TRUE;

	diprg.diph.dwObj = DIJOFS_Y;
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][1] = TRUE;
	
	diprg.diph.dwObj = DIJOFS_Z;
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][2] = TRUE;

	diprg.diph.dwObj = DIJOFS_RX;
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][3] = TRUE;
	
	diprg.diph.dwObj = DIJOFS_RY;
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][4] = TRUE;
	
	diprg.diph.dwObj = DIJOFS_RZ;
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][5] = TRUE;
	
	diprg.diph.dwObj = DIJOFS_SLIDER(0);
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
	{
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][6] = TRUE;
		g_CMData.m_numSliders[g_CMData.m_numJoysticks] += 1;
	}
	diprg.diph.dwObj = DIJOFS_SLIDER(1);
	if( wSetProperty( pdev, DIPROP_RANGE, &diprg.diph) == DI_OK)
	{
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][7] = TRUE;
		g_CMData.m_numSliders[g_CMData.m_numJoysticks] += 1;
	}
	AllowFail = false;

	// get the number of buttons on the controller
	g_CMData.m_numButtons[g_CMData.m_numJoysticks] = (unsigned char) dcaps.dwButtons;

	// get the number of POV-style switches on the controller
	// and let the gameos end know they're valud
	g_CMData.m_numPOVs[g_CMData.m_numJoysticks] =  (unsigned char) dcaps.dwPOVs;
	for(DWORD i = 0; i < g_CMData.m_numPOVs[g_CMData.m_numJoysticks]; i++)
		g_CMData.m_validAxis[g_CMData.m_numJoysticks][i+8] = TRUE;

	// acquire the controller and read the initial values into our storage format
	AllowFail = 1;
	wAcquire(g_CMData.m_lpJoystick7[g_CMData.m_numJoysticks]);
	AllowFail = 0;
	CMReadJoystick(g_CMData.m_numJoysticks);
	CMRestoreEffects(g_CMData.m_numJoysticks);

	// as this was a valid joystick, increment that valid stick count by one
	g_CMData.m_numJoysticks++;
	return DIENUM_CONTINUE;
}

// Get the very latest information from the specifed joystick.
void CMReadJoystick(DWORD index)
{
	DIJOYSTATE js;
	memset(&js,0,sizeof(js));

    // jcem - begin
    if (g_bUseOrgJoy) {
    // jcem - end
	if( g_CMData.m_lpJoystick7[index]==0 )
		return;

	if (g_CMData.m_nextPoll[index] <= gos_GetElapsedTime(1))
		 g_CMData.m_nextPoll[index] = gos_GetElapsedTime(1) +  g_CMData.m_howOften[index];
	else
		return;

	AllowFail = 1;
	SafeFPU();					// Make sure exceptions cannot be generated
	HRESULT rs = wPoll(g_CMData.m_lpJoystick7[index]);

	GameOSFPU();				// Restore current GameOS FPU control word setup
	AllowFail = 0;
	if( rs!=DI_OK && rs!=DI_NOEFFECT )
	{
		g_CMData.m_requiresAcquire = true;
		return;
	}
	AllowFail = 1;
	rs = wGetDeviceState(g_CMData.m_lpJoystick7[index], sizeof(DIJOYSTATE), &js);

	AllowFail = 0;
	if( rs==DIERR_INPUTLOST || rs==DIERR_NOTACQUIRED )
	{  
		g_CMData.m_requiresAcquire =  true;
		return;
	}
	else if( rs!=DI_OK )
	{
		STOP(( "Unabled to perform 'GetDeviceState' on joystick" ));
	}
    // jcem - begin
    } else {
	    if (g_CMData.m_nextPoll[index] <= gos_GetElapsedTime(1))
		     g_CMData.m_nextPoll[index] = gos_GetElapsedTime(1) +  g_CMData.m_howOften[index];
	    else
		    return;
	    if (g_pfnRIO_Joy) {
	        AllowFail = 1;
	        SafeFPU();					// Make sure exceptions cannot be generated

		    (*g_pfnRIO_Joy)(js);

	        GameOSFPU();				// Restore current GameOS FPU control word setup
	        AllowFail = 0;
        } else {
            return;
        }
    }
    // jcem - end

	// fill our storage format with the latest joystick information.
	g_CMData.m_joyAxis[index][0] = js.lX;
	g_CMData.m_joyAxis[index][1] = js.lY;
	g_CMData.m_joyAxis[index][2] = js.lZ;
	g_CMData.m_joyAxis[index][3] = js.lRx;
	g_CMData.m_joyAxis[index][4] = js.lRy;
	g_CMData.m_joyAxis[index][5] = js.lRz;
	g_CMData.m_joyAxis[index][6] = js.rglSlider[0];
	g_CMData.m_joyAxis[index][7] = js.rglSlider[1];
	g_CMData.m_joyAxis[index][8] = js.rgdwPOV[0];
	g_CMData.m_joyAxis[index][9] = js.rgdwPOV[1];
	g_CMData.m_joyAxis[index][10] = js.rgdwPOV[2];
	g_CMData.m_joyAxis[index][11] = js.rgdwPOV[3];
#if defined(_DEBUG) && 0 // jcem
	static char s_sz[256];
	/*    
    sprintf(s_sz, "lX: %d, lY: %d, lZ: %d, lRx: %d, lRy: %d, lRz: %d, Sl[0]: %d, POV[0]: %d\n",
        js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz, js.rglSlider[0], js.rgdwPOV[0]);
    ::OutputDebugString(s_sz);
	*/

	sprintf(s_sz, "Sl[0]: %d, \n", js.rglSlider[0]);
    ::OutputDebugString(s_sz);
#endif // jcem
	// generate button events as appropriate
	if(Environment.ButtonsAsKeys)
	{
		int button;
		for(button = 0; button < 64; ++button)
		{
			if(js.rgbButtons[button] && !g_CMData.m_joyButton[index][button])
			{
				AddKeyEvent(KEYDEV_JOYSTICK | (index << 16) | (button << 8));
			}
			g_CMData.m_joyButton[index][button] = js.rgbButtons[button];
		}
	}
	else
		memcpy(g_CMData.m_joyButton[index], js.rgbButtons, 64);
}

void __stdcall gosJoystick_GetInfo(DWORD index, gosJoystick_Info * gji)
{
	gosJoystick_Info ji;
	memset(&ji, 0, sizeof(gosJoystick_Info));

	if( 1==LogMode )
	{
//
// Playing back a log file
//
		if( DebuggerActive && InDebugger )
		{
			return;
		}
		
		for( int t0=0; t0<sizeof(gosJoystick_Info); t0++ )
		{
			*((BYTE*)&ji+t0)=(BYTE)ReadBitStream(8,Log_JoystickInfo);
		}

		memcpy( gji, &ji, sizeof(gosJoystick_Info) );

		return;
	}
//
// Recording a log file
//		
	gosASSERT(index < g_CMData.m_numJoysticks);

	
	ji.bIsForceFeedback =	g_CMData.m_bForceFeedback[index];
	ji.nAxes = 0;
	ji.lpstrName = g_CMData.m_joyName[index];
	ji.bIsPolled = g_CMData.m_pollMe[index];
	ji.nButtons = g_CMData.m_numButtons[index];
	ji.nSliders = g_CMData.m_numSliders[index];
	ji.nPOVs = g_CMData.m_numPOVs[index];
	for(int i=0; i < 12; i ++)
	{
		if (g_CMData.m_validAxis[index][i])
		{
			ji.nAxes++;
			ji.bAxisValid |= 1<<i;
		}
	}

	if( !InDebugger )
	{
		for( int t0=0; t0<sizeof(gosJoystick_Info); t0++ )
		{
			SPEW(( "GameOS_LogFile", "gosJoystick_GetInfo(%d)",index ));
			WriteBitStream(*((BYTE*)&ji+t0), 8, Log_JoystickInfo);
		}
	}

	memcpy( gji, &ji, sizeof(gosJoystick_Info) );

	return;
}

void CMRestoreEffects(int stick)
{
	if (stick == -1)
	{
		// do all sticks
		for( DWORD i=0; i < g_CMData.m_numJoysticks; i++ )
		{
			if( g_CMData.m_lpJoystick7[i] && ! g_CMData.m_disabled[i] )
			{
				//
				// Download the effects again...
				//
				HGOSFORCEEFFECT itr = gForceEffects;
				while(itr)
				{
					if (i == itr->dwStick)
						itr->ReCreate();
					itr = itr->pNext;
				}
			}
		}
	}
	else
	{
		if( g_CMData.m_lpJoystick7[stick] && ! g_CMData.m_disabled[stick] )
		{
			//
			// Download the effects again...
			//
			HGOSFORCEEFFECT itr = gForceEffects;
			while(itr)
			{
				if (stick == itr->dwStick)
					itr->ReCreate();
				itr = itr->pNext;
			}
		}
	}
}
