//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//===========================================================================//


#if defined( WIN32 ) 
#if !defined( _X360 )
#include <wtypes.h>
#include <winuser.h>
#include "xbox/xboxstubs.h"
#else
#include "xbox/xbox_win32stubs.h"
#endif
#endif // WIN32

#include "key_translation.h"
#include "tier1/convar.h"
#include "tier1/strtools.h"
#include "tier0/dbg.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

#if defined(__clang__)
	#pragma GCC diagnostic ignored "-Wchar-subscripts"
#endif

static ButtonCode_t s_pVirtualKeyToButtonCode[256];

static ButtonCode_t s_pSKeytoButtonCode[SK_MAX_KEYS];

#if !defined( POSIX )
static ButtonCode_t s_pXKeyTrans[XK_MAX_KEYS];
#endif

#define SCONTROLLERBUTTONS_BUTTONS( x ) \
	"SC_A",\
	"SC_B",\
	"SC_X",\
	"SC_Y",\
	"SC_DPAD_UP",\
	"SC_DPAD_RIGHT",\
	"SC_DPAD_DOWN",\
	"SC_DPAD_LEFT",\
	"SC_LEFT_BUMPER",\
	"SC_RIGHT_BUMPER",\
	"SC_LEFT_TRIGGER",\
	"SC_RIGHT_TRIGGER",\
	"SC_LEFT_GRIP",\
	"SC_RIGHT_GRIP",\
	"SC_LEFT_PAD_TOUCH",\
	"SC_RIGHT_PAD_TOUCH",\
	"SC_LEFT_PAD_CLICK",\
	"SC_RIGHT_PAD_CLICK",\
	"SC_LPAD_UP",\
	"SC_LPAD_RIGHT",\
	"SC_LPAD_DOWN",\
	"SC_LPAD_LEFT",\
	"SC_RPAD_UP",\
	"SC_RPAD_RIGHT",\
	"SC_RPAD_DOWN",\
	"SC_RPAD_LEFT",\
	"SC_SELECT",\
	"SC_START",\
	"SC_STEAM",\
	"SC_NULL"

#define SCONTROLLERBUTTONS_AXIS( x ) \
	"SC_LPAD_AXIS_RIGHT",\
	"SC_LPAD_AXIS_LEFT",\
	"SC_LPAD_AXIS_DOWN",\
	"SC_LPAD_AXIS_UP",\
	"SC_AXIS_L_TRIGGER",\
	"SC_AXIS_R_TRIGGER",\
	"SC_RPAD_AXIS_RIGHT",\
	"SC_RPAD_AXIS_LEFT",\
	"SC_RPAD_AXIS_DOWN",\
	"SC_RPAD_AXIS_UP",\
	"SC_GYRO_AXIS_PITCH_POSITIVE",\
	"SC_GYRO_AXIS_PITCH_NEGATIVE",\
	"SC_GYRO_AXIS_ROLL_POSITIVE",\
	"SC_GYRO_AXIS_ROLL_NEGATIVE",\
	"SC_GYRO_AXIS_YAW_POSITIVE",\
	"SC_GYRO_AXIS_YAW_NEGATIVE"

#define SCONTROLLERBUTTONS_VBUTTONS( x ) \
	"SC_F1",\
	"SC_F2",\
	"SC_F3",\
	"SC_F4",\
	"SC_F5",\
	"SC_F6",\
	"SC_F7",\
	"SC_F8",\
	"SC_F9",\
	"SC_F10",\
	"SC_F11",\
	"SC_F12"

static int s_pButtonCodeToVirtual[BUTTON_CODE_LAST];

