#include "RBC9-SpaceNav.h"



#pragma warning(disable : 4996)
void RBC9_Wait(short MilliSec)
{
	LARGE_INTEGER time;

	time.QuadPart = -10 * 1000 * MilliSec;
	KeDelayExecutionThread(KernelMode, FALSE, &time);

}

VOID RBC9_Create_Next_From(PBIND_LIST NewBind,
						   BIND_FROM BindFrom,UCHAR Num,BOOLEAN Invert,short MinVal,short MaxVal,short AxePart)
{



	NewBind->BindFrom = BindFrom;
	switch (BindFrom)
	{
	case BIND_FROM_AXE:

		NewBind->FromAxe.NumAxe = Num;
		NewBind->FromAxe.Invert = Invert;
		NewBind->FromAxe.DeadVal = 0;
		NewBind->FromAxe.MinVal = MinVal;
		NewBind->FromAxe.MaxVal = MaxVal;
		NewBind->FromAxe.AxePart = AxePart;
		break;

	case BIND_FROM_BTN:

		NewBind->FromBtn.NumBtn = Num;
		NewBind->FromBtn.Invert = Invert;
		NewBind->FromBtn.FalseVal = MinVal;
		NewBind->FromBtn.TrueVal = MaxVal;
		NewBind->FromType.Type = AxePart;
		NewBind->FromType.Delay = 500;


		if	((NewBind->FromBtn.FalseVal ==0) && (NewBind->FromBtn.TrueVal==0))
			NewBind->FromBtn.TrueVal = 1;

		break;
	}

}

VOID RBC9_Create_Next_To(PBIND_LIST NewBind, BIND_TO BindTo,short Param)
{

	NewBind->BindTo = BindTo;

	switch (BindTo)
	{
	case BIND_TO_JOYSTICK_AXE:

		NewBind->Joy.Axe = (CHAR) Param;
		if(NewBind->Joy.Axe > (INPUT_REPORT_NUM_JOY_AXE-1)) NewBind->Joy.Axe=(INPUT_REPORT_NUM_JOY_AXE-1);
		break;

	case BIND_TO_JOYSTICK_BTN:

		NewBind->Joy.Btn = (CHAR) Param;
		if(NewBind->Joy.Btn > (INPUT_REPORT_NUM_JOY_BUTTON-1)) NewBind->Joy.Btn=(INPUT_REPORT_NUM_JOY_BUTTON-1);
		break;

	case BIND_TO_JOYSTICK_POV:

		NewBind->Joy.POV = (CHAR) Param;
		if (NewBind->Joy.POV > 1) NewBind->Joy.POV = 1;
		break;

	case BIND_TO_MOUSE_X:
		NewBind->Mou.Sensi = (CHAR) Param;
		break;

	case BIND_TO_MOUSE_Y:

		NewBind->Mou.Sensi = (CHAR) Param;
		break;
	case BIND_TO_MOUSE_WHEEL:

		NewBind->Mou.Wheel_Speed = (CHAR) Param;
		break;

	case BIND_TO_MOUSE_BTN:

		NewBind->Mou.Btn = (CHAR) Param;
		if(NewBind->Mou.Btn > (INPUT_REPORT_NUM_MOU_BUTTON-1)) NewBind->Mou.Btn=(INPUT_REPORT_NUM_MOU_BUTTON-1);
		break;

	case BIND_TO_PROFIL:

		NewBind->Profil_Id = Param;
		break;

	case BIND_TO_WWW:
			NewBind->www = (CHAR) Param;
		break;

	}

}

VOID RBC9_Create_NextBind(PBIND_LIST *LastBind,
						  BIND_FROM BindFrom,UCHAR Num,BOOLEAN Invert,short MinVal,short MaxVal,short AxePart,
						  BIND_TO BindTo,short Param
								)
{
	PBIND_LIST NewBind = (PBIND_LIST)  ExAllocatePool(NonPagedPool, sizeof(BIND_LIST));

	if (NewBind == NULL)
	{
		DBG_LEAVE(("ExAllocatePool Error"));
		return;
	}

	NewBind->NextBind = *LastBind;
	*LastBind = NewBind;

	RBC9_Create_Next_From(NewBind,BindFrom,Num,Invert,MinVal,MaxVal,AxePart);

	RBC9_Create_Next_To(NewBind,BindTo,Param);

}

VOID RBC9_Create_NextBind_KEYB(PBIND_LIST *LastBind,
							   BIND_FROM BindFrom,UCHAR Num,BOOLEAN Invert,short MinVal,short MaxVal,short AxePart,
							   BIND_TO BindTo,KEY_BIND Param
							   )
{
	PBIND_LIST NewBind = (PBIND_LIST)  ExAllocatePool(NonPagedPool, sizeof(BIND_LIST));

	if (NewBind == NULL)
	{
		DBG_LEAVE(("ExAllocatePool Error"));
		return;
	}

	NewBind->NextBind = *LastBind;
	*LastBind = NewBind;

	RBC9_Create_Next_From(NewBind,BindFrom,Num,Invert,MinVal,MaxVal,AxePart);

	NewBind->BindTo = BindTo;

	NewBind->Key = Param;

}


