//-----------------------------------------------------------
//
//-----------------------------------------------------------
class KFTab_Controls extends Settings_Tabs;

enum ESectionIDs
{
	SID_Movement,
	SID_Looking,
	SID_Weapons,
	SID_Comm,
	SID_Game,
	SID_Misc,
	SID_Interface
};

var automated GUISectionBackground      i_BG1;
var automated GUILabel                  l_Hint;
var automated GUIMultiColumnListBox     lb_Binds;
var GUIMultiColumnList                  li_Binds;

var bool                                bFirstOpen;

struct InputKeyInfo
{
	var int KeyNumber;
	var string KeyName;
	var string LocalizedKeyName;
};

struct KeyBinding
{
    var             bool            bIsSectionLabel;
    var             string          KeyLabel;
    var             string          Alias;
    var             array<int>  	BoundKeys;
};

var() noexport editconst InputKeyInfo AllKeys[255];

var() array<KeyBinding> Bindings;
var localized string BindingLabel[150]; 		// remove this later
var() bool bPendingRawInput;                  	// Waiting for input - changing a keybind

var() editconst noexport int  NewIndex, NewSubIndex;
var() editconst noexport GUIStyles SelStyle, SectionStyle;
var() string SectionStyleName;

var() localized string Headings[3];
var() float SectionLabelMargin;

//var() localized string PageCaption;
//var() localized string SpeechLabel;
var() localized string ClearCaption, ActionText;


var localized string        Section_Movement, Section_Looking,
                            Section_Weapons, Section_Comm,
                            Section_Game, Section_Misc,
                            Section_Interface, Section_Speech_Prefix;

var array<string>           bindings_movement,
                            bindings_looking,
                            bindings_weapons,
                            bindings_comm,
                            bindings_game,
                            bindings_misc,
                            bindings_interface;

// Those are static because for some reason it frells up if they're dynamic. go figure.
var localized string        captions_movement[15],
                            captions_looking[15],
                            captions_weapons[20],
                            captions_comm[15],
                            captions_game[15],
                            captions_misc[15],
                            captions_interface[15];

var class<KFVoicePack>      VoicePackClass;

function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
	Super.InitComponent(MyController, MyOwner);

	i_BG1.ManageComponent(lb_Binds);
	i_BG1.ManageComponent(l_Hint);

	li_Binds = lb_Binds.List;
	SectionStyle = Controller.GetStyle(SectionStyleName, li_Binds.FontScale);
}

function InitializeBindingsArray()
{
	local int i;

	for ( i = 0; i < ArrayCount(AllKeys); i++ )
	{
		AllKeys[i].KeyNumber = i;
		Controller.KeyNameFromIndex( byte(i), AllKeys[i].KeyName, AllKeys[i].LocalizedKeyName );
	}
}

function Initialize()
{
	LoadCommands();
	MapBindings();
}

// query each key's assigned command/alias, and add the key number to the appropriate place
function MapBindings()
{
    local int i, BindingIndex;
    local string Alias;

    LoadCustomBindings();

    for ( i = 1; i < ArrayCount(AllKeys); i++ )
    {
    	// Find out if this key is currently bound to any commands
    	if ( Controller.GetCurrentBind( AllKeys[i].KeyName, Alias ) )
        {
        	// If this key is bound to a command, find out if the command is a known alias
        	BindingIndex = FindAliasIndex( Alias );
        	if ( BindingIndex != -1 )
            	BindKeyToAlias( BindingIndex, i );
        }
    }
}

function CreateAliasMapping(string Command, string FriendlyName, bool bSectionLabel)
{
    local int At;

    At = Bindings.Length;
    Bindings.Length = Bindings.Length + 1;

    Bindings[At].bIsSectionLabel = bSectionLabel;
    Bindings[At].KeyLabel = FriendlyName;
    Bindings[At].Alias = Command;

    li_Binds.AddedItem();
}

function BindKeyToAlias( int BindIndex, int KeyIndex )
{
	local int i;

	if ( !ValidBindIndex(BindIndex) )
		return;

	if ( !ValidKeyIndex(KeyIndex) )
		return;

	for ( i = 0; i < Bindings[BindIndex].BoundKeys.Length; i++ )
	{
		if ( Bindings[BindIndex].BoundKeys[i] == KeyIndex )
			return;

		if ( class'GameInfo'.static.GetBindWeight(Bindings[BindIndex].BoundKeys[i]) < class'GameInfo'.static.GetBindWeight(KeyIndex) )
			break;
	}

	Bindings[BindIndex].BoundKeys.Insert( i, 1 );
	Bindings[BindIndex].BoundKeys[i] = KeyIndex;
}

