

//---Includes---
#include <xtl.h>
#include <stdlib.h>

//---defines---
#define		KEYBOARD_INT	0x09  // Keyboard interupt
#define         KEY_BUFFER	0x60  // location of keyboard buffer
#define		KEY_CONTROL     0x61  // location of key controller
#define         INT_CONTROL	0x20  // location of interupt controller

#define         key_ESC			key_arr[1]
#define         key_1			key_arr[2]
#define         key_2			key_arr[3]
#define         key_3			key_arr[4]
#define         key_4			key_arr[5]
#define         key_5			key_arr[6]
#define         key_6			key_arr[7]
#define         key_7			key_arr[8]
#define         key_8			key_arr[9]
#define         key_9			key_arr[10]
#define         key_0			key_arr[11]
#define         key_MINUS		key_arr[12]
#define         key_EQUAL		key_arr[13]
#define         key_BACK_SPACE		key_arr[14]
#define         key_TAB			key_arr[15]
#define         key_Q			key_arr[16]
#define         key_W			key_arr[17]
#define         key_E			key_arr[18]
#define         key_R			key_arr[19]
#define         key_T			key_arr[20]
#define         key_Y			key_arr[21]
#define         key_U			key_arr[22]
#define         key_I			key_arr[23]
#define         key_O			key_arr[24]
#define         key_P			key_arr[25]
#define         key_left_bracket	key_arr[26]
#define        	key_right_bracket	key_arr[27]
#define         key_ENTER		key_arr[28]
#define         key_Ctrl		key_arr[29]
#define         key_A			key_arr[30]
#define         key_S			key_arr[31]
#define         key_D			key_arr[32]
#define         key_F			key_arr[33]
#define         key_G			key_arr[34]
#define         key_H			key_arr[35]
#define         key_J			key_arr[36]
#define         key_K			key_arr[37]
#define         key_L			key_arr[38]
#define         key_SEMICOLON		key_arr[39]
#define         key_APOSTROPHE		key_arr[40]
#define         key_TILDE		key_arr[41]
#define         key_L_SHIFT		key_arr[42]
#define         key_BACK_SLASH		key_arr[43]
#define         key_Z			key_arr[44]
#define         key_X			key_arr[45]
#define         key_C			key_arr[46]
#define         key_V			key_arr[47]
#define         key_B			key_arr[48]
#define         key_N			key_arr[49]
#define         key_M			key_arr[50]
#define         key_COMMA		key_arr[51]
#define         key_PERIOD		key_arr[52]
#define         key_FORWARD_SLASH	key_arr[53]
#define         key_R_SHIFT		key_arr[54]
#define         key_PRINT_SCREEN	key_arr[55]
#define         key_Alt			key_arr[56]
#define         key_SPACEBAR		key_arr[57]
#define         key_CAPS_LOCK		key_arr[58]
#define         key_F1			key_arr[59]
#define         key_F2			key_arr[60]
#define         key_F3			key_arr[61]
#define         key_F4			key_arr[62]
#define         key_F5			key_arr[63]
#define         key_F6			key_arr[64]
#define         key_F7			key_arr[65]
#define         key_F8			key_arr[66]
#define         key_F9			key_arr[67]
#define         key_F10			key_arr[68]
#define         key_F11			key_arr[87]
#define         key_F12			key_arr[88]
#define         key_NUM_LOCK		key_arr[69]
#define         key_SCROLL_LOCK		key_arr[70]
#define         key_HOME		key_arr[71]
#define         key_up			key_arr[72]
#define         key_PAGE_UP		key_arr[73]
#define         key_NUM_MINUS		key_arr[74]
#define        	key_left    		key_arr[75]
#define         key_CENTER		key_arr[76]
#define         key_right		key_arr[77]
#define         key_NUM_PLUS		key_arr[78]
#define         key_END			key_arr[79]
#define         key_down		key_arr[80]
#define         key_PAGE_DOWN		key_arr[81]
#define         key_INSERT		key_arr[82]
#define         key_DELETE		key_arr[83]

#ifdef __cplusplus

#define __CPPARGS void*
#else

#define __CPPARGS void* 
#endif

//---Global---
volatile int  	key_arr[101]= {   0,
			  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
			  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
			  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
			  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
			  0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0 };
XINPUT_GAMEPAD gamepad;
HANDLE thread = NULL;
UINT thread_id = 0;
HANDLE mutex = NULL;

// this pointer will hold the old keyboard interrupt handler
//void  interrupt far ( *Old_keyboard_ISR)(__CPPARGS);

int	Raw_key=0;
int xinput_initialized = 0;

//---Prototypes---
unsigned  interrupt far New_keyboard_ISR (__CPPARGS);
void  install_keyboard ();
void  uninstall_keyboard ();

