mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-09 17:48:19 +00:00
Merge pull request #8685 from Robyt3/Client-Binds-Fixes
Support composite binds with `+` commands, fix handling of composite binds with F1-F24 keys, fix incorrect key names with multiple modifiers, refactoring
This commit is contained in:
commit
8d609b9202
|
@ -367,6 +367,26 @@ bool CInput::KeyState(int Key) const
|
||||||
return m_aInputState[Key];
|
return m_aInputState[Key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CInput::FindKeyByName(const char *pKeyName) const
|
||||||
|
{
|
||||||
|
// check for numeric
|
||||||
|
if(pKeyName[0] == '&')
|
||||||
|
{
|
||||||
|
int Key = str_toint(pKeyName + 1);
|
||||||
|
if(Key > KEY_FIRST && Key < KEY_LAST)
|
||||||
|
return Key; // numeric
|
||||||
|
}
|
||||||
|
|
||||||
|
// search for key
|
||||||
|
for(int Key = KEY_FIRST; Key < KEY_LAST; Key++)
|
||||||
|
{
|
||||||
|
if(str_comp_nocase(pKeyName, KeyName(Key)) == 0)
|
||||||
|
return Key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return KEY_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
void CInput::UpdateMouseState()
|
void CInput::UpdateMouseState()
|
||||||
{
|
{
|
||||||
const int MouseState = SDL_GetMouseState(nullptr, nullptr);
|
const int MouseState = SDL_GetMouseState(nullptr, nullptr);
|
||||||
|
|
|
@ -136,6 +136,7 @@ public:
|
||||||
bool AltIsPressed() const override { return KeyState(KEY_LALT) || KeyState(KEY_RALT); }
|
bool AltIsPressed() const override { return KeyState(KEY_LALT) || KeyState(KEY_RALT); }
|
||||||
bool KeyIsPressed(int Key) const override { return KeyState(Key); }
|
bool KeyIsPressed(int Key) const override { return KeyState(Key); }
|
||||||
bool KeyPress(int Key, bool CheckCounter) const override { return CheckCounter ? (m_aInputCount[Key] == m_InputCounter) : m_aInputCount[Key]; }
|
bool KeyPress(int Key, bool CheckCounter) const override { return CheckCounter ? (m_aInputCount[Key] == m_InputCounter) : m_aInputCount[Key]; }
|
||||||
|
int FindKeyByName(const char *pKeyName) const override;
|
||||||
|
|
||||||
size_t NumJoysticks() const override { return m_vJoysticks.size(); }
|
size_t NumJoysticks() const override { return m_vJoysticks.size(); }
|
||||||
CJoystick *GetJoystick(size_t Index) override { return &m_vJoysticks[Index]; }
|
CJoystick *GetJoystick(size_t Index) override { return &m_vJoysticks[Index]; }
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
virtual bool KeyIsPressed(int Key) const = 0;
|
virtual bool KeyIsPressed(int Key) const = 0;
|
||||||
virtual bool KeyPress(int Key, bool CheckCounter = false) const = 0;
|
virtual bool KeyPress(int Key, bool CheckCounter = false) const = 0;
|
||||||
const char *KeyName(int Key) const { return (Key >= 0 && Key < g_MaxKeys) ? g_aaKeyStrings[Key] : g_aaKeyStrings[0]; }
|
const char *KeyName(int Key) const { return (Key >= 0 && Key < g_MaxKeys) ? g_aaKeyStrings[Key] : g_aaKeyStrings[0]; }
|
||||||
|
virtual int FindKeyByName(const char *pKeyName) const = 0;
|
||||||
|
|
||||||
// joystick
|
// joystick
|
||||||
class IJoystick
|
class IJoystick
|
||||||
|
|
|
@ -11,26 +11,15 @@ static const ColorRGBA gs_BindPrintColor{1.0f, 1.0f, 0.8f, 1.0f};
|
||||||
|
|
||||||
bool CBinds::CBindsSpecial::OnInput(const IInput::CEvent &Event)
|
bool CBinds::CBindsSpecial::OnInput(const IInput::CEvent &Event)
|
||||||
{
|
{
|
||||||
|
if((Event.m_Flags & (IInput::FLAG_PRESS | IInput::FLAG_RELEASE)) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
// only handle F and composed F binds
|
// only handle F and composed F binds
|
||||||
if(((Event.m_Key >= KEY_F1 && Event.m_Key <= KEY_F12) || (Event.m_Key >= KEY_F13 && Event.m_Key <= KEY_F24)) && (Event.m_Key != KEY_F5 || !m_pClient->m_Menus.IsActive()))
|
// do not handle F5 bind while menu is active
|
||||||
|
if(((Event.m_Key >= KEY_F1 && Event.m_Key <= KEY_F12) || (Event.m_Key >= KEY_F13 && Event.m_Key <= KEY_F24)) &&
|
||||||
|
(Event.m_Key != KEY_F5 || !m_pClient->m_Menus.IsActive()))
|
||||||
{
|
{
|
||||||
int Mask = CBinds::GetModifierMask(Input());
|
return m_pBinds->OnInput(Event);
|
||||||
|
|
||||||
// Look for a composed bind
|
|
||||||
bool ret = false;
|
|
||||||
if(m_pBinds->m_aapKeyBindings[Mask][Event.m_Key])
|
|
||||||
{
|
|
||||||
m_pBinds->GetConsole()->ExecuteLineStroked(Event.m_Flags & IInput::FLAG_PRESS, m_pBinds->m_aapKeyBindings[Mask][Event.m_Key]);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
// Look for a non composed bind
|
|
||||||
if(!ret && m_pBinds->m_aapKeyBindings[0][Event.m_Key])
|
|
||||||
{
|
|
||||||
m_pBinds->GetConsole()->ExecuteLineStroked(Event.m_Flags & IInput::FLAG_PRESS, m_pBinds->m_aapKeyBindings[0][Event.m_Key]);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -44,25 +33,19 @@ CBinds::CBinds()
|
||||||
|
|
||||||
CBinds::~CBinds()
|
CBinds::~CBinds()
|
||||||
{
|
{
|
||||||
for(int i = 0; i < KEY_LAST; i++)
|
UnbindAll();
|
||||||
for(auto &apKeyBinding : m_aapKeyBindings)
|
|
||||||
free(apKeyBinding[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBinds::Bind(int KeyId, const char *pStr, bool FreeOnly, int ModifierCombination)
|
void CBinds::Bind(int KeyId, const char *pStr, bool FreeOnly, int ModifierCombination)
|
||||||
{
|
{
|
||||||
if(KeyId < 0 || KeyId >= KEY_LAST)
|
dbg_assert(KeyId >= KEY_FIRST && KeyId < KEY_LAST, "KeyId invalid");
|
||||||
return;
|
dbg_assert(ModifierCombination >= MODIFIER_NONE && ModifierCombination < MODIFIER_COMBINATION_COUNT, "ModifierCombination invalid");
|
||||||
|
|
||||||
if(FreeOnly && Get(KeyId, ModifierCombination)[0])
|
if(FreeOnly && Get(KeyId, ModifierCombination)[0])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
free(m_aapKeyBindings[ModifierCombination][KeyId]);
|
free(m_aapKeyBindings[ModifierCombination][KeyId]);
|
||||||
m_aapKeyBindings[ModifierCombination][KeyId] = 0;
|
m_aapKeyBindings[ModifierCombination][KeyId] = nullptr;
|
||||||
|
|
||||||
// skip modifiers for +xxx binds
|
|
||||||
if(pStr[0] == '+')
|
|
||||||
ModifierCombination = 0;
|
|
||||||
|
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
if(!pStr[0])
|
if(!pStr[0])
|
||||||
|
@ -120,59 +103,94 @@ int CBinds::GetModifierMaskOfKey(int Key)
|
||||||
case KEY_RGUI:
|
case KEY_RGUI:
|
||||||
return 1 << CBinds::MODIFIER_GUI;
|
return 1 << CBinds::MODIFIER_GUI;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return CBinds::MODIFIER_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CBinds::OnInput(const IInput::CEvent &Event)
|
bool CBinds::OnInput(const IInput::CEvent &Event)
|
||||||
{
|
{
|
||||||
// don't handle invalid events
|
if((Event.m_Flags & (IInput::FLAG_PRESS | IInput::FLAG_RELEASE)) == 0)
|
||||||
if(Event.m_Key <= KEY_FIRST || Event.m_Key >= KEY_LAST)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int Mask = GetModifierMask(Input());
|
const int KeyModifierMask = GetModifierMaskOfKey(Event.m_Key);
|
||||||
int KeyModifierMask = GetModifierMaskOfKey(Event.m_Key);
|
const int ModifierMask = GetModifierMask(Input()) & ~KeyModifierMask;
|
||||||
Mask &= ~KeyModifierMask;
|
|
||||||
|
|
||||||
bool ret = false;
|
bool Handled = false;
|
||||||
const char *pKey = nullptr;
|
|
||||||
|
|
||||||
if(m_aapKeyBindings[Mask][Event.m_Key])
|
|
||||||
{
|
|
||||||
if(Event.m_Flags & IInput::FLAG_PRESS)
|
if(Event.m_Flags & IInput::FLAG_PRESS)
|
||||||
{
|
{
|
||||||
Console()->ExecuteLineStroked(1, m_aapKeyBindings[Mask][Event.m_Key]);
|
auto ActiveBind = std::find_if(m_vActiveBinds.begin(), m_vActiveBinds.end(), [&](const CBindSlot &Bind) {
|
||||||
pKey = m_aapKeyBindings[Mask][Event.m_Key];
|
return Event.m_Key == Bind.m_Key;
|
||||||
}
|
});
|
||||||
// Have to check for nullptr again because the previous execute can unbind itself
|
if(ActiveBind == m_vActiveBinds.end())
|
||||||
if(Event.m_Flags & IInput::FLAG_RELEASE && m_aapKeyBindings[Mask][Event.m_Key])
|
|
||||||
Console()->ExecuteLineStroked(0, m_aapKeyBindings[Mask][Event.m_Key]);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_aapKeyBindings[0][Event.m_Key] && !ret)
|
|
||||||
{
|
{
|
||||||
// When ctrl+shift are pressed (ctrl+shift binds and also the hard-coded ctrl+shift+d, ctrl+shift+g, ctrl+shift+e), ignore other +xxx binds
|
const auto &&OnPress = [&](int Mask) {
|
||||||
if(Event.m_Flags & IInput::FLAG_PRESS && Mask != ((1 << MODIFIER_CTRL) | (1 << MODIFIER_SHIFT)) && Mask != ((1 << MODIFIER_GUI) | (1 << MODIFIER_SHIFT)))
|
const char *pBind = m_aapKeyBindings[Mask][Event.m_Key];
|
||||||
|
if(g_Config.m_ClSubTickAiming)
|
||||||
{
|
{
|
||||||
Console()->ExecuteLineStroked(1, m_aapKeyBindings[0][Event.m_Key]);
|
if(str_comp("+fire", pBind) == 0 || str_comp("+hook", pBind) == 0)
|
||||||
pKey = m_aapKeyBindings[Mask][Event.m_Key];
|
|
||||||
}
|
|
||||||
// Have to check for nullptr again because the previous execute can unbind itself
|
|
||||||
if(Event.m_Flags & IInput::FLAG_RELEASE && m_aapKeyBindings[0][Event.m_Key])
|
|
||||||
Console()->ExecuteLineStroked(0, m_aapKeyBindings[0][Event.m_Key]);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(g_Config.m_ClSubTickAiming && pKey)
|
|
||||||
{
|
|
||||||
if(str_comp("+fire", pKey) == 0 || str_comp("+hook", pKey) == 0)
|
|
||||||
{
|
{
|
||||||
m_MouseOnAction = true;
|
m_MouseOnAction = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Console()->ExecuteLineStroked(1, pBind);
|
||||||
|
m_vActiveBinds.emplace_back(Event.m_Key, Mask);
|
||||||
|
};
|
||||||
|
|
||||||
return ret;
|
if(m_aapKeyBindings[ModifierMask][Event.m_Key])
|
||||||
|
{
|
||||||
|
OnPress(ModifierMask);
|
||||||
|
Handled = true;
|
||||||
|
}
|
||||||
|
else if(m_aapKeyBindings[MODIFIER_NONE][Event.m_Key] &&
|
||||||
|
ModifierMask != ((1 << MODIFIER_CTRL) | (1 << MODIFIER_SHIFT)) &&
|
||||||
|
ModifierMask != ((1 << MODIFIER_GUI) | (1 << MODIFIER_SHIFT)))
|
||||||
|
{
|
||||||
|
OnPress(MODIFIER_NONE);
|
||||||
|
Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Event.m_Flags & IInput::FLAG_RELEASE)
|
||||||
|
{
|
||||||
|
// Release active bind that uses this primary key
|
||||||
|
auto ActiveBind = std::find_if(m_vActiveBinds.begin(), m_vActiveBinds.end(), [&](const CBindSlot &Bind) {
|
||||||
|
return Event.m_Key == Bind.m_Key;
|
||||||
|
});
|
||||||
|
if(ActiveBind != m_vActiveBinds.end())
|
||||||
|
{
|
||||||
|
// Have to check for nullptr again because the previous execute can unbind itself
|
||||||
|
if(m_aapKeyBindings[ActiveBind->m_ModifierMask][ActiveBind->m_Key])
|
||||||
|
{
|
||||||
|
Console()->ExecuteLineStroked(0, m_aapKeyBindings[ActiveBind->m_ModifierMask][ActiveBind->m_Key]);
|
||||||
|
}
|
||||||
|
m_vActiveBinds.erase(ActiveBind);
|
||||||
|
Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release all active binds that use this modifier key
|
||||||
|
if(KeyModifierMask != MODIFIER_NONE)
|
||||||
|
{
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
auto ActiveModifierBind = std::find_if(m_vActiveBinds.begin(), m_vActiveBinds.end(), [&](const CBindSlot &Bind) {
|
||||||
|
return (Bind.m_ModifierMask & KeyModifierMask) != 0;
|
||||||
|
});
|
||||||
|
if(ActiveModifierBind == m_vActiveBinds.end())
|
||||||
|
break;
|
||||||
|
// Have to check for nullptr again because the previous execute can unbind itself
|
||||||
|
if(m_aapKeyBindings[ActiveModifierBind->m_ModifierMask][ActiveModifierBind->m_Key])
|
||||||
|
{
|
||||||
|
Console()->ExecuteLineStroked(0, m_aapKeyBindings[ActiveModifierBind->m_ModifierMask][ActiveModifierBind->m_Key]);
|
||||||
|
}
|
||||||
|
m_vActiveBinds.erase(ActiveModifierBind);
|
||||||
|
Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBinds::UnbindAll()
|
void CBinds::UnbindAll()
|
||||||
|
@ -182,35 +200,32 @@ void CBinds::UnbindAll()
|
||||||
for(auto &pKeyBinding : apKeyBinding)
|
for(auto &pKeyBinding : apKeyBinding)
|
||||||
{
|
{
|
||||||
free(pKeyBinding);
|
free(pKeyBinding);
|
||||||
pKeyBinding = 0;
|
pKeyBinding = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CBinds::Get(int KeyId, int ModifierCombination)
|
const char *CBinds::Get(int KeyId, int ModifierCombination)
|
||||||
{
|
{
|
||||||
if(KeyId > 0 && KeyId < KEY_LAST && m_aapKeyBindings[ModifierCombination][KeyId])
|
dbg_assert(KeyId >= KEY_FIRST && KeyId < KEY_LAST, "KeyId invalid");
|
||||||
return m_aapKeyBindings[ModifierCombination][KeyId];
|
dbg_assert(ModifierCombination >= MODIFIER_NONE && ModifierCombination < MODIFIER_COMBINATION_COUNT, "ModifierCombination invalid");
|
||||||
return "";
|
return m_aapKeyBindings[ModifierCombination][KeyId] ? m_aapKeyBindings[ModifierCombination][KeyId] : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBinds::GetKey(const char *pBindStr, char *pBuf, size_t BufSize)
|
void CBinds::GetKey(const char *pBindStr, char *pBuf, size_t BufSize)
|
||||||
{
|
{
|
||||||
pBuf[0] = 0;
|
pBuf[0] = '\0';
|
||||||
for(int Mod = 0; Mod < MODIFIER_COMBINATION_COUNT; Mod++)
|
for(int Modifier = MODIFIER_NONE; Modifier < MODIFIER_COMBINATION_COUNT; Modifier++)
|
||||||
{
|
{
|
||||||
for(int KeyId = 0; KeyId < KEY_LAST; KeyId++)
|
for(int KeyId = KEY_FIRST; KeyId < KEY_LAST; KeyId++)
|
||||||
{
|
{
|
||||||
const char *pBind = Get(KeyId, Mod);
|
const char *pBind = Get(KeyId, Modifier);
|
||||||
if(!pBind[0])
|
if(!pBind[0])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(str_comp(pBind, pBindStr) == 0)
|
if(str_comp(pBind, pBindStr) == 0)
|
||||||
{
|
{
|
||||||
if(Mod)
|
str_format(pBuf, BufSize, "%s%s", GetKeyBindModifiersName(Modifier), Input()->KeyName(KeyId));
|
||||||
str_format(pBuf, BufSize, "%s+%s", GetModifierName(Mod), Input()->KeyName(KeyId));
|
|
||||||
else
|
|
||||||
str_copy(pBuf, Input()->KeyName(KeyId), BufSize);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,8 +234,8 @@ void CBinds::GetKey(const char *pBindStr, char *pBuf, size_t BufSize)
|
||||||
|
|
||||||
void CBinds::SetDefaults()
|
void CBinds::SetDefaults()
|
||||||
{
|
{
|
||||||
// set default key bindings
|
|
||||||
UnbindAll();
|
UnbindAll();
|
||||||
|
|
||||||
Bind(KEY_F1, "toggle_local_console");
|
Bind(KEY_F1, "toggle_local_console");
|
||||||
Bind(KEY_F2, "toggle_remote_console");
|
Bind(KEY_F2, "toggle_remote_console");
|
||||||
Bind(KEY_TAB, "+scoreboard");
|
Bind(KEY_TAB, "+scoreboard");
|
||||||
|
@ -260,7 +275,6 @@ void CBinds::SetDefaults()
|
||||||
Bind(KEY_Q, "say /pause");
|
Bind(KEY_Q, "say /pause");
|
||||||
Bind(KEY_P, "say /pause");
|
Bind(KEY_P, "say /pause");
|
||||||
|
|
||||||
// DDRace
|
|
||||||
g_Config.m_ClDDRaceBindsSet = 0;
|
g_Config.m_ClDDRaceBindsSet = 0;
|
||||||
SetDDRaceBinds(false);
|
SetDDRaceBinds(false);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +288,6 @@ void CBinds::OnConsoleInit()
|
||||||
Console()->Register("unbind", "s[key]", CFGFLAG_CLIENT, ConUnbind, this, "Unbind key");
|
Console()->Register("unbind", "s[key]", CFGFLAG_CLIENT, ConUnbind, this, "Unbind key");
|
||||||
Console()->Register("unbindall", "", CFGFLAG_CLIENT, ConUnbindAll, this, "Unbind all keys");
|
Console()->Register("unbindall", "", CFGFLAG_CLIENT, ConUnbindAll, this, "Unbind all keys");
|
||||||
|
|
||||||
// default bindings
|
|
||||||
SetDefaults();
|
SetDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,10 +295,9 @@ void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
CBinds *pBinds = (CBinds *)pUserData;
|
CBinds *pBinds = (CBinds *)pUserData;
|
||||||
const char *pBindStr = pResult->GetString(0);
|
const char *pBindStr = pResult->GetString(0);
|
||||||
int Modifier;
|
const CBindSlot BindSlot = pBinds->GetBindSlot(pBindStr);
|
||||||
int KeyId = pBinds->GetBindSlot(pBindStr, &Modifier);
|
|
||||||
|
|
||||||
if(!KeyId)
|
if(!BindSlot.m_Key)
|
||||||
{
|
{
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
str_format(aBuf, sizeof(aBuf), "key %s not found", pBindStr);
|
str_format(aBuf, sizeof(aBuf), "key %s not found", pBindStr);
|
||||||
|
@ -298,16 +310,16 @@ void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData)
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
const char *pKeyName = pResult->GetString(0);
|
const char *pKeyName = pResult->GetString(0);
|
||||||
|
|
||||||
if(!pBinds->m_aapKeyBindings[Modifier][KeyId])
|
if(!pBinds->m_aapKeyBindings[BindSlot.m_ModifierMask][BindSlot.m_Key])
|
||||||
str_format(aBuf, sizeof(aBuf), "%s (%d) is not bound", pKeyName, KeyId);
|
str_format(aBuf, sizeof(aBuf), "%s (%d) is not bound", pKeyName, BindSlot.m_Key);
|
||||||
else
|
else
|
||||||
str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pKeyName, KeyId, pBinds->m_aapKeyBindings[Modifier][KeyId]);
|
str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pKeyName, BindSlot.m_Key, pBinds->m_aapKeyBindings[BindSlot.m_ModifierMask][BindSlot.m_Key]);
|
||||||
|
|
||||||
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pBinds->Bind(KeyId, pResult->GetString(1), false, Modifier);
|
pBinds->Bind(BindSlot.m_Key, pResult->GetString(1), false, BindSlot.m_ModifierMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBinds::ConBinds(IConsole::IResult *pResult, void *pUserData)
|
void CBinds::ConBinds(IConsole::IResult *pResult, void *pUserData)
|
||||||
|
@ -317,35 +329,33 @@ void CBinds::ConBinds(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
const char *pKeyName = pResult->GetString(0);
|
const char *pKeyName = pResult->GetString(0);
|
||||||
|
const CBindSlot BindSlot = pBinds->GetBindSlot(pKeyName);
|
||||||
int Modifier;
|
if(!BindSlot.m_Key)
|
||||||
int KeyId = pBinds->GetBindSlot(pKeyName, &Modifier);
|
|
||||||
if(!KeyId)
|
|
||||||
{
|
{
|
||||||
str_format(aBuf, sizeof(aBuf), "key '%s' not found", pKeyName);
|
str_format(aBuf, sizeof(aBuf), "key '%s' not found", pKeyName);
|
||||||
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(!pBinds->m_aapKeyBindings[Modifier][KeyId])
|
if(!pBinds->m_aapKeyBindings[BindSlot.m_ModifierMask][BindSlot.m_Key])
|
||||||
str_format(aBuf, sizeof(aBuf), "%s (%d) is not bound", pKeyName, KeyId);
|
str_format(aBuf, sizeof(aBuf), "%s (%d) is not bound", pKeyName, BindSlot.m_Key);
|
||||||
else
|
else
|
||||||
str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pKeyName, KeyId, pBinds->m_aapKeyBindings[Modifier][KeyId]);
|
str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pKeyName, BindSlot.m_Key, pBinds->m_aapKeyBindings[BindSlot.m_ModifierMask][BindSlot.m_Key]);
|
||||||
|
|
||||||
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(pResult->NumArguments() == 0)
|
else
|
||||||
{
|
{
|
||||||
char aBuf[1024];
|
char aBuf[1024];
|
||||||
for(int i = 0; i < MODIFIER_COMBINATION_COUNT; i++)
|
for(int Modifier = MODIFIER_NONE; Modifier < MODIFIER_COMBINATION_COUNT; Modifier++)
|
||||||
{
|
{
|
||||||
for(int j = 0; j < KEY_LAST; j++)
|
for(int Key = KEY_FIRST; Key < KEY_LAST; Key++)
|
||||||
{
|
{
|
||||||
if(!pBinds->m_aapKeyBindings[i][j])
|
if(!pBinds->m_aapKeyBindings[Modifier][Key])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
str_format(aBuf, sizeof(aBuf), "%s%s (%d) = %s", GetKeyBindModifiersName(i), pBinds->Input()->KeyName(j), j, pBinds->m_aapKeyBindings[i][j]);
|
str_format(aBuf, sizeof(aBuf), "%s%s (%d) = %s", GetKeyBindModifiersName(Modifier), pBinds->Input()->KeyName(Key), Key, pBinds->m_aapKeyBindings[Modifier][Key]);
|
||||||
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf, gs_BindPrintColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -356,10 +366,9 @@ void CBinds::ConUnbind(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
CBinds *pBinds = (CBinds *)pUserData;
|
CBinds *pBinds = (CBinds *)pUserData;
|
||||||
const char *pKeyName = pResult->GetString(0);
|
const char *pKeyName = pResult->GetString(0);
|
||||||
int Modifier;
|
const CBindSlot BindSlot = pBinds->GetBindSlot(pKeyName);
|
||||||
int KeyId = pBinds->GetBindSlot(pKeyName, &Modifier);
|
|
||||||
|
|
||||||
if(!KeyId)
|
if(!BindSlot.m_Key)
|
||||||
{
|
{
|
||||||
char aBuf[256];
|
char aBuf[256];
|
||||||
str_format(aBuf, sizeof(aBuf), "key %s not found", pKeyName);
|
str_format(aBuf, sizeof(aBuf), "key %s not found", pKeyName);
|
||||||
|
@ -367,7 +376,7 @@ void CBinds::ConUnbind(IConsole::IResult *pResult, void *pUserData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pBinds->Bind(KeyId, "", false, Modifier);
|
pBinds->Bind(BindSlot.m_Key, "", false, BindSlot.m_ModifierMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBinds::ConUnbindAll(IConsole::IResult *pResult, void *pUserData)
|
void CBinds::ConUnbindAll(IConsole::IResult *pResult, void *pUserData)
|
||||||
|
@ -376,51 +385,31 @@ void CBinds::ConUnbindAll(IConsole::IResult *pResult, void *pUserData)
|
||||||
pBinds->UnbindAll();
|
pBinds->UnbindAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CBinds::GetKeyId(const char *pKeyName)
|
CBinds::CBindSlot CBinds::GetBindSlot(const char *pBindString) const
|
||||||
{
|
{
|
||||||
// check for numeric
|
int ModifierMask = MODIFIER_NONE;
|
||||||
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_nocase(pKeyName, Input()->KeyName(i)) == 0)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CBinds::GetBindSlot(const char *pBindString, int *pModifierCombination)
|
|
||||||
{
|
|
||||||
*pModifierCombination = MODIFIER_NONE;
|
|
||||||
char aMod[32];
|
char aMod[32];
|
||||||
aMod[0] = '\0';
|
aMod[0] = '\0';
|
||||||
const char *pKey = str_next_token(pBindString, "+", aMod, sizeof(aMod));
|
const char *pKey = str_next_token(pBindString, "+", aMod, sizeof(aMod));
|
||||||
while(aMod[0] && *(pKey))
|
while(aMod[0] && *(pKey))
|
||||||
{
|
{
|
||||||
if(!str_comp_nocase(aMod, "shift"))
|
if(!str_comp_nocase(aMod, "shift"))
|
||||||
*pModifierCombination |= (1 << MODIFIER_SHIFT);
|
ModifierMask |= (1 << MODIFIER_SHIFT);
|
||||||
else if(!str_comp_nocase(aMod, "ctrl"))
|
else if(!str_comp_nocase(aMod, "ctrl"))
|
||||||
*pModifierCombination |= (1 << MODIFIER_CTRL);
|
ModifierMask |= (1 << MODIFIER_CTRL);
|
||||||
else if(!str_comp_nocase(aMod, "alt"))
|
else if(!str_comp_nocase(aMod, "alt"))
|
||||||
*pModifierCombination |= (1 << MODIFIER_ALT);
|
ModifierMask |= (1 << MODIFIER_ALT);
|
||||||
else if(!str_comp_nocase(aMod, "gui"))
|
else if(!str_comp_nocase(aMod, "gui"))
|
||||||
*pModifierCombination |= (1 << MODIFIER_GUI);
|
ModifierMask |= (1 << MODIFIER_GUI);
|
||||||
else
|
else
|
||||||
return 0;
|
return {KEY_UNKNOWN, MODIFIER_NONE};
|
||||||
|
|
||||||
if(str_find(pKey + 1, "+"))
|
if(str_find(pKey + 1, "+"))
|
||||||
pKey = str_next_token(pKey + 1, "+", aMod, sizeof(aMod));
|
pKey = str_next_token(pKey + 1, "+", aMod, sizeof(aMod));
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return GetKeyId(*pModifierCombination == MODIFIER_NONE ? aMod : pKey + 1);
|
return {Input()->FindKeyByName(ModifierMask == MODIFIER_NONE ? aMod : pKey + 1), ModifierMask};
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *CBinds::GetModifierName(int Modifier)
|
const char *CBinds::GetModifierName(int Modifier)
|
||||||
|
@ -461,22 +450,22 @@ void CBinds::ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData)
|
||||||
CBinds *pSelf = (CBinds *)pUserData;
|
CBinds *pSelf = (CBinds *)pUserData;
|
||||||
|
|
||||||
pConfigManager->WriteLine("unbindall");
|
pConfigManager->WriteLine("unbindall");
|
||||||
for(int i = 0; i < MODIFIER_COMBINATION_COUNT; i++)
|
for(int Modifier = MODIFIER_NONE; Modifier < MODIFIER_COMBINATION_COUNT; Modifier++)
|
||||||
{
|
{
|
||||||
for(int j = 0; j < KEY_LAST; j++)
|
for(int Key = KEY_FIRST; Key < KEY_LAST; Key++)
|
||||||
{
|
{
|
||||||
if(!pSelf->m_aapKeyBindings[i][j])
|
if(!pSelf->m_aapKeyBindings[Modifier][Key])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// worst case the str_escape can double the string length
|
// worst case the str_escape can double the string length
|
||||||
int Size = str_length(pSelf->m_aapKeyBindings[i][j]) * 2 + 30;
|
int Size = str_length(pSelf->m_aapKeyBindings[Modifier][Key]) * 2 + 30;
|
||||||
char *pBuffer = (char *)malloc(Size);
|
char *pBuffer = (char *)malloc(Size);
|
||||||
char *pEnd = pBuffer + Size;
|
char *pEnd = pBuffer + Size;
|
||||||
|
|
||||||
str_format(pBuffer, Size, "bind %s%s \"", GetKeyBindModifiersName(i), pSelf->Input()->KeyName(j));
|
str_format(pBuffer, Size, "bind %s%s \"", GetKeyBindModifiersName(Modifier), pSelf->Input()->KeyName(Key));
|
||||||
// process the string. we need to escape some characters
|
// process the string. we need to escape some characters
|
||||||
char *pDst = pBuffer + str_length(pBuffer);
|
char *pDst = pBuffer + str_length(pBuffer);
|
||||||
str_escape(&pDst, pSelf->m_aapKeyBindings[i][j], pEnd);
|
str_escape(&pDst, pSelf->m_aapKeyBindings[Modifier][Key], pEnd);
|
||||||
str_append(pBuffer, "\"", Size);
|
str_append(pBuffer, "\"", Size);
|
||||||
|
|
||||||
pConfigManager->WriteLine(pBuffer);
|
pConfigManager->WriteLine(pBuffer);
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
#include <game/client/component.h>
|
#include <game/client/component.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class IConfigManager;
|
class IConfigManager;
|
||||||
|
|
||||||
class CBinds : public CComponent
|
class CBinds : public CComponent
|
||||||
{
|
{
|
||||||
int GetKeyId(const char *pKeyName);
|
|
||||||
|
|
||||||
static void ConBind(IConsole::IResult *pResult, void *pUserData);
|
static void ConBind(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConBinds(IConsole::IResult *pResult, void *pUserData);
|
static void ConBinds(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConUnbind(IConsole::IResult *pResult, void *pUserData);
|
static void ConUnbind(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
@ -22,6 +22,20 @@ class CBinds : public CComponent
|
||||||
|
|
||||||
static void ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData);
|
static void ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData);
|
||||||
|
|
||||||
|
class CBindSlot
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int m_Key;
|
||||||
|
int m_ModifierMask;
|
||||||
|
|
||||||
|
CBindSlot(int Key, int ModifierMask) :
|
||||||
|
m_Key(Key),
|
||||||
|
m_ModifierMask(ModifierMask)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
CBindSlot GetBindSlot(const char *pBindString) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CBinds();
|
CBinds();
|
||||||
~CBinds();
|
~CBinds();
|
||||||
|
@ -55,7 +69,6 @@ public:
|
||||||
void UnbindAll();
|
void UnbindAll();
|
||||||
const char *Get(int KeyId, int ModifierCombination);
|
const char *Get(int KeyId, int ModifierCombination);
|
||||||
void GetKey(const char *pBindStr, char *pBuf, size_t BufSize);
|
void GetKey(const char *pBindStr, char *pBuf, size_t BufSize);
|
||||||
int GetBindSlot(const char *pBindString, int *pModifierCombination);
|
|
||||||
static int GetModifierMask(IInput *pInput);
|
static int GetModifierMask(IInput *pInput);
|
||||||
static int GetModifierMaskOfKey(int Key);
|
static int GetModifierMaskOfKey(int Key);
|
||||||
static const char *GetModifierName(int Modifier);
|
static const char *GetModifierName(int Modifier);
|
||||||
|
@ -70,5 +83,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *m_aapKeyBindings[MODIFIER_COMBINATION_COUNT][KEY_LAST];
|
char *m_aapKeyBindings[MODIFIER_COMBINATION_COUNT][KEY_LAST];
|
||||||
|
std::vector<CBindSlot> m_vActiveBinds;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue