Class KF2GUIController extends Info
	transient;

var() class<GUIStyleBase> DefaultStyle;

var PlayerController PlayerOwner;
var ScoreboardExtHUD HUDOwner;
var transient KF2GUIInput CustomInput;
var transient PlayerInput BackupInput;
var transient GameViewportClient ClientViewport;

var delegate<Interaction.OnReceivedNativeInputKey> OldOnReceivedNativeInputKey;
var delegate<Interaction.OnReceivedNativeInputAxis> OldOnReceivedNativeInputAxis;
var delegate<Interaction.OnReceivedNativeInputChar> OldOnReceivedNativeInputChar;

var delegate<GameViewportClient.HandleInputAxis> OldHandleInputAxis;

var array<KFGUI_Page> ActiveMenus,PersistentMenus;
var transient KFGUI_Base MouseFocus,InputFocus,KeyboardFocus;
var IntPoint MousePosition,ScreenSize,OldMousePos,LastMousePos,LastClickPos[2];
var transient float MousePauseTime,MenuTime,LastClickTimes[2];
var transient GUIStyleBase CurrentStyle;

var transient Console OrgConsole;
var transient KFGUIConsoleHack HackConsole;

var array<Texture2D> CursorTextures;
var Color CursorColor;
var int CurrentCursorIndex, CursorSize;

var Texture DefaultPens[3];
var byte CursorFade, FastCursorFade, CursorFlash;
var int CursorStep, FastCursorStep;
var int FontBlurX,FontBlurX2,FontBlurY,FontBlurY2,FastFontBlurX,FastFontBlurX2,FastFontBlurY,FastFontBlurY2;

var bool bMouseWasIdle,bIsInMenuState,bAbsorbInput,bIsInvalid,bHideCursor,bUsingGamepad,bForceEngineCursor,bNoInputReset;

static function KF2GUIController GetGUIController( PlayerController PC )
{
	local KF2GUIController G;

	if( PC.Player==None )
	{
		return None;
	}

	foreach PC.ChildActors(class'ScoreboardExt.KF2GUIController',G)
	{
		if( !G.bIsInvalid )
		{
			break;
		}
	}

	if( G==None )
	{
		G = PC.Spawn(class'ScoreboardExt.KF2GUIController',PC);
	}

	return G;
}

simulated function PostBeginPlay()
{
	PlayerOwner = PlayerController(Owner);
	ClientViewport = LocalPlayer(PlayerOwner.Player).ViewportClient;
	HUDOwner = ScoreboardExtHUD(PlayerOwner.myHUD);

	CurrentStyle = new (None) DefaultStyle;
	CurrentStyle.InitStyle();
	CurrentStyle.Owner = self;

	SetTimer(0.1, true, 'SetupFontBlur');
	SetTimer(0.05, true, 'SetupFastFontBlur');

	SetTimer(0.75, true, 'SetupCursorFlash');
}

simulated function SetupCursorFlash()
{
	if( CursorFlash == 255 )
		CursorFlash = 0;
	else CursorFlash = 255;
}

simulated function SetupFastFontBlur()
{
	FastFontBlurX = RandRange(-8, 8);
	FastFontBlurX2 = RandRange(-8, 8);
	FastFontBlurY = RandRange(-8, 8);
	FastFontBlurY2 = RandRange(-8, 8);
}

simulated function SetupFontBlur()
{
	FontBlurX = RandRange(-8, 8);
	FontBlurX2 = RandRange(-8, 8);
	FontBlurY = RandRange(-8, 8);
	FontBlurY2 = RandRange(-8, 8);
}

simulated function Tick(float DT)
{
	Super.Tick(DT);

	DT /= WorldInfo.TimeDilation;

	CursorFade += 255 * DT * CursorStep;
	if( CursorFade<=0 )
	{
		CursorFade = 0;
		CursorStep = 1;
	}
	else if( CursorFade>=255 )
	{
		CursorFade = 255;
		CursorStep = -1;
	}

	FastCursorFade += 8192 * DT * FastCursorStep;
	if( FastCursorFade<=0 )
	{
		FastCursorFade = 0;
		FastCursorStep = 1;
	}
	else if( FastCursorFade>=255 )
	{
		FastCursorFade = 255;
		FastCursorStep = -1;
	}
}