static const char *s_pButtonCodeName[ ] =
{
	"",				// KEY_NONE
	"0",			// KEY_0,
	"1",			// KEY_1,
	"2",			// KEY_2,
	"3",			// KEY_3,
	"4",			// KEY_4,
	"5",			// KEY_5,
	"6",			// KEY_6,
	"7",			// KEY_7,
	"8",			// KEY_8,
	"9",			// KEY_9,
	"a",			// KEY_A,
	"b",			// KEY_B,
	"c",			// KEY_C,
	"d",			// KEY_D,
	"e",			// KEY_E,
	"f",			// KEY_F,
	"g",			// KEY_G,
	"h",			// KEY_H,
	"i",			// KEY_I,
	"j",			// KEY_J,
	"k",			// KEY_K,
	"l",			// KEY_L,
	"m",			// KEY_M,
	"n",			// KEY_N,
	"o",			// KEY_O,
	"p",			// KEY_P,
	"q",			// KEY_Q,
	"r",			// KEY_R,
	"s",			// KEY_S,
	"t",			// KEY_T,
	"u",			// KEY_U,
	"v",			// KEY_V,
	"w",			// KEY_W,
	"x",			// KEY_X,
	"y",			// KEY_Y,
	"z",			// KEY_Z,
	"KP_INS",		// KEY_PAD_0,
	"KP_END",		// KEY_PAD_1,
	"KP_DOWNARROW",	// KEY_PAD_2,
	"KP_PGDN",		// KEY_PAD_3,
	"KP_LEFTARROW",	// KEY_PAD_4,
	"KP_5",			// KEY_PAD_5,
	"KP_RIGHTARROW",// KEY_PAD_6,
	"KP_HOME",		// KEY_PAD_7,
	"KP_UPARROW",	// KEY_PAD_8,
	"KP_PGUP",		// KEY_PAD_9,
	"KP_SLASH",		// KEY_PAD_DIVIDE,
	"KP_MULTIPLY",	// KEY_PAD_MULTIPLY,
	"KP_MINUS",		// KEY_PAD_MINUS,
	"KP_PLUS",		// KEY_PAD_PLUS,
	"KP_ENTER",		// KEY_PAD_ENTER,
	"KP_DEL",		// KEY_PAD_DECIMAL,
	"[",			// KEY_LBRACKET,
	"]",			// KEY_RBRACKET,
	"SEMICOLON",	// KEY_SEMICOLON,
	"'",			// KEY_APOSTROPHE,
	"`",			// KEY_BACKQUOTE,
	",",			// KEY_COMMA,
	".",			// KEY_PERIOD,
	"/",			// KEY_SLASH,
	"\\",			// KEY_BACKSLASH,
	"-",			// KEY_MINUS,
	"=",			// KEY_EQUAL,
	"ENTER",		// KEY_ENTER,
	"SPACE",		// KEY_SPACE,
	"BACKSPACE",	// KEY_BACKSPACE,
	"TAB",			// KEY_TAB,
	"CAPSLOCK",		// KEY_CAPSLOCK,
	"NUMLOCK",		// KEY_NUMLOCK,
	"ESCAPE",		// KEY_ESCAPE,
	"SCROLLLOCK",	// KEY_SCROLLLOCK,
	"INS",			// KEY_INSERT,
	"DEL",			// KEY_DELETE,
	"HOME",			// KEY_HOME,
	"END",			// KEY_END,
	"PGUP",			// KEY_PAGEUP,
	"PGDN",			// KEY_PAGEDOWN,
	"PAUSE",		// KEY_BREAK,
	"SHIFT",		// KEY_LSHIFT,
	"RSHIFT",		// KEY_RSHIFT,
	"ALT",			// KEY_LALT,
	"RALT",			// KEY_RALT,
	"CTRL",			// KEY_LCONTROL,
	"RCTRL",		// KEY_RCONTROL,
	"LWIN",			// KEY_LWIN,
	"RWIN",			// KEY_RWIN,
	"APP",			// KEY_APP,
	"UPARROW",		// KEY_UP,
	"LEFTARROW",	// KEY_LEFT,
	"DOWNARROW",	// KEY_DOWN,
	"RIGHTARROW",	// KEY_RIGHT,
	"F1",			// KEY_F1,
	"F2",			// KEY_F2,
	"F3",			// KEY_F3,
	"F4",			// KEY_F4,
	"F5",			// KEY_F5,
	"F6",			// KEY_F6,
	"F7",			// KEY_F7,
	"F8",			// KEY_F8,
	"F9",			// KEY_F9,
	"F10",			// KEY_F10,
	"F11",			// KEY_F11,
	"F12",			// KEY_F12,

	// FIXME: CAPSLOCK/NUMLOCK/SCROLLLOCK all appear above. What are these for?!
	// They only appear in CInputWin32::UpdateToggleButtonState in vgui2
	"CAPSLOCKTOGGLE",	// KEY_CAPSLOCKTOGGLE,
	"NUMLOCKTOGGLE",	// KEY_NUMLOCKTOGGLE,
	"SCROLLLOCKTOGGLE", // KEY_SCROLLLOCKTOGGLE,

	// Mouse
	"MOUSE1",		// MOUSE_LEFT,
	"MOUSE2",		// MOUSE_RIGHT,
	"MOUSE3",		// MOUSE_MIDDLE,
	"MOUSE4",		// MOUSE_4,
	"MOUSE5",		// MOUSE_5,

	"MWHEELUP",		// MOUSE_WHEEL_UP
	"MWHEELDOWN",	// MOUSE_WHEEL_DOWN

#if defined ( _X360 ) || defined ( _LINUX )
	"A_BUTTON",		// JOYSTICK_FIRST_BUTTON		
	"B_BUTTON",		
	"X_BUTTON",		
	"Y_BUTTON",		
	"L_SHOULDER",		
	"R_SHOULDER",		
	"BACK",		
	"START",
	"STICK1",		
	"STICK2",		
#else
	"JOY1",			// JOYSTICK_FIRST_BUTTON
	"JOY2",		
	"JOY3",		
	"JOY4",		
	"JOY5",		
	"JOY6",		
	"JOY7",		
	"JOY8",		
	"JOY9",		
	"JOY10",
#endif

	"JOY11",		
	"JOY12",		
	"JOY13",		
	"JOY14",		
	"JOY15",		
	"JOY16",		
	"JOY17",	
	"JOY18",		
	"JOY19",		
	"JOY20",	
	"JOY21",	
	"JOY22",	
	"JOY23",		
	"JOY24",		
	"JOY25",		
	"JOY26",		
	"JOY27",	
	"JOY28",	
	"JOY29",	
	"JOY30",		
	"JOY31",		
	"JOY32",		// JOYSTICK_LAST_BUTTON

#if defined ( _X360 )
	"UP",			// JOYSTICK_FIRST_POV_BUTTON
	"RIGHT",		
	"DOWN",		
	"LEFT",			// JOYSTICK_LAST_POV_BUTTON

	"S1_RIGHT",		// JOYSTICK_FIRST_AXIS_BUTTON
	"S1_LEFT",		
	"S1_DOWN",
	"S1_UP",		
	"L_TRIGGER",		
	"R_TRIGGER",
	"S2_RIGHT",
	"S2_LEFT",		
	"S2_DOWN",
	"S2_UP",		// JOYSTICK_LAST_AXIS_BUTTON
	"V AXIS POS",
	"V AXIS NEG",		
#else
	"POV_UP",		// JOYSTICK_FIRST_POV_BUTTON
	"POV_RIGHT",		
	"POV_DOWN",		
	"POV_LEFT",		// JOYSTICK_LAST_POV_BUTTON

	"X AXIS POS",	// JOYSTICK_FIRST_AXIS_BUTTON
	"X AXIS NEG",		
	"Y AXIS POS",
	"Y AXIS NEG",		
	"Z AXIS POS",
	"Z AXIS NEG",		
	"R AXIS POS",
	"R AXIS NEG",		
	"U AXIS POS",
	"U AXIS NEG",		
	"V AXIS POS",
	"V AXIS NEG",	// JOYSTICK_LAST_AXIS_BUTTON
	"FALCON_NULL", // NVNT temp Fix for unaligned joystick enumeration
	"FALCON_1",	// NOVINT_FIRST
	"FALCON_2",
	"FALCON_3",
	"FALCON_4",
	"FALCON2_1",
	"FALCON2_2",
	"FALCON2_3",
	"FALCON2_4", // NOVINT_LAST
#endif

	SCONTROLLERBUTTONS_BUTTONS( 0 ),
	SCONTROLLERBUTTONS_BUTTONS( 1 ),
	SCONTROLLERBUTTONS_BUTTONS( 2 ),
	SCONTROLLERBUTTONS_BUTTONS( 3 ),
	SCONTROLLERBUTTONS_BUTTONS( 4 ),
	SCONTROLLERBUTTONS_BUTTONS( 5 ),
	SCONTROLLERBUTTONS_BUTTONS( 6 ),
	SCONTROLLERBUTTONS_BUTTONS( 7 ),

	SCONTROLLERBUTTONS_AXIS( 0 ),
	SCONTROLLERBUTTONS_AXIS( 1 ),
	SCONTROLLERBUTTONS_AXIS( 2 ),
	SCONTROLLERBUTTONS_AXIS( 3 ),
	SCONTROLLERBUTTONS_AXIS( 4 ),
	SCONTROLLERBUTTONS_AXIS( 5 ),
	SCONTROLLERBUTTONS_AXIS( 6 ),
	SCONTROLLERBUTTONS_AXIS( 7 ),

	SCONTROLLERBUTTONS_VBUTTONS( 0 ),
	SCONTROLLERBUTTONS_VBUTTONS( 1 ),
	SCONTROLLERBUTTONS_VBUTTONS( 2 ),
	SCONTROLLERBUTTONS_VBUTTONS( 3 ),
	SCONTROLLERBUTTONS_VBUTTONS( 4 ),
	SCONTROLLERBUTTONS_VBUTTONS( 5 ),
	SCONTROLLERBUTTONS_VBUTTONS( 6 ),
	SCONTROLLERBUTTONS_VBUTTONS( 7 ),
};

