/*
**	Command & Conquer Generals Zero Hour(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

////////////////////////////////////////////////////////////////////////////////
//																																						//
//  (c) 2001-2003 Electronic Arts Inc.																				//
//																																						//
////////////////////////////////////////////////////////////////////////////////

// FILE: Keyboard.cpp /////////////////////////////////////////////////////////////////////////////
// Created:    Colin Day, June 2001
// Desc:       Basic keyboard
///////////////////////////////////////////////////////////////////////////////////////////////////

#include "PreRTS.h"	// This must go first in EVERY cpp file int the GameEngine

#include "Common/Language.h"
#include "Common/GameEngine.h"
#include "Common/MessageStream.h"
#include "GameClient/Keyboard.h"
#include "GameClient/KeyDefs.h"


// PUBLIC DATA ////////////////////////////////////////////////////////////////////////////////////
Keyboard *TheKeyboard = NULL;

///////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

//-------------------------------------------------------------------------------------------------
/** Given the state of the device, create messages from the input and
	* place them on the message stream */
//-------------------------------------------------------------------------------------------------
void Keyboard::createStreamMessages( void )
{
	
	// santiy
	if( TheMessageStream == NULL )
		return;

	KeyboardIO *key = getFirstKey();
	GameMessage *msg = NULL;
	while( key->key != KEY_NONE )
	{

		// add message to stream
		if( BitTest( key->state, KEY_STATE_DOWN ) )
		{

			msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_KEY_DOWN );
			DEBUG_ASSERTCRASH( msg, ("Unable to append key down message to stream\n") );

		}  // end if
		else if( BitTest( key->state, KEY_STATE_UP ) )
		{

			msg = TheMessageStream->appendMessage( GameMessage::MSG_RAW_KEY_UP );
			DEBUG_ASSERTCRASH( msg, ("Unable to append key up message to stream\n") );

		}  // end else if
		else
		{

			DEBUG_CRASH(( "Unknown key state when creating msg stream\n" ));
			
		}  // end else

		// fill out message arguments
		if( msg )
		{
			msg->appendIntegerArgument( key->key );
			msg->appendIntegerArgument( key->state );
		}

		// next key please
		key++;

	}  // end while

}  // end createStreamMessages

//-------------------------------------------------------------------------------------------------
/** update all our key state data */
//-------------------------------------------------------------------------------------------------
void Keyboard::updateKeys( void )
{
	Int index = 0;

	// get latest keys
	do
	{
		do
		{

			// get a single key
			getKey( &m_keys[ index ] );

			//
			// if we get back that our device was lost, we haven't been paying
			// attention to the keyboard, lets start over now, we only need to
			// do this reset once in this loop though just to be efficient
			//
			if( m_keys[ index ].key == KEY_LOST)
			{

				resetKeys();
				index = 0;

			}  // end if

		}
		while( m_keys[ index ].key == KEY_LOST );
	} 
	while( m_keys[ index++ ].key != KEY_NONE );

	// update keyboard status array
	index = 0;
	while( m_keys[ index ].key != KEY_NONE )
	{

		/** @todo -- if we don't have focus, we could destroy all the keys retrieved
		here so that we don't process anything */

		m_keyStatus[ m_keys[ index ].key ].state = m_keys[ index ].state;
		m_keyStatus[ m_keys[ index ].key ].status = m_keys[ index ].status;
		m_keyStatus[ m_keys[ index ].key ].sequence = m_inputFrame;

		// prevent ALT-TAB from causing a TAB event
		if( m_keys[ index ].key == KEY_TAB )
		{
			if( BitTest( m_keyStatus[ KEY_LALT ].state, KEY_STATE_DOWN ) ||
					BitTest( m_keyStatus[ KEY_RALT ].state, KEY_STATE_DOWN ) )
			{
				m_keys[index].status = KeyboardIO::STATUS_USED;
			}
		}
		else if( m_keys[ index ].key == KEY_CAPS	 ||
						 m_keys[ index ].key == KEY_LCTRL  ||
						 m_keys[ index ].key == KEY_RCTRL	 ||
						 m_keys[ index ].key == KEY_LSHIFT ||
						 m_keys[ index ].key == KEY_RSHIFT ||
						 m_keys[ index ].key == KEY_LALT	 ||
						 m_keys[ index ].key == KEY_RALT )

		{

			//
			// this keeps our internal key state accurate event though we don't
			// use the returned translation ... kinda weird I think
			//
			translateKey( m_keys[ index ].key );

		}  // end else if

		index++;

	}  // end while

	// check for key repeats
	checkKeyRepeat();

	if( m_modifiers )
	{
		index = 0;
		while( m_keys[ index ].key != KEY_NONE )
		{

			// set in the modifier data into the already existing up/down state
			BitSet( m_keys[ index ].state, m_modifiers );

			// next key
			index++;

		}  // end while

	}  // end if

}  // end updateKeys