simulated function Destroyed()
{
	if( PlayerOwner!=None )
		SetMenuState(false);
}

simulated function HandleDrawMenu()
{
	if( HackConsole==None )
	{
		HackConsole = new(ClientViewport)class'ScoreboardExt.KFGUIConsoleHack';
		HackConsole.OutputObject = Self;
	}
	if( HackConsole!=ClientViewport.ViewportConsole )
	{
		OrgConsole = ClientViewport.ViewportConsole;
		ClientViewport.ViewportConsole = HackConsole;

		// Make sure nothing overrides these settings while menu is being open.
		if( bIsInMenuState ) PlayerOwner.PlayerInput = CustomInput;
	}
}
simulated function RenderMenu( Canvas C )
{
	local int i;
	local float OrgX,OrgY,ClipX,ClipY;

	ClientViewport.ViewportConsole = OrgConsole;

	OrgX = C.OrgX;
	OrgY = C.OrgY;
	ClipX = C.ClipX;
	ClipY = C.ClipY;

	ScreenSize.X = C.SizeX;
	ScreenSize.Y = C.SizeY;
	CurrentStyle.Canvas = C;
	CurrentStyle.PickDefaultFontSize(C.SizeY);

	if( !KFPlayerController(PlayerOwner).MyGFxManager.bMenusActive )
	{
		HUDOwner.Canvas = C;

		for( i=(HUDOwner.HUDWidgets.Length-1); i>=0; --i )
		{
			HUDOwner.HUDWidgets[i].InputPos[0] = 0.f;
			HUDOwner.HUDWidgets[i].InputPos[1] = 0.f;
			HUDOwner.HUDWidgets[i].InputPos[2] = ScreenSize.X;
			HUDOwner.HUDWidgets[i].InputPos[3] = ScreenSize.Y;
			HUDOwner.HUDWidgets[i].Canvas = C;
			HUDOwner.HUDWidgets[i].PreDraw();
		}

		C.SetOrigin(OrgX,OrgY);
		C.SetClip(ClipX,ClipY);
	}

	if( bIsInMenuState )
	{
		for( i=(ActiveMenus.Length-1); i>=0; --i )
		{
			ActiveMenus[i].bWindowFocused = (i==0);
			ActiveMenus[i].InputPos[0] = 0.f;
			ActiveMenus[i].InputPos[1] = 0.f;
			ActiveMenus[i].InputPos[2] = ScreenSize.X;
			ActiveMenus[i].InputPos[3] = ScreenSize.Y;
			ActiveMenus[i].Canvas = C;
			ActiveMenus[i].PreDraw();
		}
		if( InputFocus!=None && InputFocus.bFocusedPostDrawItem )
		{
			InputFocus.InputPos[0] = 0.f;
			InputFocus.InputPos[1] = 0.f;
			InputFocus.InputPos[2] = ScreenSize.X;
			InputFocus.InputPos[3] = ScreenSize.Y;
			InputFocus.Canvas = C;
			InputFocus.PreDraw();
		}
		C.SetOrigin(OrgX,OrgY);
		C.SetClip(ClipX,ClipY);

		if (!bHideCursor)
		{
			DrawCursor(C, MousePosition.X, MousePosition.Y);
		}
	}

	if( OrgConsole!=None )
		OrgConsole.PostRender_Console(C);
	OrgConsole = None;
}

simulated function DrawCursor(Canvas C, float PosX, float PosY)
{
	C.SetPos(PosX, PosY);
	C.DrawColor = CursorColor;
	C.DrawTile(CursorTextures[CurrentCursorIndex], CurrentStyle.ScreenScale(CursorSize), CurrentStyle.ScreenScale(CursorSize), 0.f, 0.f, CursorTextures[CurrentCursorIndex].SizeX, CursorTextures[CurrentCursorIndex].SizeY,, true);
}