PPROFIL RBC9_Profil_ZERO(IN PDEVICE_OBJECT pDev_obj)
{

	PPROFIL		Profil_First = (PPROFIL)  ExAllocatePool(NonPagedPool, sizeof(PROFIL));
	PBIND_LIST	Bind_Liste;	
	KEY_BIND	MyKeyTest;

	DBG_ENTER((""));

	if (Profil_First == NULL)
	{
		DBG_LEAVE(("ExAllocatePool Error"));
		return NULL;
	}

	Profil_First->Profil_Id = -1;
	Profil_First->NextProfil = NULL;

	RtlCopyMemory(&Profil_First->ProfilName[0], L"Base Profil", sizeof(L"Base Profil"));

	Profil_First->DeadVal = 50; /* % Dead */

	Profil_First->Bind_Liste = NULL;

	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,3,FALSE,15,0,AXE_ALL,BIND_TO_JOYSTICK_POV,POV_VERT);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,4,FALSE,15,0,AXE_ALL,BIND_TO_JOYSTICK_POV,POV_HORI);

	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,0,FALSE,0,0,AXE_ALL,BIND_TO_JOYSTICK_AXE,0);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,1,FALSE,0,0,AXE_ALL,BIND_TO_JOYSTICK_AXE,1);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,2,FALSE,0,0,AXE_ALL,BIND_TO_JOYSTICK_AXE,2);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,4,FALSE,0,0,AXE_ALL,BIND_TO_JOYSTICK_AXE,3);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,3,FALSE,0,0,AXE_ALL,BIND_TO_JOYSTICK_AXE,4);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,5,FALSE,0,0,AXE_ALL,BIND_TO_JOYSTICK_AXE,5);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,5,TRUE,0,0,AXE_POS,BIND_TO_JOYSTICK_AXE,6);

	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,350,0,BIND_TO_JOYSTICK_AXE,7);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,TRUE,0,-350,0,BIND_TO_JOYSTICK_AXE,7);

	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,0,FALSE,0,1,0,BIND_TO_JOYSTICK_BTN,0);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,0,TRUE,0,1,0,BIND_TO_JOYSTICK_BTN,1);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,1,0,BIND_TO_JOYSTICK_BTN,4);

	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,4,FALSE,0,0,AXE_ALL,BIND_TO_MOUSE_X,100);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,3,FALSE,0,0,AXE_ALL,BIND_TO_MOUSE_Y,100);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_AXE,5,TRUE,10,0,AXE_ALL,BIND_TO_MOUSE_WHEEL,500);

	//RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,0,FALSE,0,0,0,BIND_TO_MOUSE_BTN,0);
	//RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,0,0,BIND_TO_MOUSE_BTN,1);

	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,0,FALSE,0,0,0,BIND_TO_WWW,0x02);
	RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,0,0,BIND_TO_WWW,0x03);

	//RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,0,0,BIND_TO_PROFIL,25);

	//RBC9_Create_NextBind(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,0,0,BIND_TO_TEST,0);

/*	RtlZeroMemory(&MyKeyTest, sizeof(MyKeyTest));

	MyKeyTest.Event = KEY_BTN;
	MyKeyTest.FireDelay = 0;
	MyKeyTest.Code[0]=0x04;

	RBC9_Create_NextBind_KEYB(&Profil_First->Bind_Liste,BIND_FROM_BTN,0,FALSE,0,0,BTN_LONG,BIND_TO_KEYB,MyKeyTest);
	
	MyKeyTest.Code[0]=0x05;

	RBC9_Create_NextBind_KEYB(&Profil_First->Bind_Liste,BIND_FROM_BTN,0,FALSE,0,0,BTN_SHORT,BIND_TO_KEYB,MyKeyTest);

	//MyKeyTest.Code[0]=0x05;
	//MyKeyTest.Code[1]=0x06;
	//MyKeyTest.Code[2]=0x07;
	//MyKeyTest.Code[3]=0x08;
	MyKeyTest.Code[0]=0x08;
	MyKeyTest.Code[1]=0x00;
	RBC9_Create_NextBind_KEYB(&Profil_First->Bind_Liste,BIND_FROM_BTN,1,FALSE,0,0,0,BIND_TO_WWW,MyKeyTest);

	MyKeyTest.Event = KEY_REPEAT;
	MyKeyTest.FireDelay = 500;
	MyKeyTest.Code[0]=0x2b;
	RBC9_Create_NextBind_KEYB(&Profil_First->Bind_Liste,BIND_FROM_AXE,2,FALSE,180,0,AXE_POS,BIND_TO_KEYB,MyKeyTest);
	*/
	
		DBG_LEAVE((""));

	return Profil_First;
}