//----------------------------------------------------------------------------
//---Functions---
//----------------------------------------------------------------------------
unsigned interrupt far New_keyboard_ISR (__CPPARGS)
	{
		if( !xinput_initialized )
		{
			XInitDevices( 0, 0 );
			xinput_initialized = 1;

			memset( &mouse, 0, sizeof( mouse_inp ) );
			mouse.x = mouse.lx = SCREEN_WIDTH / 2;
			mouse.y = mouse.ly = SCREEN_HEIGHT / 2;
			mouse.sy = mouse.sx = 50;
		}

		if( !mutex )
		{
			CreateMutex( NULL, TRUE, "Input Mutex" );
		}

	 // read the key from keyboard and then renable it to read next input.
	 // its a total control ISR.
#if 0
	 asm 	{
		 STI					; // re-enable interrupts
		 IN		AL,	KEY_BUFFER	; // get the key pressed
		 XOR		AH,	AH              ; // clear	AH
		 MOV            Raw_key,AX              ; // storing the key
		 IN		AL,	KEY_CONTROL     ; // set control register
		 OR		AL,	82h             ; // set the proper bits to
							; // reset the keyboard flip flop
		 OUT		KEY_CONTROL,AL          ; // send new data back to the
							; // control register
		 AND		AL,	7fh             ;
		 OUT		KEY_CONTROL,AL          ; // completing the reset
		 MOV            AL,	20h             ;
		 OUT		INT_CONTROL,AL          ; // re-enable interrupts (not complsery in C)
		} // end of asembly code.

	 // Processing and updating the key_arr
	 if ( Raw_key < 100 ) // make code
		key_arr [Raw_key] = 1;
	 else if ( Raw_key > 127 ) // break code
		key_arr[Raw_key-128] = 0;
#endif

	 while(true)
	 {
		static HANDLE hgamepad;
		DWORD insertions, removals;
		
		XGetDeviceChanges( XDEVICE_TYPE_GAMEPAD, &insertions, &removals );

		if( insertions & 1 )
		{ 
			hgamepad = XInputOpen( XDEVICE_TYPE_GAMEPAD, 0, XDEVICE_NO_SLOT, NULL );
		}

		if( hgamepad )
		{
			XINPUT_STATE InputState;

			// Attempt ownership of the mutex
		//	DWORD res = WaitForSingleObject( mutex, INFINITE );

			// Get the controller input
			XInputGetState( hgamepad, &InputState );
			memcpy( &gamepad, &InputState.Gamepad, sizeof( XINPUT_GAMEPAD ) );
	
			// Release control of this mutex
		//	ReleaseMutex( mutex );
		}

		// simulate keyboard input
		key_ESC = ( gamepad.wButtons & XINPUT_GAMEPAD_BACK );
		key_Alt = ( gamepad.bAnalogButtons[XINPUT_GAMEPAD_X] );
		key_Ctrl = ( gamepad.bAnalogButtons[XINPUT_GAMEPAD_A] );
		key_up = ( gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP );
		key_down = ( gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN );
		key_left = ( gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT );
		key_right = ( gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT );
		key_SPACEBAR = ( gamepad.wButtons & XINPUT_GAMEPAD_START );

		// TODO: use mutex to synchronize simulated mouse input
		mouse.lx = mouse.x;
		mouse.ly = mouse.y;

		if( gamepad.sThumbLX < -8000 )
			mouse.x -= (mouse.sx/10)*2;
		if( gamepad.sThumbLX > 8000 )
			mouse.x += (mouse.sx/10)*2;
		if( gamepad.sThumbLY < -8000 )
			mouse.y += (mouse.sy/10);
		if( gamepad.sThumbLY > 8000 )
			mouse.y -= (mouse.sy/10);

		if( mouse.x < 0 ) mouse.x = 0;
		if( mouse.x > SCREEN_WIDTH ) mouse.x = SCREEN_WIDTH;
		if( mouse.y < 0 ) mouse.y = 0;
		if( mouse.y > SCREEN_HEIGHT ) mouse.y = SCREEN_HEIGHT;

		//mouse.button = ( gamepad.bAnalogButtons[XINPUT_GAMEPAD_B] );
		if( gamepad.bAnalogButtons[XINPUT_GAMEPAD_B] )
			mouse.button = 1;
		else
			mouse.button = 0;

		// Stall the thread for some time
		D3DDevice_BlockUntilVerticalBlank();
	//	Sleep(16);
	 }

	 _endthread();

	 return 0;
	}
//----------------------------------------------------------------------------
void install_keyboard ()
	{
	 // it will simply install the New keyboard ISR

	  /*Old_keyboard_ISR = (void(far*)(__CPPARGS))_dos_getvect ( KEYBOARD_INT );
	 _dos_setvect ( KEYBOARD_INT, (void(interrupt*)(__CPPARGS))New_keyboard_ISR );*/

		BOOL ret;

		thread = (HANDLE) _beginthreadex( NULL, 0, New_keyboard_ISR, NULL, 0, NULL );

		/* it's important to boost the priority of this thread and keep it at that level */
		ret = SetThreadPriority( thread, THREAD_PRIORITY_HIGHEST );
		ret = SetThreadPriorityBoost( thread, TRUE );
	}
//----------------------------------------------------------------------------
void uninstall_keyboard ()
	{
	 // it will restore the dos keyboard interruput which was hooked in
	 // install keyboard function.

	 //_dos_setvect ( KEYBOARD_INT, Old_keyboard_ISR );
		CloseHandle( thread );
	}