simulated final function InventoryChanged(optional KFWeapon Wep, optional bool bRemove)
{
	local int i;

	for( i=(ActiveMenus.Length-1); i>=0; --i )
	{
		ActiveMenus[i].InventoryChanged(Wep,bRemove);
	}
}

simulated final function SetMenuState( bool bActive )
{
	if( PlayerOwner.PlayerInput==None )
	{
		NotifyLevelChange();
		bActive = false;
	}

	if( bIsInMenuState==bActive )
		return;
	bIsInMenuState = bActive;
	bHideCursor = !bActive;

	if( bActive )
	{
		if( CustomInput==None )
		{
			CustomInput = new (KFPlayerController(PlayerOwner)) class'ScoreboardExt.KF2GUIInput';
			CustomInput.ControllerOwner = Self;
			CustomInput.OnReceivedNativeInputKey = ReceivedInputKey;
			CustomInput.BaseInput = PlayerOwner.PlayerInput;
			BackupInput = PlayerOwner.PlayerInput;
			PlayerOwner.Interactions.AddItem(CustomInput);
		}

		OldOnReceivedNativeInputKey = BackupInput.OnReceivedNativeInputKey;
		OldOnReceivedNativeInputAxis = BackupInput.OnReceivedNativeInputAxis;
		OldOnReceivedNativeInputChar = BackupInput.OnReceivedNativeInputChar;

		BackupInput.OnReceivedNativeInputKey = ReceivedInputKey;
		BackupInput.OnReceivedNativeInputAxis = ReceivedInputAxis;
		BackupInput.OnReceivedNativeInputChar = ReceivedInputChar;

		OldHandleInputAxis = ClientViewport.HandleInputAxis;
		ClientViewport.HandleInputAxis = ReceivedInputAxis;

		PlayerOwner.PlayerInput = CustomInput;

		if( LastMousePos != default.LastMousePos )
			ClientViewport.SetMouse(LastMousePos.X,LastMousePos.Y);
	}
	else
	{
		LastMousePos = MousePosition;

		ClientViewport.HandleInputAxis = None;

		if( BackupInput!=None )
		{
			PlayerOwner.PlayerInput = BackupInput;
			BackupInput.OnReceivedNativeInputKey = OldOnReceivedNativeInputKey;
			BackupInput.OnReceivedNativeInputAxis = OldOnReceivedNativeInputAxis;
			BackupInput.OnReceivedNativeInputChar = OldOnReceivedNativeInputChar;

			ClientViewport.HandleInputAxis = OldHandleInputAxis;
		}
		LastClickTimes[0] = 0;
		LastClickTimes[1] = 0;
	}

	if( !bNoInputReset )
	{
		PlayerOwner.PlayerInput.ResetInput();
	}
}

simulated function NotifyLevelChange()
{
	local int i;

	if( bIsInvalid )
		return;
	bIsInvalid = true;

	if( InputFocus!=None )
	{
		InputFocus.LostInputFocus();
		InputFocus = None;
	}

	for( i=(ActiveMenus.Length-1); i>=0; --i )
		ActiveMenus[i].NotifyLevelChange();
	for( i=(PersistentMenus.Length-1); i>=0; --i )
		PersistentMenus[i].NotifyLevelChange();

	SetMenuState(false);
}

simulated function MenuInput(float DeltaTime)
{
	local int i;
	local vector2D V;

	if( PlayerOwner.PlayerInput==None )
	{
		NotifyLevelChange();
		return;
	}
	if( InputFocus!=None )
		InputFocus.MenuTick(DeltaTime);
	for( i=0; i<ActiveMenus.Length; ++i )
		ActiveMenus[i].MenuTick(DeltaTime);

	// Check idle.
	if( Abs(MousePosition.X-OldMousePos.X)>5.f || Abs(MousePosition.Y-OldMousePos.Y)>5.f || (bMouseWasIdle && MousePauseTime<0.5f) )
	{
		if( bMouseWasIdle )
		{
			bMouseWasIdle = false;
			if( InputFocus!=None )
				InputFocus.InputMouseMoved();
		}
		OldMousePos = MousePosition;
		MousePauseTime = 0.f;
	}
	else if( !bMouseWasIdle && (MousePauseTime+=DeltaTime)>0.5f )
	{
		bMouseWasIdle = true;
		if( MouseFocus!=None )
			MouseFocus.NotifyMousePaused();
	}

	if( ActiveMenus.Length>0 )
		MenuTime+=DeltaTime;

	V = ClientViewport.GetMousePosition();

	MousePosition.X = Clamp(V.X, 0, ScreenSize.X); 
	MousePosition.Y = Clamp(V.Y, 0, ScreenSize.Y); 

	MouseMove();
}