VOID RBC9_Load_Profil(IN PDEVICE_OBJECT pDev_obj,IN PWSTR LayerName)
{
	PDEVICE_EXTENSION		pDevExt=GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	PPROFIL					*FirsProfil=&pDevExt->Profil_First;
	NTSTATUS				Status;

	HANDLE					LayerKey;

	PPROFIL					NewProfil;

	LONG					_Profil_Id;
	LONG					_DeadZone;

	unsigned int			BindBcl;
	unsigned int			BindNbr;
	WCHAR					BindName[256];
	UNICODE_STRING			BindKeyName;
	LONG					BindType;
	PBIND_LIST				NewBind;

		DBG_ENTER(("Open Layer %ws",LayerName));

	LayerKey = RBC9_Open_Reg(pDevExt->RegPath.Buffer,LayerName);
	if(LayerKey == NULL) 
	{
		DBG_LEAVE(("STATUS_OBJECT_NAME_NOT_FOUND"));
		return ;
	}

	Status = RBC9_Get_DWORD(LayerKey, L"Profil_Id", &_Profil_Id, 0);

	if(! NT_SUCCESS(Status)) {
		ZwClose(LayerKey);
		DBG_LEAVE(("Profil_Id Not Found %x", Status));
		return;
	}

	if ( RBC9_Profil_Exist(pDev_obj,(short)_Profil_Id))
	{
			ZwClose(LayerKey);
			DBG_LEAVE(("Profil_Id %d Already Exist %x",_Profil_Id, Status));
			return;
	}


	NewProfil = (PPROFIL)  ExAllocatePool(NonPagedPool, sizeof(PROFIL));

	NewProfil->Profil_Id	= (short)_Profil_Id;
	NewProfil->NextProfil	= *FirsProfil;
	*FirsProfil				= NewProfil;

	NewProfil->Bind_Liste = NULL;

	RBC9_Get_STRING(LayerKey, L"Profil_Name", NewProfil->ProfilName, sizeof(NewProfil->ProfilName));
	RBC9_Get_DWORD(LayerKey, L"DeadZone", &_DeadZone, 0);

	NewProfil->DeadVal = (short)_DeadZone;

	DBG_OUT(("Profil_Id %d - Profil_Name %ws  - DeadZone %d ",_Profil_Id,NewProfil->ProfilName,_DeadZone));

	if(NT_SUCCESS(RBC9_Get_Key_Info(LayerKey,NULL,&BindNbr))) 
	{

		RtlInitUnicodeString(&BindKeyName, L"Bind - ");

		for (BindBcl = 0 ;BindBcl <  BindNbr;BindBcl++)
		{
			if(NT_SUCCESS(RBC9_Get_Value_Info(LayerKey,BindBcl,BindName,256,&BindType))) 
			{
				if (BindType == REG_BINARY)
				{
					if(RtlCompareMemory(BindName, BindKeyName.Buffer,BindKeyName.Length) == BindKeyName.Length) 
					{
						//DBG_OUT(("Bind %ws OK",BindName));

						NewBind = (PBIND_LIST)  ExAllocatePool(NonPagedPool, sizeof(BIND_LIST));

						if (NewBind != NULL)
						{
							RtlZeroMemory(NewBind, sizeof(BIND_LIST));
							RBC9_Get_BINARY(LayerKey,BindName,NewBind,sizeof(BIND_LIST)-sizeof(NAV_STATUS)-sizeof(PBIND_LIST));
						//	DBG_OUT(("Read Bind %d %d %d",sizeof(BIND_LIST),NewBind->BindFrom,NewBind->BindTo));
						
							RtlZeroMemory(&NewBind->Nav, sizeof(NewBind->Nav));

							NewBind->NextBind = NewProfil->Bind_Liste;
						
							NewProfil->Bind_Liste = NewBind;

						}
					}
				}
			}
		}
	}


	ZwClose(LayerKey);

	DBG_LEAVE((""));
}

VOID RBC9_Get_Profils(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION		pDevExt=GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	NTSTATUS				Status;

	HANDLE					RegKey;

	unsigned int			LayerBcl;
	unsigned int			LayerNbr;
	WCHAR					LayerName[256];
	UNICODE_STRING			LayerKeyName;

	LONG					_Default_Profil;

	DBG_ENTER((""));


	/* open key */
	RegKey = RBC9_Open_Reg(pDevExt->RegPath.Buffer,NULL);
	if(RegKey == NULL) {
		DBG_LEAVE(("STATUS_OBJECT_NAME_NOT_FOUND"));
		return ;
	}

	/* Nombre de profil ? */
	Status = RBC9_Get_Key_Info(RegKey,&LayerNbr,NULL);
	if(! NT_SUCCESS(Status)) {
		DBG_LEAVE(("Error Get Info Key %x", Status));
		return;
	}


	RBC9_Get_DWORD(RegKey, L"Default_Profil", &_Default_Profil, 0);

	pDevExt->Profil_Id = (short)_Default_Profil;

	RtlInitUnicodeString(&LayerKeyName, L"Layout - ");

	for (LayerBcl = 0;LayerBcl < LayerNbr;LayerBcl++)	
	{
		Status = RBC9_Get_SubKey_Name(RegKey,LayerBcl,LayerName,256);
		if(NT_SUCCESS(Status)) 
		{
			if(RtlCompareMemory(LayerName, LayerKeyName.Buffer,LayerKeyName.Length) == LayerKeyName.Length) 
			{
				RBC9_Load_Profil(pDev_obj,LayerName);
			}
		}
	}


	ZwClose(RegKey);

	DBG_LEAVE(("Fin OK %x",Status));
}

VOID RBC9_InitState(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION	pDevExt;
	unsigned int		index;
	short				ActifProfil;
	DBG_ENTER(("Build - %d",DRIVER_VERSION_BUILD));

	pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);

	if (pDevExt->Profil_Actif != NULL)
	{
		ActifProfil = pDevExt->Profil_Actif->Profil_Id;
	}
	else
	{
		ActifProfil = -1;
	}

	RBC9_Delete_Profil(pDev_obj);
	pDevExt->Profil_First = RBC9_Profil_ZERO(pDev_obj);
	pDevExt->Profil_Actif = NULL;

	RBC9_Get_Profils(pDev_obj);

	RBC9_Led_Queue_Delete(pDev_obj);

	pDevExt->Special_Action.Running = FALSE;
	pDevExt->Special_Action.Time_Action = 0;
	pDevExt->Special_Action.Start_Detect = 0;
	pDevExt->Special_Action.MinTime = 1500;

	//DBG_OUT(("Init Change x-%d",DRIVER_VERSION_BUILD));
	//	pDevExt->hid_input_changed = INPUT_TYPE_JOYSTICK | INPUT_TYPE_NAV_ALL | INPUT_TYPE_MOUSE | INPUT_TYPE_WWW | INPUT_TYPE_KEYBOARD;
	pDevExt->hid_input_changed = INPUT_TYPE_ALL;


	RtlZeroMemory(&pDevExt->hwInData, sizeof(pDevExt->hwInData));

	RtlZeroMemory(&pDevExt->input_state, sizeof(pDevExt->input_state));
	pDevExt->input_state.joy.report_id = REPORT_ID_JOY;
	pDevExt->input_state.kbd.report_id = REPORT_ID_KEY;
	pDevExt->input_state.www.report_id = REPORT_ID_WWWKEY;
	pDevExt->input_state.mou.report_id = REPORT_ID_MOU;
	pDevExt->input_state.Info.report_id = REPORT_ID_CMD;
	pDevExt->input_state.SpaceNav.Trame[0].report_id = REPORT_ID_NAV_ID1;
	pDevExt->input_state.SpaceNav.Trame[1].report_id = REPORT_ID_NAV_ID2;
	pDevExt->input_state.SpaceNav.Trame[2].report_id = REPORT_ID_NAV_ID3;

	for(index=0; index<INPUT_REPORT_NUM_JOY_AXE; pDevExt->input_state.joy.axis[index++]=JOY_OFFSET);

	RtlZeroMemory(&pDevExt->KeyB, sizeof(pDevExt->KeyB));
	RtlZeroMemory(&pDevExt->Mouse, sizeof(pDevExt->Mouse));

	if (ActifProfil != -1)
	{
		pDevExt->Profil_Actif = RBC9_Select_Profil(pDev_obj,ActifProfil);
	}
	else
	{
		pDevExt->Profil_Actif = RBC9_Select_Profil(pDev_obj,pDevExt->Profil_Id);
	}

	RBC9_SEQ_Init_HID(pDev_obj);

	DBG_LEAVE((""));
}	

VOID RBC9_Delete_Bind(IN PPROFIL ClearProfil)
{
	PBIND_LIST	FirstBind;
	PBIND_LIST	NextBind;
	//	int			BindNum=1;

	DBG_ENTER((""));


	FirstBind = ClearProfil->Bind_Liste;

	while(FirstBind !=NULL)
	{
		NextBind = FirstBind->NextBind;

		//		DBG_OUT(("Delete Bind %d",BindNum++));
		ExFreePool(FirstBind);

		FirstBind = NextBind;
	}

	DBG_LEAVE((""));	
}

VOID RBC9_Delete_Profil(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION	pDevExt= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	PPROFIL				FirstProfil;
	PPROFIL				NextProfil;

	DBG_ENTER(("%p", pDev_obj));

	FirstProfil=pDevExt->Profil_First;
	pDevExt->Profil_First = NULL;
	pDevExt->Profil_Actif = NULL;

	while(FirstProfil !=NULL)
	{
		NextProfil = FirstProfil->NextProfil;

		DBG_OUT(("Delete Profil : %ws",FirstProfil->ProfilName));
		RBC9_Delete_Bind(FirstProfil);

		ExFreePool(FirstProfil);

		FirstProfil = NextProfil;

	}

	DBG_LEAVE((""));
}

BOOLEAN RBC9_Profil_Exist(IN PDEVICE_OBJECT pDev_obj,short Profil_Id)
{
	PDEVICE_EXTENSION		pDevExt= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	PPROFIL					SelectProfil=pDevExt->Profil_First;

	DBG_ENTER(("%p Check Profil %d", pDev_obj,Profil_Id));
	while(SelectProfil != NULL)
	{
		if(SelectProfil->Profil_Id == Profil_Id)
		{
			DBG_LEAVE(("Check Found Profil %d ",Profil_Id));

			return TRUE;
		}
		SelectProfil = SelectProfil->NextProfil;
	}

	DBG_LEAVE(("OK Not Found"));
	return FALSE;
}

PPROFIL RBC9_Select_Profil(IN PDEVICE_OBJECT pDev_obj,short Profil_Id)
{
	PDEVICE_EXTENSION		pDevExt= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	PPROFIL					SelectProfil=pDevExt->Profil_First;

	DBG_ENTER(("%p Search Profil %d", pDev_obj,Profil_Id));
	while(SelectProfil != NULL)
	{
		if(SelectProfil->Profil_Id == Profil_Id)
		{
			DBG_LEAVE(("Found Profil %d ",Profil_Id));
			RBC9_Clear_KeyB_Buffer(pDev_obj,TRUE);
			RBC9_SEQ_Change_Profil(pDev_obj);
			return SelectProfil;
		}
		SelectProfil = SelectProfil->NextProfil;
	}

	if ((Profil_Id != pDevExt->Profil_Id) & (Profil_Id != -1))
	{
		DBG_OUT(("Profil %d Not Found look for default %d",Profil_Id,pDevExt->Profil_Id));
		return RBC9_Select_Profil(pDev_obj,pDevExt->Profil_Id);
	}

	if (Profil_Id != -1)
	{
		DBG_OUT(("Profil %d Not Found look for -1",Profil_Id));
		return RBC9_Select_Profil(pDev_obj,-1);
	}

	DBG_LEAVE(("Not Found"));
	return NULL;
}

VOID RBC9_Select_Next_Profil(IN PDEVICE_OBJECT pDev_obj)
{

	PDEVICE_EXTENSION	pDevExt= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);

	RBC9_SEQ_Change_Profil(pDev_obj);

	pDevExt->Profil_Actif = pDevExt->Profil_Actif->NextProfil;
	if(pDevExt->Profil_Actif == NULL)
	{
		pDevExt->Profil_Actif = pDevExt->Profil_First;
	}

	DBG_OUT(("Switch to %d",pDevExt->Profil_Actif->Profil_Id));
}



short RBC9_NavState(PBIND_LIST BindToDo,BOOLEAN OnVal,short TrueVal,short FalseVal)
{
	ULONGLONG			cur_time	= KeQueryInterruptTime();

	if (OnVal != BindToDo->Nav.Last_On)
	{
		BindToDo->Nav.Last_On = OnVal;

		if (OnVal)
		{
			BindToDo->Nav.Last_Press = cur_time;
			BindToDo->Nav.Last_Val = TrueVal;
		}
		else
		{
			BindToDo->Nav.Last_Release = cur_time;
		}

	}

	switch (BindToDo->FromType.Type)
	{
	case PRESS_STD:
		return OnVal ? TrueVal : FalseVal;
		break;


	case PRESS_SHORT:
		
		if (!OnVal)
		{
			if (cur_time < (BindToDo->Nav.Last_Release + (1 * 10 * 1000)))
			{
				if ( (BindToDo->Nav.Last_Release - BindToDo->Nav.Last_Press) < (BindToDo->FromType.Delay * 10 * 1000))
				{
					return BindToDo->Nav.Last_Val;
				}
			}
		}
		
		break;

	case PRESS_LONG:

		if (OnVal)
		{
			if (cur_time > (BindToDo->Nav.Last_Press + (BindToDo->FromType.Delay * 10 * 1000)))
			{
				return TrueVal;
			}

		}
		break;
	}


	return FalseVal;

}
short RBC9_Get_AxeVal(IN PDEVICE_OBJECT pDev_obj,PBIND_LIST BindToDo)
{
	PDEVICE_EXTENSION	pDevExt= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	short				NewVal;
	short				New_Max_Value;
	short				CurDeadVal;
	short Signe;
	
	NewVal = pDevExt->input_state.SpaceNav.Trame[BindToDo->FromAxe.NumAxe / 3].Axe[BindToDo->FromAxe.NumAxe % 3];

	if (BindToDo->FromAxe.NumAxe == 4) NewVal *=-1;
	
	Signe = NewVal >= 0 ? 1 : -1;
	
	NewVal = (short) abs(NewVal);

	CurDeadVal = pDevExt->Profil_Actif->DeadVal + BindToDo->FromAxe.DeadVal;
	
	if (CurDeadVal >= NAV_MAX_VALUE)
	{
		CurDeadVal = NAV_MAX_VALUE-1;
	}
	New_Max_Value = NAV_MAX_VALUE - CurDeadVal;

	if(NewVal >= CurDeadVal)
	{
		NewVal=(short) NewVal - CurDeadVal;
	}
	else
	{
		NewVal = 0;
	}

	NewVal = (NewVal * NAV_MAX_VALUE) / New_Max_Value;

	if(NewVal > NAV_MAX_VALUE)
	{
		NewVal=(short)(NAV_MAX_VALUE);	
	}

	if(NewVal < BindToDo->FromAxe.MinVal )
	{
		NewVal =0;
	}

	if((NewVal > BindToDo->FromAxe.MaxVal ) && (BindToDo->FromAxe.MaxVal !=0))
	{
		NewVal =0;
	}

	NewVal= NewVal * Signe;

	if(BindToDo->FromAxe.Invert)
	{
		NewVal= NewVal * (-1);
	}

	switch (BindToDo->FromAxe.AxePart)
	{
	case AXE_POS:
		if(NewVal <0)
		{
			NewVal = 0;
		}
		break;
	case AXE_NEG:
		if(NewVal >0)
		{
			NewVal = 0;
		}
		break;
	}

//DBG_OUT(("%d",NewVal));

	return RBC9_NavState(BindToDo,(NewVal != 0)  ,NewVal,0);

}
short RBC9_Get_BtnVal(IN PDEVICE_OBJECT pDev_obj,PBIND_LIST BindToDo)
{
	PDEVICE_EXTENSION	pDevExt		= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	CHAR				BitMask;
	BOOLEAN				NewVal = FALSE;

	BitMask = 1 << (BindToDo->FromBtn.NumBtn % 8);

	NewVal = ((pDevExt->input_state.SpaceNav.Trame[2].Btn[BindToDo->FromBtn.NumBtn / 8] & BitMask) == BitMask);

	if(BindToDo->FromBtn.Invert)
	{
		NewVal = ! NewVal;
	}

	return RBC9_NavState(BindToDo,NewVal,BindToDo->FromBtn.TrueVal,BindToDo->FromBtn.FalseVal);
	
}

short RBC9_Get_Val(IN PDEVICE_OBJECT pDev_obj,PBIND_LIST BindToDo)
{

	switch (BindToDo->BindFrom)
	{
	case BIND_FROM_AXE:
		return RBC9_Get_AxeVal(pDev_obj,BindToDo);
		break;

	case BIND_FROM_BTN:
		return RBC9_Get_BtnVal(pDev_obj,BindToDo);
		break;
	}
	return 0;
}

__int16 RBC9_Get_POV(IN BIND_POV Bind_Pov,short ValIn)
{

	int			JOY_POVBits[4] = {0x01,0x02,0x04,0x08}; // UP Right Down Left
	__int16		Tmp_POVBits=0;
	short		Vert;
	short		Hori;


	Vert = 0;
	Hori = 0;

	switch (Bind_Pov)
	{
	case POV_VERT:
		Vert=ValIn;
		break;

	case POV_HORI:
		Hori=ValIn;
		break;
	}


	if (Vert <0)
	{
		Tmp_POVBits |= JOY_POVBits[0];
	}

	if (Vert >0)
	{
		Tmp_POVBits |= JOY_POVBits[2];
	}

	if (Hori <0)
	{
		Tmp_POVBits |= JOY_POVBits[3];
	}

	if (Hori >0)
	{
		Tmp_POVBits |= JOY_POVBits[1];
	}


	return Tmp_POVBits;
}