static const char *s_pAnalogCodeName[ ] =
{
	"MOUSE_X",		// MOUSE_X = 0,
	"MOUSE_Y",		// MOUSE_Y,
	"MOUSE_XY",		// MOUSE_XY,		// Invoked when either x or y changes
	"MOUSE_WHEEL",	// MOUSE_WHEEL,

	"X AXIS",		// JOY_AXIS_X
	"Y AXIS",		// JOY_AXIS_Y
	"Z AXIS",		// JOY_AXIS_Z
	"R AXIS",		// JOY_AXIS_R
	"U AXIS",		// JOY_AXIS_U
	"V AXIS",		// JOY_AXIS_V
};

#if !defined ( _X360 )
static const char *s_pXControllerButtonCodeNames[ ] =
{
	"A_BUTTON",		// JOYSTICK_FIRST_BUTTON		
	"B_BUTTON",		
	"X_BUTTON",		
	"Y_BUTTON",		
	"L_SHOULDER",		
	"R_SHOULDER",		
	"BACK",		
	"START",
	"STICK1",		
	"STICK2",		
	"JOY11",		
	"JOY12",		
	"JOY13",		
	"JOY14",		
	"JOY15",		
	"JOY16",		
	"JOY17",	
	"JOY18",		
	"JOY19",		
	"JOY20",	
	"JOY21",	
	"JOY22",	
	"JOY23",		
	"JOY24",		
	"JOY25",		
	"JOY26",		
	"JOY27",	
	"JOY28",	
	"JOY29",	
	"JOY30",		
	"JOY31",		
	"JOY32",		// JOYSTICK_LAST_BUTTON

	"UP",			// JOYSTICK_FIRST_POV_BUTTON
	"RIGHT",		
	"DOWN",		
	"LEFT",			// JOYSTICK_LAST_POV_BUTTON

	"S1_RIGHT",		// JOYSTICK_FIRST_AXIS_BUTTON
	"S1_LEFT",		
	"S1_DOWN",
	"S1_UP",		
	"L_TRIGGER",		
	"R_TRIGGER",
	"S2_RIGHT",
	"S2_LEFT",		
	"S2_DOWN",
	"S2_UP",		// JOYSTICK_LAST_AXIS_BUTTON
	"V AXIS POS",
	"V AXIS NEG",		
};
#endif