simulated function MouseMove()
{
	local int i;
	local KFGUI_Base F;

	// Capture mouse for GUI
	if( InputFocus!=None && InputFocus.bCanFocus )
	{
		if( InputFocus.CaptureMouse() )
		{
			F = InputFocus.GetMouseFocus();
			if( F!=MouseFocus )
			{
				MousePauseTime = 0;
				if( MouseFocus!=None )
					MouseFocus.MouseLeave();
				MouseFocus = F;
				F.MouseEnter();
			}
		}
		else i = ActiveMenus.Length;
	}
	else
	{
		for( i=0; i<ActiveMenus.Length; ++i )
		{
			if( ActiveMenus[i].CaptureMouse() )
			{
				F = ActiveMenus[i].GetMouseFocus();
				if( F!=MouseFocus )
				{
					MousePauseTime = 0;
					if( MouseFocus!=None )
						MouseFocus.MouseLeave();
					MouseFocus = F;
					F.MouseEnter();
				}
				break;
			}
			else if( ActiveMenus[i].bOnlyThisFocus ) // Discard any other menus after this one.
			{
				i = ActiveMenus.Length;
				break;
			}
		}
	}
	if( MouseFocus!=None && i==ActiveMenus.Length ) // Hovering over nothing.
	{
		MousePauseTime = 0;
		if( MouseFocus!=None )
			MouseFocus.MouseLeave();
		MouseFocus = None;
	}
}