function ClearBindings()
{
	Bindings.Remove(0,Bindings.Length);
	li_Binds.Clear();
}

function SetKeyBind(int Index, int SubIndex, byte NewKey)
{
	if ( !ValidBindIndex(Index) )
		return;

    if ( SubIndex < Bindings[Index].BoundKeys.Length && Bindings[Index].BoundKeys[SubIndex] == NewKey )
        return;

    RemoveAllOccurance(NewKey);
   	RemoveExistingKey(Index, SubIndex);

    if ( Controller.SetKeyBind(AllKeys[NewKey].KeyName, Bindings[Index].Alias) )
	    BindKeyToAlias(Index,NewKey);

//	Controller.SetKeyBind( AllKeys[NewKey].KeyName, Bindings[Index].Alias );
    li_Binds.UpdatedItem(Index);
}

function bool BeginRawInput(GUIComponent Sender)
{
    local int Index, SubIndex;

    if ( MouseOnCol1() )
        SubIndex = 0;
    else if ( MouseOnCol2() )
        SubIndex = 1;
    else
        return true;

	Index = li_Binds.CurrentListId();
	if ( ValidBindIndex(Index) && Bindings[Index].bIsSectionLabel )
		return true;

    bPendingRawInput = true;
    UpdateHint(Index);

	NewIndex = Index;
    NewSubIndex = SubIndex;

    Controller.OnNeedRawKeyPress = RawKey;
    Controller.Master.bRequireRawJoystick = true;

    PlayerOwner().ClientPlaySound(Controller.EditSound);
    PlayerOwner().ConsoleCommand("toggleime 0");

    return true;
}

function bool RawKey(byte NewKey)
{
   	SetKeyBind( NewIndex, NewSubIndex, NewKey );

    NewSubIndex = -1;
	UpdateHint(NewIndex);
    NewIndex = -1;

    bPendingRawInput = false;
    Controller.OnNeedRawKeyPress = none;
    Controller.Master.bRequireRawJoystick = false;

    PlayerOwner().ClientPlaySound(Controller.ClickSound);
    return true;

}

function string GetCurrentKeyBind(int BindIndex, int SubIndex)
{
	if ( !ValidBindIndex(BindIndex) )
		return "";

    if (Bindings[BindIndex].bIsSectionLabel)
        return "";

    if (BindIndex == NewIndex && SubIndex == NewSubIndex)
        return "???";

    if (SubIndex >= Bindings[BindIndex].BoundKeys.Length)
        return "";

    return AllKeys[Bindings[BindIndex].BoundKeys[SubIndex]].LocalizedKeyName;
}

function string ListGetSortString( int Index )
{
	switch ( li_Binds.SortColumn )
	{
	case 0: return Bindings[Index].KeyLabel;
	case 1: return GetCurrentKeyBind(Index,0);
	case 2: return GetCurrentKeyBind(Index,1);
	}

	return "";
}

function bool ListOnKeyEvent(out byte Key, out byte State, float delta)
{
    local Interactions.EInputKey iKey;

	if ( State != 3 )
		return li_Binds.InternalOnKeyEvent(Key,State,Delta);

	iKey = EInputKey(Key);
	if ( iKey == IK_Backspace )    // Backspace
    {
        // Clear Over
        if ( MouseOnCol1() )
            RemoveExistingKey(li_Binds.CurrentListId(),0);

        else if ( MouseOnCol2() )
            RemoveExistingKey(li_Binds.CurrentListId(),1);

        return true;
    }

    if ( iKey == IK_Enter )
    {
        BeginRawInput(None);
        return true;
    }

	return li_Binds.InternalOnKeyEvent(Key,State,Delta);
}

function ListTrack(GUIComponent Sender, int LastIndex)
{
	local int Index, OldIndex;

	if ( LastIndex >= 0 && LastIndex < li_Binds.ItemCount )
	{
		OldIndex = li_Binds.SortData[LastIndex].SortItem;
		Index = li_Binds.CurrentListId();

		if ( ValidBindIndex(Index) && Bindings[Index].bIsSectionLabel )
			SearchDown(OldIndex);

		if ( !bPendingRawInput )
			UpdateHint(Index);
	}
}

function SearchUp(int OldIndex)
{
    local int cindex;

    cindex = li_Binds.CurrentListId();
    while ( cindex > 0 && cindex < Bindings.length)
    {
        if ( !Bindings[cindex].bIsSectionLabel )
        {
            li_Binds.SetIndex(cIndex);
            return;
        }
        cindex--;
    }
    li_Binds.SetIndex(OldIndex);
}

function SearchDown(int OldIndex)
{
    local int cindex;

    cindex = li_Binds.CurrentListId();
    while ( cindex > 0 && cindex < Bindings.Length )
    {
        if (!Bindings[cindex].bIsSectionLabel)
        {
            li_Binds.SetIndex(cIndex);
            return;
        }
        cindex++;
    }
    li_Binds.SetIndex(OldIndex);
}

function RemoveExistingKey(int Index, int SubIndex)
{
	local int KeyIndex;

	if ( !ValidBindIndex(Index) )
		return;

    if ( SubIndex >= Bindings[Index].BoundKeys.Length || Bindings[Index].BoundKeys[SubIndex] < 0 )
        return;

	KeyIndex = Bindings[Index].BoundKeys[SubIndex];
    Bindings[Index].BoundKeys.Remove(SubIndex, 1);

	Controller.SetKeyBind( AllKeys[KeyIndex].KeyName, "" );
}

function RemoveAllOccurance(byte NewKey)
{
    local int i,j;

	for ( i = 0; i < Bindings.Length; i++ )
	{
		for ( j = 0; j < Bindings[i].BoundKeys.Length; j++ )
		{
			if ( Bindings[i].BoundKeys[j] == NewKey )
			{
				RemoveExistingKey(i,j);
				break;
			}
		}
	}
}

function UpdateHint(int BindIndex)
{
	local int i;
	local string Str, CurrentBindName;

    if ( !ValidBindIndex(BindIndex) || Bindings[BindIndex].bIsSectionLabel )
    {
    	l_Hint.Caption = "";
        return;
    }

	if ( Bindings[BindIndex].BoundKeys.Length > 0 )
	{
		if ( bPendingRawInput )
		{
		DrawCurrentBind:
			for ( i = 0; i < Bindings[BindIndex].BoundKeys.Length; i++ )
			{
				if ( Str != "" )
					Str $= ",";
				Str $= GetCurrentKeyBind(BindIndex, i);
			}

			if ( Str == "" )
				l_Hint.Caption = "";
			else l_Hint.Caption = Repl(ActionText, "%keybinds%", Str);
			return;
		}
		else
		{
			if ( MouseOnCol2() ) i = 1;
			CurrentBindName = GetCurrentKeyBind(BindIndex,i);
			if ( CurrentBindName == "" )
				goto DrawCurrentBind;

			Str = Repl(Repl(ClearCaption,"%backspace%",AllKeys[8].LocalizedKeyName),
			           "%keybind%",CurrentBindName);
			l_Hint.Caption = Repl( Str, "%keyname%", Bindings[BindIndex].KeyLabel );;
		}

	}
	else l_Hint.Caption = "";
}

function bool MouseOnCol1()
{
	local float CellLeft, CellWidth;

	li_Binds.GetCellLeftWidth(1, CellLeft, CellWidth);
	return Controller.MouseX >= CellLeft && Controller.MouseX <= CellLeft + CellWidth;
}

function bool MouseOnCol2()
{
	local float CellLeft, CellWidth;

	li_Binds.GetCellLeftWidth(2, CellLeft, CellWidth);
	return Controller.MouseX >= CellLeft && Controller.MouseX <= CellLeft + CellWidth;
}

function bool ValidBindIndex(int Index)
{
	return Index >= 0 && Index < Bindings.Length;
}

function bool ValidKeyIndex(int Index)
{
	return Index >= 0 && Index < ArrayCount(AllKeys);
}

function int FindAliasIndex( string Alias )
{
	local int i;

	for ( i = 0; i < Bindings.Length; i++ )
		if ( Bindings[i].Alias ~= Alias )
			return i;

	return -1;
}

function InternalOnCreateComponent( GUIComponent NewComp, GUIComponent Sender )
{
	local GUIMultiColumnList L;
	local int i;

	if ( GUIMultiColumnListBox(Sender) != None )
	{
		L = GUIMultiColumnList(NewComp);
		if ( L != None )
		{
			for ( i = 0; i < ArrayCount(Headings); i++ )
				L.ColumnHeadings[i] = Headings[i];

			L.OnKeyEvent = ListOnKeyEvent;
			L.OnDrawItem = DrawBinding;
			L.GetSortString = ListGetSortString;
			L.ExpandLastColumn = True;
			L.SortColumn = -1;
			L.bHotTrack = True;
			L.OnClick = BeginRawInput;
			L.OnTrack = ListTrack;
		}

		GUIMultiColumnListBox(Sender).InternalOnCreateComponent(NewComp,Sender);
	}

	//Super.InternalOnCreateComponent(NewComp,Sender);
}

function DrawBinding(Canvas Canvas, int Item, float X, float Y, float W, float H, bool bSelected, bool bPending)
{
    local float CellLeft, CellWidth;
    local GUIStyles DStyle;

	// hack to fix selected item appearing offset
	// real fix would be to create a "NoBackground" style that has the same border offsets as STY2ListSelection
	local int i;
    local int SavedOffset[4];

   	Canvas.Style = 1;
    Item = li_Binds.SortData[Item].SortItem;

	if ( !ValidBindIndex(Item) )
		return;

    if ( Bindings[Item].bIsSectionLabel )
    {
    	li_Binds.GetCellLeftWidth( 0, CellLeft, CellWidth );
    	Canvas.SetPos( CellLeft + 3, Y );
    	Canvas.DrawColor = SectionStyle.ImgColors[li_Binds.MenuState];

    	Canvas.DrawTile(Controller.DefaultPens[0], W - 6, H, 0, 0, 32, 32);
    	SectionStyle.DrawText(Canvas, li_Binds.MenuState, CellLeft + SectionLabelMargin, Y, CellWidth, H, TXTA_Left, Bindings[Item].KeyLabel, li_Binds.FontScale);
        return;
    }

    if ( bPendingRawInput )
    	bSelected = Item - li_Binds.Top == NewIndex;

    if ( bSelected )
    	DStyle = li_Binds.SelectedStyle;
    else DStyle = li_Binds.Style;

	for ( i = 0; i < 4; i++ )
	{
		SavedOffset[i] = DStyle.BorderOffsets[i];
		DStyle.BorderOffsets[i] = class'STY2ListSelection'.default.BorderOffsets[i];
	}

	if ( bSelected && !bPendingRawInput )
		DStyle.Draw( Canvas, li_Binds.MenuState, X + DStyle.BorderOffsets[0], Y, W - DStyle.BorderOffsets[2], H );

	li_Binds.GetCellLeftWidth(0, CellLeft, CellWidth);
	DStyle.DrawText( Canvas, li_Binds.MenuState, CellLeft, Y, CellWidth - DStyle.BorderOffsets[2], H, TXTA_Center, Bindings[Item].KeyLabel, li_Binds.FontScale);

	li_Binds.GetCellLeftWidth(1, CellLeft, CellWidth);
	if ( bPendingRawInput && bSelected && NewSubIndex == 0 )
		DStyle.Draw( Canvas, li_Binds.MenuState, CellLeft, Y, CellWidth - DStyle.BorderOffsets[2], H );
	DStyle.DrawText(Canvas, li_Binds.MenuState, CellLeft, Y, CellWidth - DStyle.BorderOffsets[2], H, TXTA_Center, GetCurrentKeyBind(Item, 0), li_Binds.FontScale);

	li_Binds.GetCellLeftWidth(2, CellLeft, CellWidth);
	if ( bPendingRawInput && bSelected && NewSubIndex == 1 )
		DStyle.Draw(Canvas, li_Binds.MenuState, CellLeft, Y, CellWidth - DStyle.BorderOffsets[2], H);
	DStyle.DrawText(Canvas, li_Binds.MenuState, CellLeft, Y, CellWidth - DStyle.BorderOffsets[2], H, TXTA_Center, GetCurrentKeyBind(Item, 1), li_Binds.FontScale);

	for ( i = 0; i < 4; i++ )
		DStyle.BorderOffsets[i] = SavedOffset[i];
}

function ResetClicked()
{
    if (Controller != none)
        Controller.ResetKeyboard();
	Initialize();
}

