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:
Dennis Felsing 2024-08-04 20:44:40 +00:00 committed by GitHub
commit 8d609b9202
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 166 additions and 141 deletions

View file

@ -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);

View file

@ -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]; }

View file

@ -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

View file

@ -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) 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())
{ {
Console()->ExecuteLineStroked(1, m_aapKeyBindings[Mask][Event.m_Key]); const auto &&OnPress = [&](int Mask) {
pKey = m_aapKeyBindings[Mask][Event.m_Key]; const char *pBind = m_aapKeyBindings[Mask][Event.m_Key];
} if(g_Config.m_ClSubTickAiming)
// Have to check for nullptr again because the previous execute can unbind itself {
if(Event.m_Flags & IInput::FLAG_RELEASE && m_aapKeyBindings[Mask][Event.m_Key]) if(str_comp("+fire", pBind) == 0 || str_comp("+hook", pBind) == 0)
Console()->ExecuteLineStroked(0, m_aapKeyBindings[Mask][Event.m_Key]); {
ret = true; m_MouseOnAction = true;
} }
}
Console()->ExecuteLineStroked(1, pBind);
m_vActiveBinds.emplace_back(Event.m_Key, Mask);
};
if(m_aapKeyBindings[0][Event.m_Key] && !ret) if(m_aapKeyBindings[ModifierMask][Event.m_Key])
{ {
// 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 OnPress(ModifierMask);
if(Event.m_Flags & IInput::FLAG_PRESS && Mask != ((1 << MODIFIER_CTRL) | (1 << MODIFIER_SHIFT)) && Mask != ((1 << MODIFIER_GUI) | (1 << MODIFIER_SHIFT))) Handled = true;
{ }
Console()->ExecuteLineStroked(1, m_aapKeyBindings[0][Event.m_Key]); else if(m_aapKeyBindings[MODIFIER_NONE][Event.m_Key] &&
pKey = m_aapKeyBindings[Mask][Event.m_Key]; ModifierMask != ((1 << MODIFIER_CTRL) | (1 << MODIFIER_SHIFT)) &&
} ModifierMask != ((1 << MODIFIER_GUI) | (1 << MODIFIER_SHIFT)))
// 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]) OnPress(MODIFIER_NONE);
Console()->ExecuteLineStroked(0, m_aapKeyBindings[0][Event.m_Key]); Handled = true;
ret = true; }
}
if(g_Config.m_ClSubTickAiming && pKey)
{
if(str_comp("+fire", pKey) == 0 || str_comp("+hook", pKey) == 0)
{
m_MouseOnAction = true;
} }
} }
return ret; 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);

View file

@ -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