// this maps non-translated keyboard scan codes to engine key codes
// Google for 'Keyboard Scan Code Specification'
static ButtonCode_t s_pScanToButtonCode_QWERTY[128] = 
{ 
	//	0				1				2				3				4				5				6				7 
	//	8				9				A				B				C				D				E				F 
	KEY_NONE,		KEY_ESCAPE,		KEY_1,			KEY_2,			KEY_3,			KEY_4,			KEY_5,			KEY_6,			// 0
	KEY_7,			KEY_8,			KEY_9,			KEY_0,			KEY_MINUS,		KEY_EQUAL,		KEY_BACKSPACE,	KEY_TAB,		// 0 

	KEY_Q,			KEY_W,			KEY_E,			KEY_R,			KEY_T,			KEY_Y,			KEY_U,			KEY_I,			// 1
	KEY_O,			KEY_P,			KEY_LBRACKET,	KEY_RBRACKET,	KEY_ENTER,		KEY_LCONTROL,	KEY_A,			KEY_S,			// 1 

	KEY_D,			KEY_F,			KEY_G,			KEY_H,			KEY_J,			KEY_K,			KEY_L,			KEY_SEMICOLON,	// 2 
	KEY_APOSTROPHE,	KEY_BACKQUOTE,	KEY_LSHIFT,		KEY_BACKSLASH,	KEY_Z,			KEY_X,			KEY_C,			KEY_V,			// 2 

	KEY_B,			KEY_N,			KEY_M,			KEY_COMMA,		KEY_PERIOD,		KEY_SLASH,		KEY_RSHIFT,		KEY_PAD_MULTIPLY,// 3
	KEY_LALT,		KEY_SPACE,		KEY_CAPSLOCK,	KEY_F1,			KEY_F2,			KEY_F3,			KEY_F4,			KEY_F5,			// 3 

	KEY_F6,			KEY_F7,			KEY_F8,			KEY_F9,			KEY_F10,		KEY_NUMLOCK,	KEY_SCROLLLOCK,	KEY_HOME,		// 4
	KEY_UP,			KEY_PAGEUP,		KEY_PAD_MINUS,	KEY_LEFT,		KEY_PAD_5,		KEY_RIGHT,		KEY_PAD_PLUS,	KEY_END,		// 4 

	KEY_DOWN,		KEY_PAGEDOWN,	KEY_INSERT,		KEY_DELETE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_F11,		// 5
	KEY_F12,		KEY_BREAK,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		// 5

	KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		// 6
	KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		// 6 

	KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		// 7
	KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE,		KEY_NONE		// 7 
};

static ButtonCode_t s_pScanToButtonCode[128];


