ddnet/src/game/client/components/binds.cpp
Marcel Herd d513af6a42 Removed default bind for home key (kill)
Kill is already bound to K by default, binding it on home as well doesn't really have any purpose. (?)
Furthermore, the home key is right next to page up which is bound to toggling entities.
It is very easy to accidentally hit home instead of page up, which is highly frustrating.. therefore I suggest removing this duplicate binding.
2017-07-26 20:43:26 +02:00

352 lines
9.1 KiB
C++

/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <engine/config.h>
#include <engine/shared/config.h>
#include "binds.h"
bool CBinds::CBindsSpecial::OnInput(IInput::CEvent Event)
{
// don't handle invalid events and keys that arn't set to anything
if(((Event.m_Key >= KEY_F1 && Event.m_Key <= KEY_F12) || (Event.m_Key >= KEY_F13 && Event.m_Key <= KEY_F24)) && m_pBinds->m_apKeyBindings[Event.m_Key])
{
int Stroke = 0;
if(Event.m_Flags&IInput::FLAG_PRESS)
Stroke = 1;
m_pBinds->GetConsole()->ExecuteLineStroked(Stroke, m_pBinds->m_apKeyBindings[Event.m_Key]);
return true;
}
return false;
}
CBinds::CBinds()
{
mem_zero(m_apKeyBindings, sizeof(m_apKeyBindings));
m_SpecialBinds.m_pBinds = this;
}
CBinds::~CBinds()
{
for(int i = 0; i < KEY_LAST; i++)
if(m_apKeyBindings[i])
mem_free(m_apKeyBindings[i]);
}
void CBinds::Bind(int KeyID, const char *pStr, bool FreeOnly)
{
if(KeyID < 0 || KeyID >= KEY_LAST)
return;
if(FreeOnly && Get(KeyID)[0])
return;
if(m_apKeyBindings[KeyID])
{
mem_free(m_apKeyBindings[KeyID]);
m_apKeyBindings[KeyID] = 0;
}
char aBuf[256];
if(!pStr[0])
{
str_format(aBuf, sizeof(aBuf), "unbound %s (%d)", Input()->KeyName(KeyID), KeyID);
}
else
{
int size = str_length(pStr) + 1;
m_apKeyBindings[KeyID] = (char *)mem_alloc(size, 1);
if(!m_apKeyBindings[KeyID])
{
str_format(aBuf, sizeof(aBuf), "couldn't bind %s (%d) (bind might be too long)", Input()->KeyName(KeyID), KeyID);
}
else
{
str_copy(m_apKeyBindings[KeyID], pStr, size);
str_format(aBuf, sizeof(aBuf), "bound %s (%d) = %s", Input()->KeyName(KeyID), KeyID, m_apKeyBindings[KeyID]);
}
}
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf);
}
bool CBinds::OnInput(IInput::CEvent e)
{
// don't handle invalid events and keys that arn't set to anything
if(e.m_Key <= 0 || e.m_Key >= KEY_LAST || !m_apKeyBindings[e.m_Key])
return false;
if(e.m_Flags&IInput::FLAG_PRESS)
Console()->ExecuteLineStroked(1, m_apKeyBindings[e.m_Key]);
if(e.m_Flags&IInput::FLAG_RELEASE)
Console()->ExecuteLineStroked(0, m_apKeyBindings[e.m_Key]);
return true;
}
void CBinds::UnbindAll()
{
for(int i = 0; i < KEY_LAST; i++)
{
if(m_apKeyBindings[i])
mem_free(m_apKeyBindings[i]);
m_apKeyBindings[i] = 0;
}
}
const char *CBinds::Get(int KeyID)
{
if(KeyID > 0 && KeyID < KEY_LAST && m_apKeyBindings[KeyID])
return m_apKeyBindings[KeyID];
return "";
}
const char *CBinds::GetKey(const char *pBindStr)
{
for(int KeyId = 0; KeyId < KEY_LAST; KeyId++)
{
const char *pBind = Get(KeyId);
if(!pBind[0])
continue;
if(str_comp(pBind, pBindStr) == 0)
return Input()->KeyName(KeyId);
}
return "";
}
void CBinds::SetDefaults()
{
// set default key bindings
UnbindAll();
Bind(KEY_F1, "toggle_local_console");
Bind(KEY_F2, "toggle_remote_console");
Bind(KEY_TAB, "+scoreboard");
Bind(KEY_EQUALS, "+statboard");
Bind(KEY_F10, "screenshot");
Bind(KEY_A, "+left");
Bind(KEY_D, "+right");
Bind(KEY_SPACE, "+jump");
Bind(KEY_MOUSE_1, "+fire");
Bind(KEY_MOUSE_2, "+hook");
Bind(KEY_LSHIFT, "+emote");
#if defined(__ANDROID__)
Bind(KEY_RCTRL, "+fire");
Bind(KEY_RETURN, "+hook");
Bind(KEY_RIGHT, "+right");
Bind(KEY_LEFT, "+left");
Bind(KEY_UP, "+jump");
Bind(KEY_DOWN, "+hook");
Bind(KEY_PAGEUP, "+prevweapon");
Bind(KEY_PAGEDOWN, "+nextweapon");
Bind(KEY_F5, "spectate_previous");
Bind(KEY_F6, "spectate_next");
#else
Bind(KEY_RETURN, "+show_chat; chat all");
Bind(KEY_RIGHT, "spectate_next");
Bind(KEY_LEFT, "spectate_previous");
Bind(KEY_RSHIFT, "+spectate");
#endif
Bind(KEY_1, "+weapon1");
Bind(KEY_2, "+weapon2");
Bind(KEY_3, "+weapon3");
Bind(KEY_4, "+weapon4");
Bind(KEY_5, "+weapon5");
Bind(KEY_MOUSE_WHEEL_UP, "+prevweapon");
Bind(KEY_MOUSE_WHEEL_DOWN, "+nextweapon");
Bind(KEY_T, "+show_chat; chat all");
Bind(KEY_Y, "+show_chat; chat team");
Bind(KEY_U, "+show_chat");
Bind(KEY_I, "+show_chat; chat all /c ");
Bind(KEY_F3, "vote yes");
Bind(KEY_F4, "vote no");
Bind(KEY_K, "kill");
Bind(KEY_Q, "say /pause");
Bind(KEY_P, "say /pause");
// DDRace
if(g_Config.m_ClDDRaceBinds)
SetDDRaceBinds(false);
}
void CBinds::OnConsoleInit()
{
// bindings
IConfig *pConfig = Kernel()->RequestInterface<IConfig>();
if(pConfig)
pConfig->RegisterCallback(ConfigSaveCallback, this);
Console()->Register("bind", "s[key] r[command]", CFGFLAG_CLIENT, ConBind, this, "Bind key to execute the command");
Console()->Register("dump_binds", "?s[key]", CFGFLAG_CLIENT, ConDumpBinds, this, "Print command executed by this keybindind or all binds");
Console()->Register("unbind", "s[key]", CFGFLAG_CLIENT, ConUnbind, this, "Unbind key");
Console()->Register("unbindall", "", CFGFLAG_CLIENT, ConUnbindAll, this, "Unbind all keys");
// default bindings
SetDefaults();
}
void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData)
{
CBinds *pBinds = (CBinds *)pUserData;
const char *pKeyName = pResult->GetString(0);
int id = pBinds->GetKeyID(pKeyName);
if(!id)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "key %s not found", pKeyName);
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf);
return;
}
pBinds->Bind(id, pResult->GetString(1));
}
void CBinds::ConDumpBinds(IConsole::IResult *pResult, void *pUserData)
{
CBinds *pBinds = (CBinds *)pUserData;
if(pResult->NumArguments() == 1)
{
char aBuf[256];
const char *pKeyName = pResult->GetString(0);
int id = pBinds->GetKeyID(pKeyName);
if (!id)
{
str_format(aBuf, sizeof(aBuf), "key '%s' not found", pKeyName);
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf);
}
else
{
if (!pBinds->m_apKeyBindings[id])
str_format(aBuf, sizeof(aBuf), "%s (%d) is not bound", pKeyName, id);
else
str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pKeyName, id, pBinds->m_apKeyBindings[id]);
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf);
}
}
else if(pResult->NumArguments() == 0)
{
char aBuf[1024];
for(int i = 0; i < KEY_LAST; i++)
{
if(!pBinds->m_apKeyBindings[i])
continue;
str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pBinds->Input()->KeyName(i), i, pBinds->m_apKeyBindings[i]);
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf);
}
}
}
void CBinds::ConUnbind(IConsole::IResult *pResult, void *pUserData)
{
CBinds *pBinds = (CBinds *)pUserData;
const char *pKeyName = pResult->GetString(0);
int id = pBinds->GetKeyID(pKeyName);
if(!id)
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "key %s not found", pKeyName);
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf);
return;
}
pBinds->Bind(id, "");
}
void CBinds::ConUnbindAll(IConsole::IResult *pResult, void *pUserData)
{
CBinds *pBinds = (CBinds *)pUserData;
pBinds->UnbindAll();
}
int CBinds::GetKeyID(const char *pKeyName)
{
// check for numeric
if(pKeyName[0] == '&')
{
int i = str_toint(pKeyName+1);
if(i > 0 && i < KEY_LAST)
return i; // numeric
}
// search for key
for(int i = 0; i < KEY_LAST; i++)
{
if(str_comp(pKeyName, Input()->KeyName(i)) == 0)
return i;
}
return 0;
}
void CBinds::ConfigSaveCallback(IConfig *pConfig, void *pUserData)
{
CBinds *pSelf = (CBinds *)pUserData;
char aBuffer[256];
char *pEnd = aBuffer+sizeof(aBuffer);
pConfig->WriteLine("unbindall");
for(int i = 0; i < KEY_LAST; i++)
{
if(!pSelf->m_apKeyBindings[i])
continue;
str_format(aBuffer, sizeof(aBuffer), "bind %s \"", pSelf->Input()->KeyName(i));
// process the string. we need to escape some characters
char *pDst = aBuffer + str_length(aBuffer);
str_escape(&pDst, pSelf->m_apKeyBindings[i], pEnd);
str_append(aBuffer, "\"", sizeof(aBuffer));
pConfig->WriteLine(aBuffer);
}
}
// DDRace
void CBinds::SetDDRaceBinds(bool FreeOnly)
{
Bind(KEY_KP_PLUS, "zoom+", FreeOnly);
Bind(KEY_KP_MINUS, "zoom-", FreeOnly);
Bind(KEY_KP_MULTIPLY, "zoom", FreeOnly);
Bind(KEY_PAUSE, "say /pause", FreeOnly);
Bind(KEY_UP, "+jump", FreeOnly);
Bind(KEY_LEFT, "+left", FreeOnly);
Bind(KEY_RIGHT, "+right", FreeOnly);
Bind(KEY_LEFTBRACKET, "+prevweapon", FreeOnly);
Bind(KEY_RIGHTBRACKET, "+nextweapon", FreeOnly);
Bind(KEY_C, "say /rank", FreeOnly);
Bind(KEY_V, "say /info", FreeOnly);
Bind(KEY_B, "say /top5", FreeOnly);
Bind(KEY_X, "emote 14", FreeOnly);
Bind(KEY_H, "emote 2", FreeOnly);
Bind(KEY_M, "emote 5", FreeOnly);
Bind(KEY_S, "+showhookcoll", FreeOnly);
Bind(KEY_X, "toggle cl_dummy 0 1", FreeOnly);
#if !defined(__ANDROID__)
Bind(KEY_PAGEDOWN, "toggle cl_show_quads 0 1", FreeOnly);
Bind(KEY_PAGEUP, "toggle cl_overlay_entities 0 100", FreeOnly);
#endif
Bind(KEY_KP_0, "say /emote normal 999999", FreeOnly);
Bind(KEY_KP_1, "say /emote happy 999999", FreeOnly);
Bind(KEY_KP_2, "say /emote angry 999999", FreeOnly);
Bind(KEY_KP_3, "say /emote pain 999999", FreeOnly);
Bind(KEY_KP_4, "say /emote surprise 999999", FreeOnly);
Bind(KEY_KP_5, "say /emote blink 999999", FreeOnly);
Bind(KEY_MOUSE_3, "+spectate", FreeOnly);
Bind(KEY_MINUS, "spectate_previous", FreeOnly);
Bind(KEY_EQUALS, "spectate_next", FreeOnly);
g_Config.m_ClDDRaceBindsSet = 1;
}