//-------------------------------------------------------------------------------------------------
/** check key repeat sequences, TRUE is returned if repeat is occurring */
//-------------------------------------------------------------------------------------------------
Bool Keyboard::checkKeyRepeat( void )
{
	Bool retVal = FALSE;
	Int index = 0;
	Int key;

	/** @todo we shouldn't think about repeating any keys while we 
	don't have the focus */
//	if( currentFocus == FOCUS_OUT )
//		return FALSE;

	// Find end of real keys for this frame
	while( m_keys[ index ].key != KEY_NONE )
		index++;

	// Scan Keyboard status array for first key down
	// long enough to repeat
	for( key = 0; key < 256; key++ )
	{

		if( BitTest( m_keyStatus[ key ].state, KEY_STATE_DOWN ) )
		{

			if( (m_inputFrame - m_keyStatus[ key ].sequence) > Keyboard::KEY_REPEAT_DELAY )
			{
				// Add key to this frame
				m_keys[ index ].key = (UnsignedByte)key;
				m_keys[ index ].state = KEY_STATE_DOWN | KEY_STATE_AUTOREPEAT;  // note: not a bitset; this is an assignment
				m_keys[ index ].status = KeyboardIO::STATUS_UNUSED;

				// Set End Flag
				m_keys[ ++index ].key = KEY_NONE;
			
				// Set all keys as new to prevent multiple keys repeating
				for( index = 0; index< NUM_KEYS; index++ )
					m_keyStatus[ index ].sequence = m_inputFrame;

				// Set repeated key so it will repeat again in two frames
				m_keyStatus[ key ].sequence = m_inputFrame - (Keyboard::KEY_REPEAT_DELAY + 2);

				retVal = TRUE;
				break;  // exit for key

			}  // end if

		}  // end if, key down

	}  // end for key

	return retVal;

}  // end checkKeyRepeat

//-------------------------------------------------------------------------------------------------
/** Initialize the keyboard key-names array */
//-------------------------------------------------------------------------------------------------
void Keyboard::initKeyNames( void )
{
	Int i;

	#define _set_keyname_(k,s,s2,z) (m_keyNames[z].stdKey = k, m_keyNames[z].shifted = s, m_keyNames[z].shifted2 = s2)

	/*
	 * Initialize the keyboard key-names array.
	 */
	for( i = 0; i < KEY_NAMES_COUNT; i++ )
	{

		m_keyNames[ i ].stdKey =		L'\0';
		m_keyNames[ i ].shifted =		L'\0';
		m_keyNames[ i ].shifted2 =	L'\0';

	}  // end for i

	m_shift2Key = KEY_NONE;

	// generic to all languages
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_UP );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_DOWN );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_LEFT );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_RIGHT );

	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_HOME );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_END );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_PGUP );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_PGDN );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_INS );
	_set_keyname_(L'\b',	L'\b',	L'\0',	KEY_DEL );

	_set_keyname_(L'\b',	L'\b',	L'\0',	KEY_BACKSPACE  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_ESC  );
	_set_keyname_(L'\t',	L'\t',	L'\0',	KEY_TAB  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_CAPS  );
	_set_keyname_(L'\n',	L'\n',	L'\0',	KEY_ENTER  );

	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_RALT );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_RCTRL );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_RSHIFT  );

	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_LALT  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_LCTRL  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_LSHIFT  );

	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_NUM );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_SCROLL );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_SYSREQ );

	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F1  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F2  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F3  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F4  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F5  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F6  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F7  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F8  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F9  );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F10 );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F11 );
	_set_keyname_(L'\0',	L'\0',	L'\0',	KEY_F12 );

	_set_keyname_(L'1',		L'1',		L'\0',	KEY_KP1 );
	_set_keyname_(L'2',		L'2',		L'\0',	KEY_KP2 );
	_set_keyname_(L'3',		L'3',		L'\0',	KEY_KP3 );
	_set_keyname_(L'4',		L'4',		L'\0',	KEY_KP4 );
	_set_keyname_(L'5',		L'5',		L'\0',	KEY_KP5 );
	_set_keyname_(L'6',		L'6',		L'\0',	KEY_KP6 );
	_set_keyname_(L'7',		L'7',		L'\0',	KEY_KP7 );
	_set_keyname_(L'8',		L'8',		L'\0',	KEY_KP8 );
	_set_keyname_(L'9',		L'9',		L'\0',	KEY_KP9 );
	_set_keyname_(L'0',		L'0',		L'\0',	KEY_KP0 );

	_set_keyname_(L' ',		L' ',		L'\0',	KEY_SPACE  );

	HKL kLayout = GetKeyboardLayout(0);

	Int low = (UnsignedInt)kLayout & 0xFFFF;
	LanguageID currentLanguage = OurLanguage;
	if(low == 0x040c
		 || low == 0x080c
		 || low == 0x0c0c
		 || low == 0x100c
		 || low == 0x140c)
		currentLanguage = LANGUAGE_ID_FRENCH;

	switch( currentLanguage )
	{
		case LANGUAGE_ID_US:
		case LANGUAGE_ID_JAPANESE:
		case LANGUAGE_ID_KOREAN:
		case LANGUAGE_ID_JABBER:
		case LANGUAGE_ID_UNKNOWN:
		case LANGUAGE_ID_SPANISH:		// not localized
			_set_keyname_(L'-',				L'-',				L'\0',	KEY_KPMINUS );
			_set_keyname_(L'+',				L'+',				L'\0',	KEY_KPPLUS );
			_set_keyname_(L'\n',			L'\n',			L'\0',	KEY_KPENTER );
			_set_keyname_(L'/',				L'/',				L'\0',	KEY_KPSLASH );
			_set_keyname_(L'.',				L'.',				L'\0',	KEY_KPDEL );
			_set_keyname_(L'*',				L'*',				L'\0',	KEY_KPSTAR );

			_set_keyname_(L'a',				L'A',				L'\0',	KEY_A  );
			_set_keyname_(L'b',				L'B',				L'\0',	KEY_B  );
			_set_keyname_(L'c',				L'C',				L'\0',	KEY_C  );
			_set_keyname_(L'd',				L'D',				L'\0',	KEY_D  );
			_set_keyname_(L'e',				L'E',				L'\0',	KEY_E  );
			_set_keyname_(L'f',				L'F',				L'\0',	KEY_F  );
			_set_keyname_(L'g',				L'G',				L'\0',	KEY_G  );
			_set_keyname_(L'h',				L'H',				L'\0',	KEY_H  );
			_set_keyname_(L'i',				L'I',				L'\0',	KEY_I  );
			_set_keyname_(L'j',				L'J',				L'\0',	KEY_J  );
			_set_keyname_(L'k',				L'K',				L'\0',	KEY_K  );
			_set_keyname_(L'l',				L'L',				L'\0',	KEY_L  );
			_set_keyname_(L'm',				L'M',				L'\0',	KEY_M  );
			_set_keyname_(L'n',				L'N',				L'\0',	KEY_N  );
			_set_keyname_(L'o',				L'O',				L'\0',	KEY_O  );
			_set_keyname_(L'p',				L'P',				L'\0',	KEY_P  );
			_set_keyname_(L'q',				L'Q',				L'\0',	KEY_Q  );
			_set_keyname_(L'r',				L'R',				L'\0',	KEY_R  );
			_set_keyname_(L's',				L'S',				L'\0',	KEY_S  );
			_set_keyname_(L't',				L'T',				L'\0',	KEY_T  );
			_set_keyname_(L'u',				L'U',				L'\0',	KEY_U  );
			_set_keyname_(L'v',				L'V',				L'\0',	KEY_V  );
			_set_keyname_(L'w',				L'W',				L'\0',	KEY_W  );
			_set_keyname_(L'x',				L'X',				L'\0',	KEY_X  );
			_set_keyname_(L'y',				L'Y',				L'\0',	KEY_Y  );
			_set_keyname_(L'z',				L'Z',				L'\0',	KEY_Z  );

			_set_keyname_(L'1',				L'!',				L'\0',	KEY_1  );
			_set_keyname_(L'2',				L'@',				L'\0',	KEY_2  );
			_set_keyname_(L'3',				L'#',				L'\0',	KEY_3  );
			_set_keyname_(L'4',				L'$',				L'\0',	KEY_4  );
			_set_keyname_(L'5',				L'%',				L'\0',	KEY_5  );
			_set_keyname_(L'6',				L'^',				L'\0',	KEY_6  );
			_set_keyname_(L'7',				L'&',				L'\0',	KEY_7  );
			_set_keyname_(L'8',				L'*',				L'\0',	KEY_8  );
			_set_keyname_(L'9',				L'(',				L'\0',	KEY_9  );
			_set_keyname_(L'0',				L')',				L'\0',	KEY_0  );

			_set_keyname_(L',',				L'<',				L'\0',	KEY_COMMA  );
			_set_keyname_(L'.',				L'>',				L'\0',	KEY_PERIOD  );
			_set_keyname_(L'/',				L'?',				L'\0',	KEY_SLASH  );

			_set_keyname_(L'[',				L'{',				L'\0',	KEY_LBRACKET  );
			_set_keyname_(L']',				L'}',				L'\0',	KEY_RBRACKET  );

			_set_keyname_(L';',				L':',				L'\0',	KEY_SEMICOLON  );
			_set_keyname_(L'\'',			L'\"',			L'\0',	KEY_APOSTROPHE  );
			_set_keyname_(L'`',				L'~',				L'\0',	KEY_TICK  );
			_set_keyname_(L'\\',			L'|',				L'\0',	KEY_BACKSLASH  );

			_set_keyname_(L'-',				L'_',				L'\0',	KEY_MINUS  );
			_set_keyname_(L'=',				L'+',				L'\0',	KEY_EQUAL  );

			break;

		case LANGUAGE_ID_UK:
			_set_keyname_(L'-',				L'-',				L'\0',	KEY_KPMINUS );
			_set_keyname_(L'+',				L'+',				L'\0',	KEY_KPPLUS );
			_set_keyname_(L'\n',			L'\n',			L'\0',	KEY_KPENTER );
			_set_keyname_(L'/',				L'/',				L'\0',	KEY_KPSLASH );
			_set_keyname_(L'.',				L'.',				L'\0',	KEY_KPDEL );
			_set_keyname_(L'*',				L'*',				L'\0',	KEY_KPSTAR );

			_set_keyname_(L'a',				L'A',				L'\0',	KEY_A  );
			_set_keyname_(L'b',				L'B',				L'\0',	KEY_B  );
			_set_keyname_(L'c',				L'C',				L'\0',	KEY_C  );
			_set_keyname_(L'd',				L'D',				L'\0',	KEY_D  );
			_set_keyname_(L'e',				L'E',				L'\0',	KEY_E  );
			_set_keyname_(L'f',				L'F',				L'\0',	KEY_F  );
			_set_keyname_(L'g',				L'G',				L'\0',	KEY_G  );
			_set_keyname_(L'h',				L'H',				L'\0',	KEY_H  );
			_set_keyname_(L'i',				L'I',				L'\0',	KEY_I  );
			_set_keyname_(L'j',				L'J',				L'\0',	KEY_J  );
			_set_keyname_(L'k',				L'K',				L'\0',	KEY_K  );
			_set_keyname_(L'l',				L'L',				L'\0',	KEY_L  );
			_set_keyname_(L'm',				L'M',				L'\0',	KEY_M  );
			_set_keyname_(L'n',				L'N',				L'\0',	KEY_N  );
			_set_keyname_(L'o',				L'O',				L'\0',	KEY_O  );
			_set_keyname_(L'p',				L'P',				L'\0',	KEY_P  );
			_set_keyname_(L'q',				L'Q',				L'\0',	KEY_Q  );
			_set_keyname_(L'r',				L'R',				L'\0',	KEY_R  );
			_set_keyname_(L's',				L'S',				L'\0',	KEY_S  );
			_set_keyname_(L't',				L'T',				L'\0',	KEY_T  );
			_set_keyname_(L'u',				L'U',				L'\0',	KEY_U  );
			_set_keyname_(L'v',				L'V',				L'\0',	KEY_V  );
			_set_keyname_(L'w',				L'W',				L'\0',	KEY_W  );
			_set_keyname_(L'x',				L'X',				L'\0',	KEY_X  );
			_set_keyname_(L'y',				L'Y',				L'\0',	KEY_Y  );
			_set_keyname_(L'z',				L'Z',				L'\0',	KEY_Z  );

			_set_keyname_(L'1',				L'!',				L'\0',	KEY_1  );
			_set_keyname_(L'2',				L'\"',			L'\0',	KEY_2  );
			_set_keyname_(L'3',				0x00A3,			L'\0',	KEY_3  );	//£
			_set_keyname_(L'4',				L'$',				L'€',		KEY_4  );
			_set_keyname_(L'5',				L'%',				L'\0',	KEY_5  );
			_set_keyname_(L'6',				L'^',				L'\0',	KEY_6  );
			_set_keyname_(L'7',				L'&',				L'\0',	KEY_7  );
			_set_keyname_(L'8',				L'*',				L'\0',	KEY_8  );
			_set_keyname_(L'9',				L'(',				L'\0',	KEY_9  );
			_set_keyname_(L'0',				L')',				L'\0',	KEY_0  );

			_set_keyname_(L',',				L'<',				L'\0',	KEY_COMMA  );
			_set_keyname_(L'.',				L'>',				L'\0',	KEY_PERIOD  );
			_set_keyname_(L'/',				L'?',				L'\0',	KEY_SLASH  );

			_set_keyname_(L'[',				L'{',				L'\0',	KEY_LBRACKET  );
			_set_keyname_(L']',				L'}',				L'\0',	KEY_RBRACKET  );

			_set_keyname_(L';',				L':',				L'\0',	KEY_SEMICOLON  );
			_set_keyname_(L'\'',			L'@',				L'\0',	KEY_APOSTROPHE  );
			_set_keyname_(L'`',				0x00AC,			0x00A6,	KEY_TICK  );	//¬¦
			_set_keyname_(L'#',				L'~',				L'\0',	KEY_BACKSLASH  );

			_set_keyname_(L'-',				L'_',				L'\0',	KEY_MINUS  );
			_set_keyname_(L'=',				L'+',				L'\0',	KEY_EQUAL  );

			_set_keyname_(L'\\',			L'|',				L'\0',	KEY_102  );

			m_shift2Key = KEY_RALT;
			break;

		case LANGUAGE_ID_GERMAN:
			_set_keyname_(L'-',				L'-',				L'\0',	KEY_KPMINUS );
			_set_keyname_(L'+',				L'+',				L'\0',	KEY_KPPLUS );
			_set_keyname_(L'\n',			L'\n',			L'\0',	KEY_KPENTER );
			_set_keyname_(L'/',				L'/',				L'\0',	KEY_KPSLASH );
			_set_keyname_(L',',				L',',				L'\0',	KEY_KPDEL );
			_set_keyname_(L'*',				L'*',				L'\0',	KEY_KPSTAR );

			_set_keyname_(L'a',				L'A',				L'\0',	KEY_A  );
			_set_keyname_(L'b',				L'B',				L'\0',	KEY_B  );
			_set_keyname_(L'c',				L'C',				L'\0',	KEY_C  );
			_set_keyname_(L'd',				L'D',				L'\0',	KEY_D  );
			_set_keyname_(L'e',				L'E',				L'\0',	KEY_E  );
			_set_keyname_(L'f',				L'F',				L'\0',	KEY_F  );
			_set_keyname_(L'g',				L'G',				L'\0',	KEY_G  );
			_set_keyname_(L'h',				L'H',				L'\0',	KEY_H  );
			_set_keyname_(L'i',				L'I',				L'\0',	KEY_I  );
			_set_keyname_(L'j',				L'J',				L'\0',	KEY_J  );
			_set_keyname_(L'k',				L'K',				L'\0',	KEY_K  );
			_set_keyname_(L'l',				L'L',				L'\0',	KEY_L  );
			_set_keyname_(L'm',				L'M',				0x00B5,	KEY_M  );	//µ
			_set_keyname_(L'n',				L'N',				L'\0',	KEY_N  );
			_set_keyname_(L'o',				L'O',				L'\0',	KEY_O  );
			_set_keyname_(L'p',				L'P',				L'\0',	KEY_P  );
			_set_keyname_(L'q',				L'Q',				L'@',		KEY_Q  );
			_set_keyname_(L'r',				L'R',				L'\0',	KEY_R  );
			_set_keyname_(L's',				L'S',				L'\0',	KEY_S  );
			_set_keyname_(L't',				L'T',				L'\0',	KEY_T  );
			_set_keyname_(L'u',				L'U',				L'\0',	KEY_U  );
			_set_keyname_(L'v',				L'V',				L'\0',	KEY_V  );
			_set_keyname_(L'w',				L'W',				L'\0',	KEY_W  );
			_set_keyname_(L'x',				L'X',				L'\0',	KEY_X  );
			_set_keyname_(L'z',				L'Z',				L'\0',	KEY_Y  );
			_set_keyname_(L'y',				L'Y',				L'\0',	KEY_Z  );

			_set_keyname_(L'1',				L'!',				L'\0',	KEY_1  );
			_set_keyname_(L'2',				L'"',				0x00B2,	KEY_2  );	//²
			_set_keyname_(L'3',				0x00A7,			0x00B3,	KEY_3  );	//§³
			_set_keyname_(L'4',				L'$',				L'\0',	KEY_4  );
			_set_keyname_(L'5',				L'%',				L'\0',	KEY_5  );
			_set_keyname_(L'6',				L'&',				L'\0',	KEY_6  );
			_set_keyname_(L'7',				L'/',				L'{',		KEY_7  );
			_set_keyname_(L'8',				L'(',				L'[',		KEY_8  );
			_set_keyname_(L'9',				L')',				L']',		KEY_9  );
			_set_keyname_(L'0',				L'=',				L'}',		KEY_0  );

			_set_keyname_(L',',				L';',				L'\0',	KEY_COMMA  );
			_set_keyname_(L'.',				L':',				L'\0',	KEY_PERIOD  );
			_set_keyname_(L'-',				L'_',				L'\0',	KEY_SLASH  );

			_set_keyname_(0x00FC,			0x00DC,			L'\0',	KEY_LBRACKET  );		//üÜ
			_set_keyname_(L'+',				L'*',				L'~',		KEY_RBRACKET  );

			_set_keyname_(0x00F6,			0x00D6,			L'\0',	KEY_SEMICOLON  );		//öÖ
			_set_keyname_(0x00E4,			0x00C4,			L'\0',	KEY_APOSTROPHE  );	//äÄ
			_set_keyname_(L'^',				0x00B0,			L'\0',	KEY_TICK  );				//°
			_set_keyname_(L'#',				L'\'',			L'\0',	KEY_BACKSLASH  );

			_set_keyname_(0x00DF,			L'?',				L'\\',	KEY_MINUS  );				//ß
			_set_keyname_(0x00B4,			L'`',				L'\0',	KEY_EQUAL  );				//´

			_set_keyname_(L'<',				L'>',				L'|',		KEY_102  );

			m_shift2Key = KEY_RALT;
			break;

		case LANGUAGE_ID_FRENCH:
			_set_keyname_(L'-',				L'-',				L'\0',	KEY_KPMINUS );
			_set_keyname_(L'+',				L'+',				L'\0',	KEY_KPPLUS );
			_set_keyname_(L'\n',			L'\n',			L'\0',	KEY_KPENTER );
			_set_keyname_(L'/',				L'/',				L'\0',	KEY_KPSLASH );
			_set_keyname_(L'.',				L'.',				L'\0',	KEY_KPDEL );
			_set_keyname_(L'*',				L'*',				L'\0',	KEY_KPSTAR );

			_set_keyname_(L'q',				L'Q',				L'\0',	KEY_A  );
			_set_keyname_(L'b',				L'B',				L'\0',	KEY_B  );
			_set_keyname_(L'c',				L'C',				L'\0',	KEY_C  );
			_set_keyname_(L'd',				L'D',				L'\0',	KEY_D  );
			_set_keyname_(L'e',				L'E',				L'\0',	KEY_E  );
			_set_keyname_(L'f',				L'F',				L'\0',	KEY_F  );
			_set_keyname_(L'g',				L'G',				L'\0',	KEY_G  );
			_set_keyname_(L'h',				L'H',				L'\0',	KEY_H  );
			_set_keyname_(L'i',				L'I',				L'\0',	KEY_I  );
			_set_keyname_(L'j',				L'J',				L'\0',	KEY_J  );
			_set_keyname_(L'k',				L'K',				L'\0',	KEY_K  );
			_set_keyname_(L'l',				L'L',				L'\0',	KEY_L  );
			_set_keyname_(L',',				L'?',				L'\0',	KEY_M  );
			_set_keyname_(L'n',				L'N',				L'\0',	KEY_N  );
			_set_keyname_(L'o',				L'O',				L'\0',	KEY_O  );
			_set_keyname_(L'p',				L'P',				L'\0',	KEY_P  );
			_set_keyname_(L'a',				L'A',				L'\0',	KEY_Q  );
			_set_keyname_(L'r',				L'R',				L'\0',	KEY_R  );
			_set_keyname_(L's',				L'S',				L'\0',	KEY_S  );
			_set_keyname_(L't',				L'T',				L'\0',	KEY_T  );
			_set_keyname_(L'u',				L'U',				L'\0',	KEY_U  );
			_set_keyname_(L'v',				L'V',				L'\0',	KEY_V  );
			_set_keyname_(L'z',				L'Z',				L'\0',	KEY_W  );
			_set_keyname_(L'x',				L'X',				L'\0',	KEY_X  );
			_set_keyname_(L'y',				L'Y',				L'\0',	KEY_Y  );
			_set_keyname_(L'w',				L'W',				L'\0',	KEY_Z  );

			_set_keyname_(L'&',				L'1',				L'\0',	KEY_1  );
			_set_keyname_(0x00E9,			L'2',				L'~',		KEY_2  );	//é
			_set_keyname_(L'"',				L'3',				L'#',		KEY_3  );
			_set_keyname_(L'\'',			L'4',				L'{',		KEY_4  );
			_set_keyname_(L'(',				L'5',				L'[',		KEY_5  );
			_set_keyname_(L'-',				L'6',				L'|',		KEY_6  );
			_set_keyname_(0x00E8,			L'7',				L'`',		KEY_7  );	//è
			_set_keyname_(L'_',				L'8',				L'\\',	KEY_8  );
			_set_keyname_(0x00E7,			L'9',				L'\0',	KEY_9  );	//ç
			_set_keyname_(0x00E0,			L'0',				L'@',		KEY_0  );	//à

			_set_keyname_(L';',				L'.',				L'\0',	KEY_COMMA  );
			_set_keyname_(L':',				L'/',				L'\0',	KEY_PERIOD  );
			_set_keyname_(L'!',				0x00A7,			L'\0',	KEY_SLASH  );				//§

			_set_keyname_(L'^',				0x00A8,			L'\0',	KEY_LBRACKET  );		//¨
			_set_keyname_(L'$',				0x00A3,			0x00A4,	KEY_RBRACKET  );		//£¤

			_set_keyname_(L'm',				L'M',				L'\0',	KEY_SEMICOLON  );
			_set_keyname_(0x00F9,			L'%',				L'\0',	KEY_APOSTROPHE  );	//ù
			_set_keyname_(0x00B2,			L'\0',			L'\0',	KEY_TICK  );				//²
			_set_keyname_(L'*',				0x00B5,			L'\0',	KEY_BACKSLASH  );		//µ

			_set_keyname_(L')',				0x00B0,			L']',		KEY_MINUS  );				//°
			_set_keyname_(L'=',				L'+',				L'}',		KEY_EQUAL  );

			_set_keyname_(L'<',				L'>',				L'\0',	KEY_102  );

			m_shift2Key = KEY_RALT;
			break;

		case LANGUAGE_ID_ITALIAN:
			_set_keyname_(L'-',				L'-',				L'\0',	KEY_KPMINUS );
			_set_keyname_(L'+',				L'+',				L'\0',	KEY_KPPLUS );
			_set_keyname_(L'\n',			L'\n',			L'\0',	KEY_KPENTER );
			_set_keyname_(L'/',				L'/',				L'\0',	KEY_KPSLASH );
			_set_keyname_(L'.',				L'.',				L'\0',	KEY_KPDEL );
			_set_keyname_(L'*',				L'*',				L'\0',	KEY_KPSTAR );

			_set_keyname_(L'a',				L'A',				L'\0',	KEY_A  );
			_set_keyname_(L'b',				L'B',				L'\0',	KEY_B  );
			_set_keyname_(L'c',				L'C',				L'\0',	KEY_C  );
			_set_keyname_(L'd',				L'D',				L'\0',	KEY_D  );
			_set_keyname_(L'e',				L'E',				L'\0',	KEY_E  );
			_set_keyname_(L'f',				L'F',				L'\0',	KEY_F  );
			_set_keyname_(L'g',				L'G',				L'\0',	KEY_G  );
			_set_keyname_(L'h',				L'H',				L'\0',	KEY_H  );
			_set_keyname_(L'i',				L'I',				L'\0',	KEY_I  );
			_set_keyname_(L'j',				L'J',				L'\0',	KEY_J  );
			_set_keyname_(L'k',				L'K',				L'\0',	KEY_K  );
			_set_keyname_(L'l',				L'L',				L'\0',	KEY_L  );
			_set_keyname_(L'm',				L'M',				L'\0',	KEY_M  );
			_set_keyname_(L'n',				L'N',				L'\0',	KEY_N  );
			_set_keyname_(L'o',				L'O',				L'\0',	KEY_O  );
			_set_keyname_(L'p',				L'P',				L'\0',	KEY_P  );
			_set_keyname_(L'q',				L'Q',				L'\0',	KEY_Q  );
			_set_keyname_(L'r',				L'R',				L'\0',	KEY_R  );
			_set_keyname_(L's',				L'S',				L'\0',	KEY_S  );
			_set_keyname_(L't',				L'T',				L'\0',	KEY_T  );
			_set_keyname_(L'u',				L'U',				L'\0',	KEY_U  );
			_set_keyname_(L'v',				L'V',				L'\0',	KEY_V  );
			_set_keyname_(L'w',				L'W',				L'\0',	KEY_W  );
			_set_keyname_(L'x',				L'X',				L'\0',	KEY_X  );
			_set_keyname_(L'y',				L'Y',				L'\0',	KEY_Y  );
			_set_keyname_(L'z',				L'Z',				L'\0',	KEY_Z  );

			_set_keyname_(L'1',				L'!',				L'\0',	KEY_1  );
			_set_keyname_(L'2',				L'"',				L'\0',	KEY_2  );
			_set_keyname_(L'3',				0x00A3,			L'\0',	KEY_3  );		//£
			_set_keyname_(L'4',				L'$',				L'\0',	KEY_4  );
			_set_keyname_(L'5',				L'%',				L'\0',	KEY_5  );
			_set_keyname_(L'6',				L'&',				L'\0',	KEY_6  );
			_set_keyname_(L'7',				L'/',				L'\0',	KEY_7  );
			_set_keyname_(L'8',				L'(',				L'\0',	KEY_8  );
			_set_keyname_(L'9',				L')',				L'\0',	KEY_9  );
			_set_keyname_(L'0',				L'=',				L'\0',	KEY_0  );

			_set_keyname_(L',',				L';',				L'\0',	KEY_COMMA  );
			_set_keyname_(L'.',				L':',				L'\0',	KEY_PERIOD  );
			_set_keyname_(L'-',				L'_',				L'\0',	KEY_SLASH  );

			_set_keyname_(0x00E8,			0x00E9,			L'[',		KEY_LBRACKET  );		//èé
			_set_keyname_(L'+',				L'*',				L']',		KEY_RBRACKET  );

			_set_keyname_(0x00F2,			0x00E7,			L'@',		KEY_SEMICOLON  );		//òç
			_set_keyname_(0x00E0,			0x00B0,			L'#',		KEY_APOSTROPHE  );	//à°
			_set_keyname_(L'\\',			L'|',				L'\0',	KEY_TICK  );
			_set_keyname_(0x00F9,			0x00A7,			L'\0',	KEY_BACKSLASH  );		//ù§

			_set_keyname_(L'\'',			L'?',				L'\0',	KEY_MINUS  );
			_set_keyname_(0x00EC,			L'^',				L'\0',	KEY_EQUAL  );				//ì

			_set_keyname_(L'<',				L'>',				L'\0',	KEY_102  );

			m_shift2Key = KEY_RALT;
			break;

	}  // end switch( Language )

}  // end initKeyNames

///////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC PROTOTYPES //////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Keyboard::Keyboard( void )
{

	memset( m_keys, 0, sizeof( m_keys ) );
	memset( m_keyStatus, 0, sizeof( m_keyStatus ) );
	m_modifiers = KEY_STATE_NONE;
	m_shift2Key = KEY_NONE;

	memset( m_keyNames, 0, sizeof( m_keyNames ) );
	m_inputFrame = 0;

}  // end Keyboard

//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Keyboard::~Keyboard( void )
{

}  // end ~Keyboard

//-------------------------------------------------------------------------------------------------
/** Initialzie the keyboard */
//-------------------------------------------------------------------------------------------------
void Keyboard::init( void )
{

	// initialize the key names
	initKeyNames();

	// first input frame
	m_inputFrame = 0;

}  // end init

//-------------------------------------------------------------------------------------------------
/** Reset keyboard system */
//-------------------------------------------------------------------------------------------------
void Keyboard::reset( void )
{

}  // end reset

//-------------------------------------------------------------------------------------------------
/** Called once per frame to gather key data input */
//-------------------------------------------------------------------------------------------------
void Keyboard::update( void )
{

	// increment input frame
	m_inputFrame++;

	// update the key data
	updateKeys();

}  // end update

//-------------------------------------------------------------------------------------------------
/** Reset the state data for the keys, we likely want to do this when
	* we once again gain focus to our app from something like an alt tab */