event Opened(GUIComponent Sender)
{
    if (bFirstOpen)
    {
        InitializeBindingsArray();
        Initialize();
        bFirstOpen = false;
    }

    Super.Opened(Sender);
}

protected function LoadCustomBindings()
{
	local int i;
	local array<string> KeyBindClasses;
    local class<GUIUserKeyBinding> CustomKeyBindClass;

    // Load custom keybinds from .int files
    PlayerOwner().GetAllInt("XInterface.GUIUserKeyBinding",KeyBindClasses);
	for (i = 0; i < KeyBindClasses.Length; i++)
	{
		CustomKeyBindClass = class<GUIUserKeyBinding>(DynamicLoadObject(KeyBindClasses[i],class'Class'));
		if (CustomKeyBindClass != None)
			AddCustomBindings( CustomKeyBindClass.default.KeyData );
    }
}

function AddCustomBindings( array<GUIUserKeyBinding.KeyInfo> KeyData )
{
	local int i;

	for ( i = 0; i < KeyData.Length; i++ )
		CreateAliasMapping( KeyData[i].Alias, KeyData[i].KeyLabel, KeyData[i].bIsSection );
}

/*function TestClearBindings()
{
	local int i, max;

	Bindings = default.Bindings;
	max = Min(Bindings.Length, ArrayCount(BindingLabel));
	for ( i = 0; i < max; i++ )
	{
		if ( BindingLabel[i] != "" )
			Bindings[i].KeyLabel = BindingLabel[i];
	}
}*/

// Add all possible commands to the guilist
function LoadCommands()
{
	local array<string> VoiceCommands;
	local int i;

	ClearBindings();

	// Load RO keybinds
	AddBindings(Section_Game,      bindings_game.length,       SID_Game);
	AddBindings(Section_Movement,  bindings_movement.length,   SID_Movement);
	AddBindings(Section_Weapons,   bindings_weapons.length,    SID_Weapons);
	AddBindings(Section_Looking,   bindings_looking.length,    SID_Looking);
	AddBindings(Section_Comm,      bindings_comm.length,       SID_Comm);
	AddBindings(Section_Interface, bindings_interface.length,  SID_Interface);
	AddBindings(Section_Misc,      bindings_misc.length,       SID_Misc);

	// Load custom keybinds
	LoadCustomBindings();

	// Load speech binds
	UpdateVoicePackClass();

	// Support
    CreateAliasMapping("", Section_Speech_Prefix $ class'KFConsole'.default.SMStateName[1], True);
	VoicePackClass.static.GetAllSupports(VoiceCommands);
	for ( i = 0; i < VoiceCommands.Length; i++ )
	{
		CreateAliasMapping("speech SUPPORT" @ i, VoiceCommands[i], false);
	}

	// Acknowledgments
    CreateAliasMapping("", Section_Speech_Prefix $ class'KFConsole'.default.SMStateName[2], True);
	VoicePackClass.static.GetAllAcknowledgments( VoiceCommands );
	for ( i = 0; i < VoiceCommands.Length; i++ )
	{
		CreateAliasMapping("speech ACK" @ i, VoiceCommands[i], false);
	}

    // Alerts
    CreateAliasMapping("", Section_Speech_Prefix $ class'KFConsole'.default.SMStateName[3], True);
	VoicePackClass.static.GetAllAlerts(VoiceCommands);
	for ( i = 0; i < VoiceCommands.Length; i++ )
	{
		CreateAliasMapping("speech ALERT" @ i, VoiceCommands[i], false);
	}

    // Directions
    CreateAliasMapping("", Section_Speech_Prefix $ class'KFConsole'.default.SMStateName[4], True);
	VoicePackClass.static.GetAllDirections(VoiceCommands);
	for ( i = 0; i < VoiceCommands.Length; i++ )
	{
		CreateAliasMapping("speech DIRECTION" @ i, VoiceCommands[i], false);
	}

    // Insults
	CreateAliasMapping("", Section_Speech_Prefix $ class'KFConsole'.default.SMStateName[5], True);
	VoicePackClass.static.GetAllInsults(VoiceCommands);
	for ( i = 0; i < VoiceCommands.Length; i++ )
	{
		CreateAliasMapping("speech INSULT" @ i, VoiceCommands[i], false);
	}
}

function UpdateVoicePackClass()
{
    // Keep default
}