CHAR RBC9_Get_Mouse(short ValIn,UCHAR Sensi)
{

	long MouseVal;
	long ValCarre;

	short Signe;

	Signe = ValIn >= 0 ? 1 : -1;

	ValCarre = ValIn  *  ValIn;

	MouseVal = abs ((ValCarre * MOU_MAX_VALUE * Sensi) / (NAV_MAX_CARRE *100)) ;

	if(MouseVal > MOU_MAX_VALUE)
	{
		MouseVal = MOU_MAX_VALUE;
	}

	MouseVal = Signe * MouseVal;

	return (CHAR) MouseVal;
}

VOID RBC9_Get_Wheel(PDEVICE_EXTENSION pDevExt,PBIND_LIST BindToDo,short ValIn)
{

	short PasWheel;
	short Signe;

	Signe = ValIn >= 0 ? 1 : -1;

	pDevExt->Mouse.wheel_wait = (LONG) (((abs(ValIn) - NAV_VALUE_QUICK) * (MOU_DELAY_QUICK - (BindToDo->Mou.Wheel_Speed * 10 )))
		/(NAV_VALUE_QUICK-NAV_VALUE_LENT))
		+ MOU_DELAY_QUICK;

	PasWheel = 1;
	if(abs(ValIn) >= NAV_MAX_VALUE/3)   pDevExt->Mouse.wheel_wait /= 2;
	if(abs(ValIn) >= NAV_MAX_VALUE-60)	PasWheel = 10;
	if(abs(ValIn) >= NAV_MAX_VALUE-30)	PasWheel = 25;

	pDevExt->Mouse.wheel_val =   PasWheel * Signe;

	//	DBG_INFO(("Mouse Wheel %d %d %d ",ValIn,pDevExt->Mouse.wheel_val,pDevExt->Mouse.wheel_wait));
	//DBG_OUT(("Speed Wheel %d ",BindToDo->Mou.Wheel_Speed));

}


VOID RBC9_Get_KeyB(PDEVICE_EXTENSION pDevExt,PBIND_LIST BindToDo)
{
	short BclKey;
	UCHAR KeyCode;

	for(BclKey = 0;BclKey < sizeof(BindToDo->Key.Code);BclKey++)
	{
		if((BindToDo->Key.Code[BclKey]!=0) && (BindToDo->Key.Code[BclKey]< INPUT_REPORT_NUM_KBD_CODE))
		{
			//DBG_OUT(("Key %x",BindToDo->Key.Code[BclKey]));


			//	 numbyte = (int) KeyCode;

			//DBG_OUT(("Key %d %d",numbyte,KeyCode / 8));

			KeyCode = BindToDo->Key.Code[BclKey];

			pDevExt->KeyB.Key[KeyCode].Event |= BindToDo->Key.Event;

			if(BindToDo->Key.Event & KEY_RELEASE)
			{
				pDevExt->KeyB.Key[KeyCode].Event &= ~KEY_KEEP;
			}

			if(BindToDo->Key.Event & KEY_REPEAT)
			{
				if((pDevExt->KeyB.Key[KeyCode].Fire_Delay == 0)|| (BindToDo->Key.FireDelay <pDevExt->KeyB.Key[KeyCode].Fire_Delay))
				{
					pDevExt->KeyB.Key[KeyCode].Fire_Delay = BindToDo->Key.FireDelay;
				}
			}

		}
	}
}

VOID RBC9_KeyB_Buffer(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION			pDevExt		= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	ULONGLONG					cur_time	= KeQueryInterruptTime();
	UCHAR						BclBuf;
	short						PosKey		= 0;
	BOOLEAN						TurnOn;


	pDevExt->input_state.kbd.Modifier =0;
	RtlZeroMemory(&pDevExt->input_state.kbd.keys, sizeof(pDevExt->input_state.kbd.keys));

	for (BclBuf = 0;BclBuf < INPUT_REPORT_NUM_KBD_CODE;BclBuf++)
	{

		if((pDevExt->KeyB.Key[BclBuf].Event  & KEY_BTN) || (pDevExt->KeyB.Key[BclBuf].Event  & KEY_KEEP))
		{
			TurnOn = FALSE;

			if(pDevExt->KeyB.Key[BclBuf].Event  & KEY_REPEAT)
			{
				
				if(cur_time >= pDevExt->KeyB.Key[BclBuf].Last_Fire + (pDevExt->KeyB.Key[BclBuf].Fire_Delay * 10 * 1000)) 
				{
					TurnOn = TRUE;
					//DBG_OUT(("Key Repeat : %x ? %d ",BclBuf,TurnOn));
				}
				
			}
			else
			{
				TurnOn = TRUE;
				//DBG_OUT(("Key On : %x ",BclBuf));
			}


			if (TurnOn)
			{
				if (BclBuf < KEY_BASE_MODIFIER)
				{
				//	DBG_OUT(("Key Std"));

					if (PosKey < KEY_MAX_KEY)
					{
						pDevExt->KeyB.Key[BclBuf].Last_Fire = cur_time;
						pDevExt->input_state.kbd.keys[PosKey++] = BclBuf;

						//DBG_OUT(("Key Std  ---> Add"));
					}
				}
				else
				{
					// modifier
					pDevExt->KeyB.Key[BclBuf].Last_Fire = cur_time;
					pDevExt->input_state.kbd.Modifier |= 1 << (BclBuf -  KEY_BASE_MODIFIER);

					//DBG_OUT(("Key Modifier"));
				}

			}
		}
		else
		{
			pDevExt->KeyB.Key[BclBuf].Last_Fire = 0;
		}

	}

}