void ButtonCode_InitKeyTranslationTable()
{
	COMPILE_TIME_ASSERT( sizeof(s_pButtonCodeName) / sizeof( const char * ) == BUTTON_CODE_LAST );
	COMPILE_TIME_ASSERT( sizeof(s_pAnalogCodeName) / sizeof( const char * ) == ANALOG_CODE_LAST );

	// set virtual key translation table
	memset( s_pVirtualKeyToButtonCode, KEY_NONE, sizeof(s_pVirtualKeyToButtonCode) );

	s_pVirtualKeyToButtonCode['0']			=KEY_0;
	s_pVirtualKeyToButtonCode['1']			=KEY_1;
	s_pVirtualKeyToButtonCode['2']			=KEY_2;
	s_pVirtualKeyToButtonCode['3']			=KEY_3;
	s_pVirtualKeyToButtonCode['4']			=KEY_4;
	s_pVirtualKeyToButtonCode['5']			=KEY_5;
	s_pVirtualKeyToButtonCode['6']			=KEY_6;
	s_pVirtualKeyToButtonCode['7']			=KEY_7;
	s_pVirtualKeyToButtonCode['8']			=KEY_8;
	s_pVirtualKeyToButtonCode['9']			=KEY_9;
	s_pVirtualKeyToButtonCode['A']			=KEY_A;
	s_pVirtualKeyToButtonCode['B'] 			=KEY_B;
	s_pVirtualKeyToButtonCode['C'] 			=KEY_C;
	s_pVirtualKeyToButtonCode['D'] 			=KEY_D;
	s_pVirtualKeyToButtonCode['E']			=KEY_E;
	s_pVirtualKeyToButtonCode['F']			=KEY_F;
	s_pVirtualKeyToButtonCode['G']			=KEY_G;
	s_pVirtualKeyToButtonCode['H'] 			=KEY_H;
	s_pVirtualKeyToButtonCode['I']			=KEY_I;
	s_pVirtualKeyToButtonCode['J']			=KEY_J;
	s_pVirtualKeyToButtonCode['K']			=KEY_K;
	s_pVirtualKeyToButtonCode['L']			=KEY_L;
	s_pVirtualKeyToButtonCode['M']			=KEY_M;
	s_pVirtualKeyToButtonCode['N']			=KEY_N;
	s_pVirtualKeyToButtonCode['O']			=KEY_O;
	s_pVirtualKeyToButtonCode['P']			=KEY_P;
	s_pVirtualKeyToButtonCode['Q']			=KEY_Q;
	s_pVirtualKeyToButtonCode['R']			=KEY_R;
	s_pVirtualKeyToButtonCode['S']			=KEY_S;
	s_pVirtualKeyToButtonCode['T']			=KEY_T;
	s_pVirtualKeyToButtonCode['U']			=KEY_U;
	s_pVirtualKeyToButtonCode['V']			=KEY_V;
	s_pVirtualKeyToButtonCode['W']			=KEY_W;
	s_pVirtualKeyToButtonCode['X']			=KEY_X;
	s_pVirtualKeyToButtonCode['Y']			=KEY_Y;
	s_pVirtualKeyToButtonCode['Z']			=KEY_Z;
#if !defined( POSIX )
	s_pVirtualKeyToButtonCode[VK_NUMPAD0]	=KEY_PAD_0;
	s_pVirtualKeyToButtonCode[VK_NUMPAD1]	=KEY_PAD_1;
	s_pVirtualKeyToButtonCode[VK_NUMPAD2]	=KEY_PAD_2;
	s_pVirtualKeyToButtonCode[VK_NUMPAD3]	=KEY_PAD_3;
	s_pVirtualKeyToButtonCode[VK_NUMPAD4]	=KEY_PAD_4;
	s_pVirtualKeyToButtonCode[VK_NUMPAD5]	=KEY_PAD_5;
	s_pVirtualKeyToButtonCode[VK_NUMPAD6]	=KEY_PAD_6;
	s_pVirtualKeyToButtonCode[VK_NUMPAD7]	=KEY_PAD_7;
	s_pVirtualKeyToButtonCode[VK_NUMPAD8]	=KEY_PAD_8;
	s_pVirtualKeyToButtonCode[VK_NUMPAD9]	=KEY_PAD_9;
	s_pVirtualKeyToButtonCode[VK_DIVIDE]	=KEY_PAD_DIVIDE;
	s_pVirtualKeyToButtonCode[VK_MULTIPLY]	=KEY_PAD_MULTIPLY;
	s_pVirtualKeyToButtonCode[VK_SUBTRACT]	=KEY_PAD_MINUS;
	s_pVirtualKeyToButtonCode[VK_ADD]		=KEY_PAD_PLUS;
	s_pVirtualKeyToButtonCode[VK_RETURN]	=KEY_PAD_ENTER;
	s_pVirtualKeyToButtonCode[VK_DECIMAL]	=KEY_PAD_DECIMAL;
#endif
	s_pVirtualKeyToButtonCode[0xdb]			=KEY_LBRACKET;
	s_pVirtualKeyToButtonCode[0xdd]			=KEY_RBRACKET;
	s_pVirtualKeyToButtonCode[0xba]			=KEY_SEMICOLON;
	s_pVirtualKeyToButtonCode[0xde]			=KEY_APOSTROPHE;
	s_pVirtualKeyToButtonCode[0xc0]			=KEY_BACKQUOTE;
	s_pVirtualKeyToButtonCode[0xbc]			=KEY_COMMA;
	s_pVirtualKeyToButtonCode[0xbe]			=KEY_PERIOD;
	s_pVirtualKeyToButtonCode[0xbf]			=KEY_SLASH;
	s_pVirtualKeyToButtonCode[0xdc]			=KEY_BACKSLASH;
	s_pVirtualKeyToButtonCode[0xbd]			=KEY_MINUS;
	s_pVirtualKeyToButtonCode[0xbb]			=KEY_EQUAL;
#if !defined( POSIX )
	s_pVirtualKeyToButtonCode[VK_RETURN]	=KEY_ENTER;
	s_pVirtualKeyToButtonCode[VK_SPACE]		=KEY_SPACE;
	s_pVirtualKeyToButtonCode[VK_BACK]		=KEY_BACKSPACE;
	s_pVirtualKeyToButtonCode[VK_TAB]		=KEY_TAB;
	s_pVirtualKeyToButtonCode[VK_CAPITAL]	=KEY_CAPSLOCK;
	s_pVirtualKeyToButtonCode[VK_NUMLOCK]	=KEY_NUMLOCK;
	s_pVirtualKeyToButtonCode[VK_ESCAPE]	=KEY_ESCAPE;
	s_pVirtualKeyToButtonCode[VK_SCROLL]	=KEY_SCROLLLOCK;
	s_pVirtualKeyToButtonCode[VK_INSERT]	=KEY_INSERT;
	s_pVirtualKeyToButtonCode[VK_DELETE]	=KEY_DELETE;
	s_pVirtualKeyToButtonCode[VK_HOME]		=KEY_HOME;
	s_pVirtualKeyToButtonCode[VK_END]		=KEY_END;
	s_pVirtualKeyToButtonCode[VK_PRIOR]		=KEY_PAGEUP;
	s_pVirtualKeyToButtonCode[VK_NEXT]		=KEY_PAGEDOWN;
	s_pVirtualKeyToButtonCode[VK_PAUSE]		=KEY_BREAK;
	s_pVirtualKeyToButtonCode[VK_SHIFT]		=KEY_RSHIFT;
	s_pVirtualKeyToButtonCode[VK_SHIFT]		=KEY_LSHIFT;	// SHIFT -> left SHIFT
	s_pVirtualKeyToButtonCode[VK_MENU]		=KEY_RALT;
	s_pVirtualKeyToButtonCode[VK_MENU]		=KEY_LALT;		// ALT -> left ALT
	s_pVirtualKeyToButtonCode[VK_CONTROL]	=KEY_RCONTROL;
	s_pVirtualKeyToButtonCode[VK_CONTROL]	=KEY_LCONTROL;	// CTRL -> left CTRL
	s_pVirtualKeyToButtonCode[VK_LWIN]		=KEY_LWIN;
	s_pVirtualKeyToButtonCode[VK_RWIN]		=KEY_RWIN;
	s_pVirtualKeyToButtonCode[VK_APPS]		=KEY_APP;
	s_pVirtualKeyToButtonCode[VK_UP]		=KEY_UP;
	s_pVirtualKeyToButtonCode[VK_LEFT]		=KEY_LEFT;
	s_pVirtualKeyToButtonCode[VK_DOWN]		=KEY_DOWN;
	s_pVirtualKeyToButtonCode[VK_RIGHT]		=KEY_RIGHT;	
	s_pVirtualKeyToButtonCode[VK_F1]		=KEY_F1;
	s_pVirtualKeyToButtonCode[VK_F2]		=KEY_F2;
	s_pVirtualKeyToButtonCode[VK_F3]		=KEY_F3;
	s_pVirtualKeyToButtonCode[VK_F4]		=KEY_F4;
	s_pVirtualKeyToButtonCode[VK_F5]		=KEY_F5;
	s_pVirtualKeyToButtonCode[VK_F6]		=KEY_F6;
	s_pVirtualKeyToButtonCode[VK_F7]		=KEY_F7;
	s_pVirtualKeyToButtonCode[VK_F8]		=KEY_F8;
	s_pVirtualKeyToButtonCode[VK_F9]		=KEY_F9;
	s_pVirtualKeyToButtonCode[VK_F10]		=KEY_F10;
	s_pVirtualKeyToButtonCode[VK_F11]		=KEY_F11;
	s_pVirtualKeyToButtonCode[VK_F12]		=KEY_F12;
#endif

	// init the xkey translation table
#if !defined( POSIX )
	s_pXKeyTrans[XK_NULL]					= KEY_NONE;
	s_pXKeyTrans[XK_BUTTON_UP]				= KEY_XBUTTON_UP;
	s_pXKeyTrans[XK_BUTTON_DOWN]			= KEY_XBUTTON_DOWN;
	s_pXKeyTrans[XK_BUTTON_LEFT]			= KEY_XBUTTON_LEFT;
	s_pXKeyTrans[XK_BUTTON_RIGHT]			= KEY_XBUTTON_RIGHT;
	s_pXKeyTrans[XK_BUTTON_START]			= KEY_XBUTTON_START;
	s_pXKeyTrans[XK_BUTTON_BACK]			= KEY_XBUTTON_BACK;
	s_pXKeyTrans[XK_BUTTON_STICK1]			= KEY_XBUTTON_STICK1;
	s_pXKeyTrans[XK_BUTTON_STICK2]			= KEY_XBUTTON_STICK2;
	s_pXKeyTrans[XK_BUTTON_A]				= KEY_XBUTTON_A;
	s_pXKeyTrans[XK_BUTTON_B]				= KEY_XBUTTON_B;
	s_pXKeyTrans[XK_BUTTON_X]				= KEY_XBUTTON_X;
	s_pXKeyTrans[XK_BUTTON_Y]				= KEY_XBUTTON_Y;
	s_pXKeyTrans[XK_BUTTON_LEFT_SHOULDER]   = KEY_XBUTTON_LEFT_SHOULDER;
	s_pXKeyTrans[XK_BUTTON_RIGHT_SHOULDER]	= KEY_XBUTTON_RIGHT_SHOULDER;
	s_pXKeyTrans[XK_BUTTON_LTRIGGER]		= KEY_XBUTTON_LTRIGGER;
	s_pXKeyTrans[XK_BUTTON_RTRIGGER]		= KEY_XBUTTON_RTRIGGER;
	s_pXKeyTrans[XK_STICK1_UP]				= KEY_XSTICK1_UP;
	s_pXKeyTrans[XK_STICK1_DOWN]			= KEY_XSTICK1_DOWN;
	s_pXKeyTrans[XK_STICK1_LEFT]			= KEY_XSTICK1_LEFT;
	s_pXKeyTrans[XK_STICK1_RIGHT]			= KEY_XSTICK1_RIGHT;
	s_pXKeyTrans[XK_STICK2_UP]				= KEY_XSTICK2_UP;
	s_pXKeyTrans[XK_STICK2_DOWN]			= KEY_XSTICK2_DOWN;
	s_pXKeyTrans[XK_STICK2_LEFT]			= KEY_XSTICK2_LEFT;
	s_pXKeyTrans[XK_STICK2_RIGHT]			= KEY_XSTICK2_RIGHT;
#endif // PLATFORM_POSIX

	// create reverse table engine to virtual
	for ( int i = 0; i < ARRAYSIZE( s_pVirtualKeyToButtonCode ); i++ )
	{
		s_pButtonCodeToVirtual[ s_pVirtualKeyToButtonCode[i] ] = i;
	}

	s_pButtonCodeToVirtual[0] = 0;

	s_pSKeytoButtonCode[SK_NULL] = KEY_NONE;
	s_pSKeytoButtonCode[SK_BUTTON_A] = STEAMCONTROLLER_A;
	s_pSKeytoButtonCode[SK_BUTTON_B] = STEAMCONTROLLER_B;
	s_pSKeytoButtonCode[SK_BUTTON_X] = STEAMCONTROLLER_X;
	s_pSKeytoButtonCode[SK_BUTTON_Y] = STEAMCONTROLLER_Y;
	s_pSKeytoButtonCode[SK_BUTTON_UP] = STEAMCONTROLLER_DPAD_UP;
	s_pSKeytoButtonCode[SK_BUTTON_RIGHT] = STEAMCONTROLLER_DPAD_RIGHT;
	s_pSKeytoButtonCode[SK_BUTTON_DOWN] = STEAMCONTROLLER_DPAD_DOWN;
	s_pSKeytoButtonCode[SK_BUTTON_LEFT] = STEAMCONTROLLER_DPAD_LEFT;
	s_pSKeytoButtonCode[SK_BUTTON_LEFT_BUMPER] = STEAMCONTROLLER_LEFT_BUMPER;
	s_pSKeytoButtonCode[SK_BUTTON_RIGHT_BUMPER] = STEAMCONTROLLER_RIGHT_BUMPER;
	s_pSKeytoButtonCode[SK_BUTTON_LEFT_TRIGGER] = STEAMCONTROLLER_LEFT_TRIGGER;
	s_pSKeytoButtonCode[SK_BUTTON_RIGHT_TRIGGER] = STEAMCONTROLLER_RIGHT_TRIGGER;
	s_pSKeytoButtonCode[SK_BUTTON_LEFT_GRIP] = STEAMCONTROLLER_LEFT_GRIP;
	s_pSKeytoButtonCode[SK_BUTTON_RIGHT_GRIP] = STEAMCONTROLLER_RIGHT_GRIP;
	s_pSKeytoButtonCode[SK_BUTTON_LPAD_TOUCH] = STEAMCONTROLLER_LEFT_PAD_FINGERDOWN;
	s_pSKeytoButtonCode[SK_BUTTON_RPAD_TOUCH] = STEAMCONTROLLER_RIGHT_PAD_FINGERDOWN;
	s_pSKeytoButtonCode[SK_BUTTON_LPAD_CLICK] = STEAMCONTROLLER_LEFT_PAD_CLICK;
	s_pSKeytoButtonCode[SK_BUTTON_RPAD_CLICK] = STEAMCONTROLLER_RIGHT_PAD_CLICK;
	s_pSKeytoButtonCode[SK_BUTTON_LPAD_UP] = STEAMCONTROLLER_LEFT_PAD_UP;
	s_pSKeytoButtonCode[SK_BUTTON_LPAD_RIGHT] = STEAMCONTROLLER_LEFT_PAD_RIGHT;
	s_pSKeytoButtonCode[SK_BUTTON_LPAD_DOWN] = STEAMCONTROLLER_LEFT_PAD_DOWN;
	s_pSKeytoButtonCode[SK_BUTTON_LPAD_LEFT] = STEAMCONTROLLER_LEFT_PAD_LEFT;
	s_pSKeytoButtonCode[SK_BUTTON_RPAD_UP] = STEAMCONTROLLER_RIGHT_PAD_UP;
	s_pSKeytoButtonCode[SK_BUTTON_RPAD_RIGHT] = STEAMCONTROLLER_RIGHT_PAD_RIGHT;
	s_pSKeytoButtonCode[SK_BUTTON_RPAD_DOWN] = STEAMCONTROLLER_RIGHT_PAD_DOWN;
	s_pSKeytoButtonCode[SK_BUTTON_RPAD_LEFT] = STEAMCONTROLLER_RIGHT_PAD_LEFT;
	s_pSKeytoButtonCode[SK_BUTTON_SELECT] = STEAMCONTROLLER_SELECT;
	s_pSKeytoButtonCode[SK_BUTTON_START] = STEAMCONTROLLER_START;
	s_pSKeytoButtonCode[SK_BUTTON_STEAM] = STEAMCONTROLLER_STEAM;
	s_pSKeytoButtonCode[SK_BUTTON_INACTIVE_START] = STEAMCONTROLLER_INACTIVE_START;

	// These are fake ("virtual") steam controller buttons that don't physically exist, but we can manufacture to make internal routing
	// to old school UI (which is expecting button code rather than actions) without clashing with other butt
	s_pSKeytoButtonCode[SK_VBUTTON_F1] = STEAMCONTROLLER_F1;
	s_pSKeytoButtonCode[SK_VBUTTON_F2] = STEAMCONTROLLER_F2;
	s_pSKeytoButtonCode[SK_VBUTTON_F3] = STEAMCONTROLLER_F3;
	s_pSKeytoButtonCode[SK_VBUTTON_F4] = STEAMCONTROLLER_F4;
	s_pSKeytoButtonCode[SK_VBUTTON_F5] = STEAMCONTROLLER_F5;
	s_pSKeytoButtonCode[SK_VBUTTON_F6] = STEAMCONTROLLER_F6;
	s_pSKeytoButtonCode[SK_VBUTTON_F7] = STEAMCONTROLLER_F7;
	s_pSKeytoButtonCode[SK_VBUTTON_F8] = STEAMCONTROLLER_F8;
	s_pSKeytoButtonCode[SK_VBUTTON_F9] = STEAMCONTROLLER_F9;
	s_pSKeytoButtonCode[SK_VBUTTON_F10] = STEAMCONTROLLER_F10;
	s_pSKeytoButtonCode[SK_VBUTTON_F11] = STEAMCONTROLLER_F11;
	s_pSKeytoButtonCode[SK_VBUTTON_F12] = STEAMCONTROLLER_F12;
}