// Valid section ids:
function AddBindings(string section_title, int num_elements, ESectionIDs section_id)
{
    local int i;
    local string a, c;

    if (section_title != "")
        CreateAliasMapping("", section_title, true );

    for (i = 0; i < num_elements; i++)
    {
        switch (section_id)
        {
            case SID_Movement: a = bindings_movement[i]; c = captions_movement[i]; break;
            case SID_Looking: a = bindings_looking[i]; c = captions_looking[i]; break;
            case SID_Weapons: a = bindings_weapons[i]; c = captions_weapons[i]; break;
            case SID_Comm: a = bindings_comm[i]; c = captions_comm[i]; break;
            case SID_Game: a = bindings_game[i]; c = captions_game[i]; break;
            case SID_Misc: a = bindings_misc[i]; c = captions_misc[i]; break;
            case SID_Interface: a = bindings_interface[i]; c = captions_interface[i]; break;
            default: a = ""; c = "Unknown id: " $ section_id; break;
        }

        CreateAliasMapping(a, c, false);
    }
}

defaultproperties
{
    Begin Object class=ROGUIProportionalContainer Name=InputBK1
		WinWidth=0.956718
		WinHeight=0.956718
		WinLeft=0.021641
		WinTop=0.021641
		Caption="Bindings"
        TopPadding=0.01
        LeftPadding=0.0
        RightPadding=0.0
        BottomPadding=0.0
	End Object
	i_BG1=InputBK1

	Begin Object Class=GUIMultiColumnListBox Name=BindListBox
		WinWidth=1
		WinHeight=0.9
		WinLeft=0
		WinTop=0
		bScaleToParent=True
		bBoundToParent=True
	    OnCreateComponent=InternalOnCreateComponent
	    HeaderColumnPerc(0)=0.5
	    HeaderColumnPerc(1)=0.25
	    HeaderColumnPerc(2)=0.25
	    TabOrder=0
	End Object
	lb_Binds=BindListBox

    Begin Object Class=GUILabel Name=HintLabel
        TextAlign=TXTA_Center
        bMultiline=True
        VertAlign=TXTA_Center
        FontScale=FNS_Small
        StyleName="textLabel"
        WinTop=0.95
        WinLeft=0
        WinWidth=1
        WinHeight=0.05
        bBoundToParent=True
        bScaleToParent=True
    End Object
    l_Hint=HintLabel

    // Movement keybinds
    Section_Movement="Movement"
    bindings_movement(0)="MoveForward"
    captions_movement(0)="Forward"
    bindings_movement(1)="MoveBackward"
    captions_movement(1)="Backward"
    bindings_movement(2)="StrafeLeft"
    captions_movement(2)="Strafe Left"
    bindings_movement(3)="StrafeRight"
    captions_movement(3)="Strafe Right"
    bindings_movement(4)="Jump"
    captions_movement(4)="Jump"
    bindings_movement(5)="Duck"
    captions_movement(5)="Crouch"
    bindings_movement(6)="ToggleDuck"
    captions_movement(6)="Toggle Crouch"
    bindings_movement(7)="Walking"
    captions_movement(7)="Walk"
    bindings_movement(8)="Strafe"
    captions_movement(8)="Toggle Strafe"

    // Looking keybinds
    Section_Looking="Looking"
    bindings_looking(0)="TurnLeft"
    captions_looking(0)="Turn Left"
    bindings_looking(1)="TurnRight"
    captions_looking(1)="Turn Right"
    bindings_looking(2)="LookUp"
    captions_looking(2)="Look Up"
    bindings_looking(3)="LookDown"
    captions_looking(3)="Look Down"
    bindings_looking(4)="CenterView"
    captions_looking(4)="Center View"
    bindings_looking(5)="ToggleBehindView"
    captions_looking(5)="Toggle Third Person Mode (offline only)"
    bindings_looking(6)="ToggleFreeCam"
    captions_looking(6)="Toggle Camera Mode (offline only)"

    // Weapons keybinds
    Section_Weapons="Weapons"
    bindings_weapons(0)="Fire"
    captions_weapons(0)="Primary Fire"
    bindings_weapons(1)="AltFire"
    captions_weapons(1)="Alternate Fire/Flashlight"
    bindings_weapons(2)="ReloadWeapon"
    captions_weapons(2)="Reload"
    bindings_weapons(3)="Aiming"
    captions_weapons(3)="Quick Iron Sights"
    bindings_weapons(4)="ToggleAiming"
    captions_weapons(4)="Toggle Iron Sights"
    bindings_weapons(5)="ThrowWeapon"
    captions_weapons(5)="Drop Weapon"
    bindings_weapons(6)="NextWeapon"
    captions_weapons(6)="Next Weapon"
    bindings_weapons(7)="PrevWeapon"
    captions_weapons(7)="Previous Weapon"
    bindings_weapons(8)="SwitchToBestWeapon"
    captions_weapons(8)="Switch to Best Weapon"
    bindings_weapons(9)="SwitchToLastWeapon"
    captions_weapons(9)="Switch to Last Weapon"
    bindings_weapons(10)="SwitchToBestMeleeWeapon"
    captions_weapons(10)="Switch to Knife"
    bindings_weapons(11)="SwitchWeapon 1"
    captions_weapons(11)="Select Melee Weapons"
    bindings_weapons(12)="SwitchWeapon 2"
    captions_weapons(12)="Select Secondary Weapons"
    bindings_weapons(13)="SwitchWeapon 3"
    captions_weapons(13)="Select Primary Weapons"
    bindings_weapons(14)="SwitchWeapon 4"
    captions_weapons(14)="Select Specialty Weapons"
    bindings_weapons(15)="SwitchWeapon 5"
    captions_weapons(15)="Select Tools"
    bindings_weapons(16)="ThrowNade"
    captions_weapons(16)="Throw Grenade"
    bindings_weapons(17)="ToggleFlashlight"
    captions_weapons(17)="Quick Flashlight"
    bindings_weapons(18)="QuickHeal"
    captions_weapons(18)="Quick Self-Heal"

    // Communication keybinds
    Section_Comm="Communication"
    bindings_comm(0)="Talk"
    captions_comm(0)="Say"
    bindings_comm(1)="TeamTalk"
    captions_comm(1)="Team Say"
    bindings_comm(2)="SpeechMenuToggle"
    captions_comm(2)="Toggle Voice Commands Menu"
    bindings_comm(3)="VoiceTalk"
    captions_comm(3)="Activate Microphone"
    bindings_comm(4)="Speak Public"
    captions_comm(4)="Switch to Public Voice Channel"
    bindings_comm(5)="Speak Local"
    captions_comm(5)="Switch to Local Voice Channel"
    bindings_comm(6)="Speak Team"
    captions_comm(6)="Switch to Team Voice Channel"

    // Game keybinds
    Section_Game="Game"
    bindings_game(0)="ShowMenu"
    captions_game(0)="Open Game Menu"
    bindings_game(1)="use"
    captions_game(1)="Use"
	bindings_game(2)="TossCash"
    captions_game(2)="Drop Cash"
    bindings_game(3)="shot"
    captions_game(3)="Screenshot"
    bindings_game(4)="Pause"
    captions_game(4)="Pause Game"

    // Interface keybinds
    Section_Interface="Interface"
    bindings_interface(0)="ShowScores"
    captions_interface(0)="Toggle Scoreboard"
    bindings_interface(1)="ScoreToggle"
    captions_interface(1)="Quick Scoreboard"
    bindings_interface(2)="ShowKickMenu"
    captions_interface(2)="Open Vote Kick Menu"

    // Miscellaneous keybinds
    Section_Misc="Miscellaneous"
    bindings_misc(0)="ConsoleToggle"
    captions_misc(0)="Toggle Console"
    bindings_misc(1)="Stat Net"
    captions_misc(1)="View Connection Status"
    bindings_misc(2)="Cancel"
    captions_misc(2)="Cancel Pending Connection"
    bindings_misc(3)="demorec"
    captions_misc(3)="Start Demo Recording"
    bindings_misc(4)="stopdemo"
    captions_misc(4)="Stop Demo Recording"

    // Speech sections
	Section_Speech_Prefix="Voice Commands: "

    Headings(0)="Action"
    Headings(1)="Key 1"
	Headings(2)="Key 2"

    SectionLabelMargin=10
	SectionStyleName="ListSection"

	ClearCaption="Press '%backspace%' to unbind %keybind% from %keyname%."
    ActionText="{%keybinds%} - currently bound to this key."

    bFirstOpen=true

    VoicePackClass=class'KFMod.KFVoicePack'
}