simulated final function int GetFreeIndex( bool bNewAlwaysTop ) // Find first allowed top index of the stack.
{
	local int i;

	for( i=0; i<ActiveMenus.Length; ++i )
		if( bNewAlwaysTop || !ActiveMenus[i].bAlwaysTop )
		{
			ActiveMenus.Insert(i,1);
			return i;
		}
	i = ActiveMenus.Length;
	ActiveMenus.Length = i+1;
	return i;
}
simulated function KFGUI_Base InitializeHUDWidget( class<KFGUI_Base> GUIClass )
{
	local KFGUI_Base Widget;

	if( GUIClass==None )
		return None;

	Widget = New(None) GUIClass;

	if( Widget==None )
		return None;

	HUDOwner.HUDWidgets.AddItem(Widget);

	Widget.Owner = Self;
	Widget.HUDOwner = HUDOwner;
	Widget.InitMenu();
	Widget.ShowMenu();
	Widget.bIsHUDWidget = true;

	return Widget;
}
simulated function KFGUI_Page OpenMenu( class<KFGUI_Page> MenuClass )
{
	local int i;
	local KFGUI_Page M;

	if( MenuClass==None )
		return None;

	if( KeyboardFocus!=None )
		GrabInputFocus(None);
	if( InputFocus!=None )
	{
		InputFocus.LostInputFocus();
		InputFocus = None;
	}

	// Enable mouse on UI if disabled.
	SetMenuState(true);

	// Check if should use pre-excisting menu.
	if( MenuClass.Default.bUnique )
	{
		for( i=0; i<ActiveMenus.Length; ++i )
			if( ActiveMenus[i].Class==MenuClass )
			{
				if( i>0 && ActiveMenus[i].BringPageToFront() ) // Sort it upfront.
				{
					M = ActiveMenus[i];
					ActiveMenus.Remove(i,1);
					i = GetFreeIndex(M.bAlwaysTop);
					ActiveMenus[i] = M;
				}
				return M;
			}

		if( MenuClass.Default.bPersistant )
		{
			for( i=0; i<PersistentMenus.Length; ++i )
				if( PersistentMenus[i].Class==MenuClass )
				{
					M = PersistentMenus[i];
					PersistentMenus.Remove(i,1);
					i = GetFreeIndex(M.bAlwaysTop);
					ActiveMenus[i] = M;
					M.ShowMenu();
					return M;
				}
		}
	}
	M = New(None)MenuClass;

	if( M==None ) // Probably abstract class.
		return None;

	i = GetFreeIndex(M.bAlwaysTop);
	ActiveMenus[i] = M;
	M.Owner = Self;
	M.InitMenu();
	M.ShowMenu();
	return M;
}
simulated function CloseMenu( class<KFGUI_Page> MenuClass, optional bool bCloseAll )
{
	local int i, j;
	local KFGUI_Page M;

	if( !bCloseAll && MenuClass==None )
		return;

	if( KeyboardFocus!=None )
		GrabInputFocus(None);
	if( InputFocus!=None )
	{
		InputFocus.LostInputFocus();
		InputFocus = None;
	}
	for( i=(ActiveMenus.Length-1); i>=0; --i )
	{
		if( bCloseAll || ActiveMenus[i].Class==MenuClass )
		{
			M = ActiveMenus[i];
			ActiveMenus.Remove(i,1);
			M.CloseMenu();

			for( j=0; j<M.TimerNames.Length; j++ )
			{
				M.ClearTimer(M.TimerNames[j]);
			}

			// Cache menu.
			if( M.bPersistant && M.bUnique )
				PersistentMenus[PersistentMenus.Length] = M;
		}
	}
	if( ActiveMenus.Length==0 )
	{
		SetMenuState(false);
	}
}
simulated function PopCloseMenu( KFGUI_Base Item )
{
	local int i;
	local KFGUI_Page M;

	if( Item==None )
		return;

	if( Item.bIsHUDWidget )
	{
		HUDOwner.HUDWidgets.RemoveItem(Item);
		Item.CloseMenu();
		return;
	}

	if( KeyboardFocus!=None )
		GrabInputFocus(None);
	if( InputFocus!=None )
	{
		InputFocus.LostInputFocus();
		InputFocus = None;
	}
	for( i=(ActiveMenus.Length-1); i>=0; --i )
		if( ActiveMenus[i]==Item )
		{
			M = ActiveMenus[i];
			ActiveMenus.Remove(i,1);
			M.CloseMenu();

			// Cache menu.
			if( M.bPersistant && M.bUnique )
				PersistentMenus[PersistentMenus.Length] = M;
			break;
		}
	if( ActiveMenus.Length==0 )
		SetMenuState(false);
}
simulated function BringMenuToFront( KFGUI_Page Page )
{
	local int i;

	if( ActiveMenus[0].bAlwaysTop && !Page.bAlwaysTop )
		return; // Can't override this menu.

	// Try to remove from current position at stack.
	for( i=(ActiveMenus.Length-1); i>=0; --i )
		if( ActiveMenus[i]==Page )
		{
			ActiveMenus.Remove(i,1);
			break;
		}
	if( i==-1 )
		return; // Page isn't open.

	// Put on front of stack.
	ActiveMenus.Insert(0,1);
	ActiveMenus[0] = Page;
}
simulated final function bool MenuIsOpen( optional class<KFGUI_Page> MenuClass )
{
	local int i;

	for( i=(ActiveMenus.Length-1); i>=0; --i )
		if( MenuClass==None || ActiveMenus[i].Class==MenuClass )
			return true;
	return false;
}
simulated final function GrabInputFocus( KFGUI_Base Comp, optional bool bForce )
{
	if( Comp==KeyboardFocus && !bForce )
		return;

	if( KeyboardFocus!=None )
		KeyboardFocus.LostKeyFocus();

	if( Comp==None )
	{
		OnInputKey = InternalInputKey;
		OnReceivedInputChar = InternalReceivedInputChar;
	}
	else if( KeyboardFocus==None )
	{
		OnInputKey = Comp.NotifyInputKey;
		OnReceivedInputChar = Comp.NotifyInputChar;
		OnReceivedInputAxis = Comp.NotifyInputAxis;
	}
	KeyboardFocus = Comp;
}