VOID RBC9_Get_WWW(PDEVICE_EXTENSION pDevExt,PBIND_LIST BindToDo)
{

	UCHAR KeyCode;


	if((BindToDo->www!=0) && (BindToDo->www<= INPUT_REPORT_NUM_WWW_CODE))
	{

		KeyCode = BindToDo->www-1;

		//DBG_OUT(("WWW Key Press %d %d %d",KeyCode,KeyCode / 8,KeyCode % 8));

		pDevExt->input_state.www.keys[KeyCode / 8]  |= 1 << (KeyCode % 8);

	}

}

VOID RBC9_Set_Info(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION	pDevExt		= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	
	pDevExt->input_state.Info.Ctrl = 1;

	if (pDevExt->Profil_Actif != NULL)
	{
		pDevExt->input_state.Info.Profil_Id = pDevExt->Profil_Actif->Profil_Id;
	}
	else
	{
	    pDevExt->input_state.Info.Profil_Id = -1;
	}

}

VOID RBC9_Set_Navigator(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION	pDevExt		= GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	int					BclAxe;
	//	DBG_ENTER(("%p", pDev_obj));

	

	if ((pDevExt->hwInData.ReportId == REPORT_ID_NAV_ID1) || (pDevExt->hwInData.ReportId == REPORT_ID_NAV_ID2)|| (pDevExt->hwInData.ReportId == REPORT_ID_NAV_ID3))
	{
		pDevExt->input_state.SpaceNav.Trame[pDevExt->hwInData.ReportId-1].Axe[0] =  pDevExt->hwInData.Axe[0];
		pDevExt->input_state.SpaceNav.Trame[pDevExt->hwInData.ReportId-1].Axe[1] =  pDevExt->hwInData.Axe[1];
		pDevExt->input_state.SpaceNav.Trame[pDevExt->hwInData.ReportId-1].Axe[2] =  pDevExt->hwInData.Axe[2];

		if(pDevExt->hwInData.ReportId != REPORT_ID_NAV_ID3)
		{
			for(BclAxe = 0;BclAxe < 3; BclAxe++)
			{
				if(abs(pDevExt->input_state.SpaceNav.Trame[pDevExt->hwInData.ReportId-1].Axe[BclAxe]) > NAV_MAX_VALUE)
				{
					pDevExt->input_state.SpaceNav.Trame[pDevExt->hwInData.ReportId-1].Axe[BclAxe]=(short)((pDevExt->input_state.SpaceNav.Trame[pDevExt->hwInData.ReportId-1].Axe[BclAxe] >0) ? NAV_MAX_VALUE : -NAV_MAX_VALUE);	
				}
			}
		}
	}


	//	DBG_LEAVE((""));
}



VOID RBC9_Clear_KeyB_Buffer(IN PDEVICE_OBJECT pDev_obj,BOOLEAN ClearKeep)
{

	PDEVICE_EXTENSION			pDevExt			=	GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	unsigned int				index;

	for(index=0; index<INPUT_REPORT_NUM_KBD_CODE; index++)
	{

		if (!(pDevExt->KeyB.Key[index].Event & KEY_KEEP)|| ClearKeep)
		{
			pDevExt->KeyB.Key[index].Event = 0;
			pDevExt->KeyB.Key[index].Fire_Delay=0;
		}
	}

}


VOID RBC9_Clear_State(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION			pDevExt			=	GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	unsigned int				index;

	for(index=0; index<INPUT_REPORT_NUM_JOY_AXE; pDevExt->input_state.joy.axis[index++]=JOY_OFFSET);
	pDevExt->input_state.joy.button = 0;
	
	pDevExt->input_state.mou.x = 0;
	pDevExt->input_state.mou.y = 0;
	pDevExt->input_state.mou.button = 0;
	pDevExt->input_state.mou.wheel = 0;
	pDevExt->Mouse.wheel_val = 0;
	

	RtlZeroMemory(&pDevExt->input_state.www.keys, sizeof(pDevExt->input_state.www.keys));

	RBC9_Clear_KeyB_Buffer(pDev_obj,FALSE);
	
}