//-------------------------------------------------------------------------------------------------
void Keyboard::resetKeys( void )
{

	memset( m_keys, 0, sizeof( m_keys ) );
	memset( m_keyStatus, 0, sizeof( m_keyStatus ) );
	m_modifiers = KEY_STATE_NONE; 
	if( getCapsState() )
	{
		m_modifiers |= KEY_STATE_CAPSLOCK;
	}

}  // end resetKeys

//-------------------------------------------------------------------------------------------------
/** get the first key in our current state of the keyboard */
//-------------------------------------------------------------------------------------------------
KeyboardIO *Keyboard::getFirstKey( void )
{
	return &m_keys[ 0 ];	
}  // end getFirstKey

//-------------------------------------------------------------------------------------------------
/** return the key status for the specified key */
//-------------------------------------------------------------------------------------------------
UnsignedByte Keyboard::getKeyStatusData( UnsignedByte key )
{
	return m_keyStatus[ key ].status;
}  // end getKeyStatusData

//-------------------------------------------------------------------------------------------------
/** Get the key state data as a Bool for the specified key */
//-------------------------------------------------------------------------------------------------
Bool Keyboard::getKeyStateBit( UnsignedByte key, Int bit )
{
	return (m_keyStatus[ key ].state & bit) ? 1 : 0;
}  // end getKeyStateBit

//-------------------------------------------------------------------------------------------------
/** return the sequence data for the given key */
//-------------------------------------------------------------------------------------------------
UnsignedInt Keyboard::getKeySequenceData( UnsignedByte key )
{
	return m_keyStatus[ key ].sequence;
}  // end getKeySequenceData

//-------------------------------------------------------------------------------------------------
/** set the key status data */
//-------------------------------------------------------------------------------------------------
void Keyboard::setKeyStatusData( UnsignedByte key, KeyboardIO::StatusType data )
{
	m_keyStatus[ key ].status = data;
}  // end setKeyStatusData

//-------------------------------------------------------------------------------------------------
/** set the key state data */
//-------------------------------------------------------------------------------------------------
void Keyboard::setKeyStateData( UnsignedByte key, UnsignedByte data )
{
	m_keyStatus[ key ].state = data;
}  // end setKeyStateData

//-------------------------------------------------------------------------------------------------
/** This routine must be called with every character to
	* properly monitor the shift state.  Takes a keycode as
	* input, and returns the UNICODE char representing the
	* character. */
//-------------------------------------------------------------------------------------------------
WideChar Keyboard::translateKey( WideChar keyCode )
{

	if( keyCode > 0x00FF )
		return keyCode;

	UnsignedByte ubKeyCode = (UnsignedByte)keyCode;
	switch( ubKeyCode )
	{

		case KEY_CAPS:
			if( getKeyStatusData( KEY_CAPS ) == KeyboardIO::STATUS_UNUSED )
			{
				if( getKeyStateBit( KEY_CAPS, KEY_STATE_DOWN ) )
				{
					if( m_modifiers & KEY_STATE_CAPSLOCK )
					{
						// Toggle caplocks off
						m_modifiers &= ~KEY_STATE_CAPSLOCK;
					}
					else
					{
						// Toggle caplocks on
						m_modifiers |= KEY_STATE_CAPSLOCK;
					}
				}

				setKeyStatusData( KEY_CAPS, KeyboardIO::STATUS_USED );
			}
			return 0;

		case KEY_LSHIFT:
			if( getKeyStateBit( KEY_LSHIFT, KEY_STATE_DOWN ) )
			{
				m_modifiers |= KEY_STATE_LSHIFT;
			}
			else
			{
				m_modifiers &= ~KEY_STATE_LSHIFT;
			}
			return 0;

		case KEY_RSHIFT:
			if( getKeyStateBit( KEY_RSHIFT, KEY_STATE_DOWN ) )
			{
				m_modifiers |= KEY_STATE_RSHIFT;
			}
			else
			{
				m_modifiers &= ~KEY_STATE_RSHIFT;
			}
			return 0;

		case KEY_LCTRL:
			if( getKeyStateBit( KEY_LCTRL, KEY_STATE_DOWN ) )
			{
				m_modifiers |= KEY_STATE_LCONTROL;
			}
			else
			{
				m_modifiers &= ~KEY_STATE_LCONTROL;
			}
			return 0;

		case KEY_RCTRL:
			if( getKeyStateBit( KEY_RCTRL, KEY_STATE_DOWN ) )
			{
				m_modifiers |= KEY_STATE_RCONTROL;
			}
			else
			{
				m_modifiers &= ~KEY_STATE_RCONTROL;
			}
			return 0;

		case KEY_LALT:
			if( getKeyStateBit( KEY_LALT, KEY_STATE_DOWN ) )
			{
				m_modifiers |= KEY_STATE_LALT;
			}
			else
			{
				m_modifiers &= ~KEY_STATE_LALT;
			}
			return 0;

		case KEY_RALT:
			if( getKeyStateBit( KEY_RALT, KEY_STATE_DOWN ) )
			{
				m_modifiers |= KEY_STATE_RALT;
			}
			else
			{
				m_modifiers &= ~KEY_STATE_RALT;
			}
			return 0;

		default:
			if( ubKeyCode == m_shift2Key )
			{
				if( getKeyStateBit( m_shift2Key, KEY_STATE_DOWN ) )
				{
					m_modifiers |= KEY_STATE_SHIFT2;
				}
				else
				{
					m_modifiers &= ~KEY_STATE_SHIFT2;
				}
				return 0;
			}

			if( m_modifiers & KEY_STATE_SHIFT2 )
			{
				return( m_keyNames[ ubKeyCode ].shifted2 );
			}
			
			if( isShift() || getCapsState() && GameIsAlpha( m_keyNames[ ubKeyCode ].stdKey ) )
			{
				return( m_keyNames[ ubKeyCode ].shifted );
			}
			
			return( m_keyNames[ubKeyCode ].stdKey );
	}  // end switch( ubKeyCode )
}  // end translateKey

//-------------------------------------------------------------------------------------------------
/** returns true if any shift state is pressed */
//-------------------------------------------------------------------------------------------------
Bool Keyboard::isShift()
{
		if( m_modifiers & KEY_STATE_LSHIFT || m_modifiers & KEY_STATE_RSHIFT || m_modifiers & KEY_STATE_SHIFT2 )
		{
			return TRUE;
		}
		return FALSE;
}  // end isShift()

//-------------------------------------------------------------------------------------------------
/** returns true if any control state is pressed */
//-------------------------------------------------------------------------------------------------
Bool Keyboard::isCtrl()
{
		if( m_modifiers & KEY_STATE_LCONTROL || m_modifiers & KEY_STATE_RCONTROL )
		{
			return TRUE;
		}
		return FALSE;
}  // end isCtrl()

//-------------------------------------------------------------------------------------------------
/** returns true if any shift state is pressed */
//-------------------------------------------------------------------------------------------------
Bool Keyboard::isAlt()
{
	if( m_modifiers & KEY_STATE_LALT || m_modifiers & KEY_STATE_RALT )
	{
		return TRUE;
	}
	return FALSE;
}  // end isAlt()


WideChar Keyboard::getPrintableKey( UnsignedByte key,  Int state )
{
	if((key < 0 || key >=KEY_NAMES_COUNT) || ( state < 0 || state >= MAX_KEY_STATES))
		return L'';
	if(state == 0)
		return m_keyNames[key].stdKey;
	else if(state == 1)
		return m_keyNames[key].shifted;
	else 
		return m_keyNames[key].shifted2;


}