ButtonCode_t ButtonCode_VirtualKeyToButtonCode( int keyCode )
{
	if ( keyCode < 0 || keyCode >= sizeof( s_pVirtualKeyToButtonCode ) / sizeof( s_pVirtualKeyToButtonCode[0] ) )
	{
		Assert( false );
		return KEY_NONE;
	}
	return s_pVirtualKeyToButtonCode[keyCode];
}

int ButtonCode_ButtonCodeToVirtualKey( ButtonCode_t code )
{
	return s_pButtonCodeToVirtual[code];
}

ButtonCode_t ButtonCode_XKeyToButtonCode( int nPort, int keyCode )
{
#if !defined( POSIX )
	if ( keyCode < 0 || keyCode >= sizeof( s_pXKeyTrans ) / sizeof( s_pXKeyTrans[0] ) )
	{
		Assert( false );
		return KEY_NONE;
	}

	ButtonCode_t code = s_pXKeyTrans[keyCode];
	if ( IsJoystickButtonCode( code ) )
	{
		int nOffset = code - JOYSTICK_FIRST_BUTTON;
		return JOYSTICK_BUTTON( nPort, nOffset );
	}
	
	if ( IsJoystickPOVCode( code ) )
	{
		int nOffset = code - JOYSTICK_FIRST_POV_BUTTON;
		return JOYSTICK_POV_BUTTON( nPort, nOffset );
	}
	
	if ( IsJoystickAxisCode( code ) )
	{
		int nOffset = code - JOYSTICK_FIRST_AXIS_BUTTON;
		return JOYSTICK_AXIS_BUTTON( nPort, nOffset );
	}

	return code;
#else // POSIX
	return KEY_NONE;
#endif // POSIX
}

// Convert back + forth between ButtonCode/AnalogCode + strings
const char *ButtonCode_ButtonCodeToString( ButtonCode_t code, bool bXController )
{
#if !defined ( _X360 )
	if ( bXController && code >= JOYSTICK_FIRST_BUTTON && code <= JOYSTICK_LAST_AXIS_BUTTON )
		return s_pXControllerButtonCodeNames[ code - JOYSTICK_FIRST_BUTTON ];
#endif

	return s_pButtonCodeName[ code ];
}

const char *AnalogCode_AnalogCodeToString( AnalogCode_t code )
{
	return s_pAnalogCodeName[ code ];
}

ButtonCode_t ButtonCode_StringToButtonCode( const char *pString, bool bXController )
{
	if ( !pString || !pString[0] )
		return BUTTON_CODE_INVALID;

	// Backward compat for screwed up previous joystick button names
	if ( !Q_strnicmp( pString, "aux", 3 ) )
	{
		int nIndex = atoi( &pString[3] );
		if ( nIndex < 29 )
			return JOYSTICK_BUTTON( 0, nIndex );
		if ( ( nIndex >= 29 ) && ( nIndex <= 32 ) )
			return JOYSTICK_POV_BUTTON( 0, nIndex - 29 );
		return BUTTON_CODE_INVALID;
	}

	for ( int i = 0; i < BUTTON_CODE_LAST; ++i )
	{
		if ( !Q_stricmp( s_pButtonCodeName[i], pString ) )
			return (ButtonCode_t)i;
	}

#if !defined ( _X360 )
	if ( bXController )
	{
		for ( int i = 0; i < ARRAYSIZE(s_pXControllerButtonCodeNames); ++i )
		{
			if ( !Q_stricmp( s_pXControllerButtonCodeNames[i], pString ) )
				return (ButtonCode_t)(JOYSTICK_FIRST_BUTTON + i);
		}
	}
#endif

	return BUTTON_CODE_INVALID;
}