VOID RBC9_Do_Bind(IN PDEVICE_OBJECT pDev_obj)
{

	PDEVICE_EXTENSION			pDevExt			=	GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	PPROFIL						Profil_Actif	=	pDevExt->Profil_Actif;
	PBIND_LIST					BindToDo		=	Profil_Actif->Bind_Liste;
	short						ValIn;
	short						ValTo;
	__int16						POVBits;
	unsigned int				index;
	short						SwitchProfil;

	//	DBG_ENTER(("%p", pDev_obj));


	RBC9_Clear_State(pDev_obj);

	if (pDevExt->Profil_Actif == NULL) return;

	//DBG_OUT(("buf size %d",sizeof(pDevExt->input_state.kbd.keys)));

	POVBits=0;

	SwitchProfil = pDevExt->Profil_Actif->Profil_Id;

	while(BindToDo != NULL)
	{

		ValIn = RBC9_Get_Val(pDev_obj,BindToDo);

		if(ValIn !=0)
		{


			//DBG_OUT(("Do Bind From %d - ValIn %d",BindToDo->BindFrom,ValIn));

			switch (BindToDo->BindTo)
			{
			case BIND_TO_JOYSTICK_AXE:

				ValTo = ValIn + JOY_OFFSET;
				//DBG_OUT(("Do Bind From %d - ValTo %d Axe %d",BindToDo->BindFrom,ValTo,BindToDo->Joy.Axe));
				if(abs(ValIn) > abs(pDevExt->input_state.joy.axis[BindToDo->Joy.Axe]-JOY_OFFSET))
				{
					pDevExt->input_state.joy.axis[BindToDo->Joy.Axe] = ValTo;
				}
				break;

			case BIND_TO_JOYSTICK_BTN:

				pDevExt->input_state.joy.button |= (1 << (BindToDo->Joy.Btn));
				//DBG_OUT(("Joy btn : %d",pDevExt->input_state.joy.button))
				break;

			case BIND_TO_JOYSTICK_POV:

				POVBits |= RBC9_Get_POV(BindToDo->Joy.POV,ValIn);
				break;

			case BIND_TO_MOUSE_X:

				ValTo = RBC9_Get_Mouse(ValIn,BindToDo->Mou.Sensi);
				if(abs(ValTo) > abs(pDevExt->input_state.mou.x))
				{
					pDevExt->input_state.mou.x = (char) ValTo;
				}
				//DBG_OUT(("Mouse X %d %d",pDevExt->input_state.mou.x,ValIn));
				break;

			case BIND_TO_MOUSE_Y:

				ValTo = RBC9_Get_Mouse(ValIn,BindToDo->Mou.Sensi);
				if(abs(ValTo) > abs(pDevExt->input_state.mou.y))
				{
					pDevExt->input_state.mou.y = (char) ValTo;
				}
				//DBG_OUT(("Mouse Y %d",pDevExt->input_state.mou.y));
				break;

			case BIND_TO_MOUSE_WHEEL:

				RBC9_Get_Wheel(pDevExt,BindToDo,ValIn);
				break;

			case BIND_TO_MOUSE_BTN:

				pDevExt->input_state.mou.button |=  (1 << (BindToDo->Mou.Btn));
				break;


			case BIND_TO_KEYB:

				RBC9_Get_KeyB(pDevExt,BindToDo);

				break;


			case BIND_TO_PROFIL:

				SwitchProfil = BindToDo->Profil_Id;
				break;

			case BIND_TO_WWW:

				RBC9_Get_WWW(pDevExt,BindToDo);

				break;

			}

		}
		BindToDo = BindToDo->NextBind;
	}

	pDevExt->input_state.joy.Pov = JOY_POVVal[POVBits];

	if (SwitchProfil != pDevExt->Profil_Actif->Profil_Id)
	{
		pDevExt->Profil_Actif = RBC9_Select_Profil(pDev_obj,SwitchProfil);
	}

	//	DBG_LEAVE((""));
}




BOOLEAN RBC9_Special_Action(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION			pDevExt=GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);
	ULONGLONG					cur_time;

	cur_time = KeQueryInterruptTime();

	if (cur_time > (pDevExt->Special_Action.Time_Action + (pDevExt->Special_Action.MinTime * 10 * 1000)))
	{

		if (!pDevExt->Special_Action.Running)
		{
	
			if ((pDevExt->input_state.SpaceNav.Trame[0].Axe[2] < -300) && (pDevExt->input_state.SpaceNav.Trame[1].Axe[2] < -300))
			{

				if (pDevExt->Special_Action.Start_Detect == 0)
				{
					pDevExt->Special_Action.Start_Detect = cur_time;
				}

				if (cur_time > (pDevExt->Special_Action.Start_Detect + (pDevExt->Special_Action.MinTime * 10 * 1000)))
				{
					pDevExt->Special_Action.Time_Action = cur_time;
					pDevExt->Special_Action.Start_Detect = 0;
					pDevExt->Special_Action.Running = TRUE;
					RBC9_SEQ_Special_Action(pDev_obj);

					RBC9_Clear_State(pDev_obj);
					RtlZeroMemory(&pDevExt->KeyB, sizeof(pDevExt->KeyB));

					return TRUE;
				}
			}	
			else
			{
				pDevExt->Special_Action.Start_Detect = 0;	
			}
		}
		else
		{

			if (pDevExt->input_state.SpaceNav.Trame[0].Axe[2] > 300)
			{
				pDevExt->Special_Action.Running = FALSE;
				RBC9_SEQ_Special_Action_Fin(pDev_obj);
				pDevExt->Special_Action.Time_Action = cur_time;
			}
			else
			{
				if (pDevExt->Led == NULL)
				{
					DBG_OUT(("Relance My Led"));
					RBC9_SEQ_Special_Action(pDev_obj);
				}	
				if (pDevExt->input_state.SpaceNav.Trame[2].Btn[0] == 0x02)
				{
					DBG_OUT(("RBC9_Select_Next_Profil"));
					RBC9_Select_Next_Profil(pDev_obj);
					pDevExt->Special_Action.Time_Action = cur_time;
				}
				if (pDevExt->input_state.SpaceNav.Trame[2].Btn[0] == 0x01)
				{
					DBG_OUT(("RBC9_Select_Default"));
					pDevExt->Profil_Actif = RBC9_Select_Profil(pDev_obj,pDevExt->Profil_Id);
					pDevExt->Special_Action.Time_Action = cur_time;
				}
			}
			return TRUE;
		}

		return FALSE;
	}

	return TRUE;
}

VOID RBC9_process_raw_input(IN PDEVICE_OBJECT pDev_obj)
{
	PDEVICE_EXTENSION			pDevExt;


	//	DBG_ENTER(("%p", pDev_obj));

	pDevExt = GET_MINIDRIVER_DEVICE_EXTENSION(pDev_obj);

	RBC9_Set_Navigator(pDev_obj);

	if ( !RBC9_Special_Action(pDev_obj) && !pDevExt->ModeConfig)
	{

		//DBG_OUT(("SpaceNav changed"));

			if(pDevExt->Profil_Actif != NULL)
			{
				RBC9_Do_Bind(pDev_obj);
			}
	

		RBC9_KeyB_Buffer(pDev_obj);

	};

	RBC9_Set_Info(pDev_obj);

	//	DBG_LEAVE(("void"));
}