simulated final function GUI_InputMouse( bool bPressed, bool bRight )
{
	local byte i;

	MousePauseTime = 0;

	if( bPressed )
	{
		if( KeyboardFocus!=None && KeyboardFocus!=MouseFocus )
		{
			GrabInputFocus(None);
			LastClickTimes[0] = 0;
			LastClickTimes[1] = 0;
		}
		if( MouseFocus!=None )
		{
			if( MouseFocus!=InputFocus && !MouseFocus.bClickable && !MouseFocus.IsTopMenu() && MouseFocus.BringPageToFront() )
			{
				BringMenuToFront(MouseFocus.GetPageTop());
				LastClickTimes[0] = 0;
				LastClickTimes[1] = 0;
			}
			else
			{
				i = byte(bRight);
				if( (MenuTime-LastClickTimes[i])<0.2 && Abs(LastClickPos[i].X-MousePosition.X)<5 && Abs(LastClickPos[i].Y-MousePosition.Y)<5 )
				{
					LastClickTimes[i] = 0;
					MouseFocus.DoubleMouseClick(bRight);
				}
				else
				{
					MouseFocus.MouseClick(bRight);
					LastClickTimes[i] = MenuTime;
					LastClickPos[i] = MousePosition;
				}
			}
		}
		else if( InputFocus!=None )
		{
			InputFocus.LostInputFocus();
			InputFocus = None;
			LastClickTimes[0] = 0;
			LastClickTimes[1] = 0;
		}
	}
	else
	{
		if( InputFocus!=None )
			InputFocus.MouseRelease(bRight);
		else if( MouseFocus!=None )
			MouseFocus.MouseRelease(bRight);
	}
}
simulated final function bool CheckMouse( name Key, EInputEvent Event )
{
	if ( Event == IE_Pressed )
	{
		switch( Key )
		{
		case 'XboxTypeS_A':
		case 'LeftMouseButton':
			GUI_InputMouse(true,false);
			return true;
		case 'XboxTypeS_B':
		case 'RightMouseButton':
			GUI_InputMouse(true,true);
			return true;
		}
	}
	else if ( Event == IE_Released )
	{
		switch( Key )
		{
		case 'XboxTypeS_A':
		case 'LeftMouseButton':
			GUI_InputMouse(false,false);
			return true;
		case 'XboxTypeS_B':
		case 'RightMouseButton':
			GUI_InputMouse(false,true);
			return true;
		}
	}
	return false;
}
simulated function bool ReceivedInputKey( int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad )
{
	local KFPlayerInput KFInput;
	local KeyBind BoundKey;

	if( !bIsInMenuState )
		return false;

	bUsingGamepad = bGamepad;

	KFInput = KFPlayerInput(BackupInput);
	if( KFInput == None )
	{
		KFInput = KFPlayerInput(PlayerOwner.PlayerInput);
	}

	if( KeyboardFocus == None )
	{
		if( KFInput != None )
		{	
			KFInput.GetKeyBindFromCommand(BoundKey, "GBA_VoiceChat", false);	
			if( string(Key) ~= KFInput.GetBindDisplayName(BoundKey) )
			{
				if( Event == IE_Pressed )
				{
					KFInput.StartVoiceChat(true);
				}
				else if( Event == IE_Released )
				{
					KFInput.StopVoiceChat();
				}

				return true;
			}
		}
	}

	if( !CheckMouse(Key,Event) && !OnInputKey(ControllerId,Key,Event,AmountDepressed,bGamepad) )
	{
		if( bGamepad )
		{
			if( ActiveMenus[0].ReceievedControllerInput(ControllerId, Key, Event) )
				return true;
		}

		switch( Key )
		{
		case 'XboxTypeS_Start':
		case 'Escape':
			if( Event==IE_Pressed )
				ActiveMenus[0].UserPressedEsc(); // Pop top menu if possible. // IE_Released
			return true;
		case 'XboxTypeS_DPad_Up':
		case 'XboxTypeS_DPad_Down':
		case 'XboxTypeS_DPad_Left':
		case 'XboxTypeS_DPad_Right':
		case 'MouseScrollDown':
		case 'MouseScrollUp':
			if( Event==IE_Pressed && MouseFocus!=None )
				MouseFocus.ScrollMouseWheel(Key=='MouseScrollUp' || Key=='XboxTypeS_DPad_Up' || Key=='XboxTypeS_DPad_Left');
			return true;
		}

		return bAbsorbInput;
	}

	return true;
}
simulated function bool ReceivedInputAxis( int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad )
{
	local Vector2D V;
	local KFPlayerInput KFInput;
	local float GamepadSensitivity,OldMouseX,OldMouseY,MoveDelta,MoveDeltaInvert;

	if( !bIsInMenuState )
		return false;

	if( bGamepad  )
	{
		if( Abs(Delta) > 0.2f )
		{
			bUsingGamepad = true;

			V = ClientViewport.GetMousePosition();
			OldMouseX = V.X;
			OldMouseY = V.Y;

			KFInput = KFPlayerInput(BackupInput);
			GamepadSensitivity = KFInput.GamepadSensitivityScale * 10;
			MoveDelta = Delta * (KFInput.bInvertController ? -GamepadSensitivity : GamepadSensitivity);
			MoveDeltaInvert = Delta * (KFInput.bInvertController ? GamepadSensitivity : -GamepadSensitivity);

			switch(Key)
			{
				case 'XboxTypeS_LeftX':
				case 'XboxTypeS_RightX':
					if( Delta < 0 )
						V.X = Clamp(V.X - MoveDeltaInvert, 0, ScreenSize.X);
					else V.X = Clamp(V.X + MoveDelta, 0, ScreenSize.X);
					break;
				case 'XboxTypeS_LeftY':
					if( Delta < 0 )
						V.Y = Clamp(V.Y + MoveDeltaInvert, 0, ScreenSize.Y);
					else V.Y = Clamp(V.Y - MoveDelta, 0, ScreenSize.Y);
					break;
				case 'XboxTypeS_RightY':
					if( Delta < 0 )
						V.Y = Clamp(V.Y - MoveDeltaInvert, 0, ScreenSize.Y);
					else V.Y = Clamp(V.Y + MoveDelta, 0, ScreenSize.Y);
					break;
			}

			if( OldMouseX != V.X || OldMouseY != V.Y )
				ClientViewport.SetMouse(V.X, V.Y);
		}
	}
	return OnReceivedInputAxis(ControllerId, Key, Delta, DeltaTime, bGamepad);
}
simulated function bool ReceivedInputChar( int ControllerId, string Unicode )
{
	if( !bIsInMenuState )
		return false;
	return OnReceivedInputChar(ControllerId,Unicode);
}

simulated Delegate bool OnInputKey( int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad )
{
	return false;
}
simulated Delegate bool OnReceivedInputAxis( int ControllerId, name Key, float Delta, float DeltaTime, bool bGamepad )
{
	return false;
}
simulated Delegate bool OnReceivedInputChar( int ControllerId, string Unicode )
{
	return false;
}
simulated Delegate bool InternalInputKey( int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad )
{
	return false;
}
simulated Delegate bool InternalReceivedInputChar( int ControllerId, string Unicode )
{
	return false;
}

defaultproperties
{
	CursorSize=24
	CursorColor=(R=255,G=255,B=255,A=255)
	CursorTextures[`CURSOR_DEFAULT]=Texture2D'UI_Managers.LoaderManager_SWF_I13'
	CurrentCursorIndex=`CURSOR_DEFAULT

	DefaultStyle=class'ClassicStyle'
	bAbsorbInput=true
	bAlwaysTick=true
	bHideCursor=true
}