ButtonCode_t ButtonCode_SKeyToButtonCode( int nPort, int keyCode )
{
#if !defined( _GAMECONSOLE )
	if ( keyCode < 0 || keyCode >= sizeof( s_pSKeytoButtonCode ) / sizeof( s_pSKeytoButtonCode[0] ) )
	{
		Assert( false );
		return KEY_NONE;
	}

	ButtonCode_t code = s_pSKeytoButtonCode[keyCode];
	// 	if ( IsSteamControllerCode( code ) )
	// 	{
	// 		// Need Per Controller Offset here.
	// 		return code;
	// 	}

	if ( IsSteamControllerButtonCode( code ) )
	{
		int nOffset = code - STEAMCONTROLLER_FIRST_BUTTON;
		return STEAMCONTROLLER_BUTTON( nPort, nOffset );
	}

	if ( IsSteamControllerAxisCode( code ) )
	{
		int nOffset = code - STEAMCONTROLLER_FIRST_AXIS_BUTTON;
		return STEAMCONTROLLER_AXIS_BUTTON( nPort, nOffset );
	}

	return code;
#else // _GAMECONSOLE
	return KEY_NONE;
#endif // _GAMECONSOLE
}

AnalogCode_t AnalogCode_StringToAnalogCode( const char *pString )
{
	if ( !pString || !pString[0] )
		return ANALOG_CODE_INVALID;

	for ( int i = 0; i < ANALOG_CODE_LAST; ++i )
	{
		if ( !Q_stricmp( s_pAnalogCodeName[i], pString ) )
			return (AnalogCode_t)i;
	}

	return ANALOG_CODE_INVALID;
}

ButtonCode_t ButtonCode_ScanCodeToButtonCode( int lParam )
{
	int nScanCode = ( lParam >> 16 ) & 0xFF;
	if ( nScanCode > 127 )
		return KEY_NONE;

	ButtonCode_t result = s_pScanToButtonCode[nScanCode];

	bool bIsExtended = ( lParam & ( 1 << 24 ) ) != 0;
	if ( !bIsExtended )
	{
		switch ( result )
		{
		case KEY_HOME:
			return KEY_PAD_7;
		case KEY_UP:
			return KEY_PAD_8;
		case KEY_PAGEUP:
			return KEY_PAD_9;
		case KEY_LEFT:
			return KEY_PAD_4;
		case KEY_RIGHT:
			return KEY_PAD_6;
		case KEY_END:
			return KEY_PAD_1;
		case KEY_DOWN:
			return KEY_PAD_2;
		case KEY_PAGEDOWN:
			return KEY_PAD_3;
		case KEY_INSERT:
			return KEY_PAD_0;
		case KEY_DELETE:
			return KEY_PAD_DECIMAL;
		default:
			break;
		}
	}
	else
	{
		switch ( result )
		{
		case KEY_ENTER:
			return KEY_PAD_ENTER;
		case KEY_LALT:
			return KEY_RALT;
		case KEY_LCONTROL:
			return KEY_RCONTROL;
		case KEY_SLASH:
			return KEY_PAD_DIVIDE;
		case KEY_CAPSLOCK:
			return KEY_PAD_PLUS;
		}
	}

	return result;
}


//-----------------------------------------------------------------------------
// Update scan codes for foreign keyboards
//-----------------------------------------------------------------------------
void ButtonCode_UpdateScanCodeLayout( )
{
	// reset the keyboard
	memcpy( s_pScanToButtonCode, s_pScanToButtonCode_QWERTY, sizeof(s_pScanToButtonCode) );

#if !defined( _X360 ) && !defined( POSIX )
	// fix up keyboard layout for other languages
	HKL currentKb = ::GetKeyboardLayout( 0 );
	HKL englishKb = ::LoadKeyboardLayout("00000409", 0);

	if (englishKb && englishKb != currentKb)
	{
		for ( int i = 0; i < ARRAYSIZE(s_pScanToButtonCode); i++ )
		{
			// take the english/QWERTY
			ButtonCode_t code = s_pScanToButtonCode_QWERTY[ i ];

			// only remap printable keys
			if ( code != KEY_NONE && code != KEY_BACKQUOTE && ( IsAlphaNumeric( code ) || IsPunctuation( code ) ) )
			{
				// get it's virtual key based on the old layout
				int vk = ::MapVirtualKeyEx( i, 1, englishKb );

				// turn in into a scancode on the new layout
				int newScanCode = ::MapVirtualKeyEx( vk, 0, currentKb );

				// strip off any high bits
				newScanCode &= 0x0000007F;

				// set in the new layout
				s_pScanToButtonCode[newScanCode] = code;
			}
		}
	}

	s_pScanToButtonCode[0] = KEY_NONE;
#endif
}


//-----------------------------------------------------------------------------
// Purpose: Updates the current keyboard layout
//-----------------------------------------------------------------------------
CON_COMMAND( key_updatelayout, "Updates game keyboard layout to current windows keyboard setting." )
{
	ButtonCode_UpdateScanCodeLayout();
}