diff --git a/src/game/client/components/binds.cpp b/src/game/client/components/binds.cpp index 8f6d78802..39b827f4f 100644 --- a/src/game/client/components/binds.cpp +++ b/src/game/client/components/binds.cpp @@ -25,82 +25,119 @@ const char CBinds::s_aaDefaultBindValues[][32] = { "ready_change", }; -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_aaKeyBindings[Event.m_Key][0] != 0) - { - int Stroke = 0; - if(Event.m_Flags&IInput::FLAG_PRESS) - Stroke = 1; - - m_pBinds->GetConsole()->ExecuteLineStroked(Stroke, m_pBinds->m_aaKeyBindings[Event.m_Key]); - return true; - } - - return false; -} CBinds::CBinds() { - mem_zero(m_aaKeyBindings, sizeof(m_aaKeyBindings)); + mem_zero(m_aaaKeyBindings, sizeof(m_aaaKeyBindings)); m_SpecialBinds.m_pBinds = this; } -void CBinds::Bind(int KeyID, const char *pStr) +void CBinds::Bind(int KeyID, int Modifier, const char *pStr) { if(KeyID < 0 || KeyID >= KEY_LAST) return; - str_copy(m_aaKeyBindings[KeyID], pStr, sizeof(m_aaKeyBindings[KeyID])); + str_copy(m_aaaKeyBindings[KeyID][Modifier], pStr, sizeof(m_aaaKeyBindings[KeyID][Modifier])); char aBuf[256]; - if(!m_aaKeyBindings[KeyID][0]) - str_format(aBuf, sizeof(aBuf), "unbound %s (%d)", Input()->KeyName(KeyID), KeyID); + if(!m_aaaKeyBindings[KeyID][Modifier][0]) + str_format(aBuf, sizeof(aBuf), "unbound %s%s (%d)", GetModifierName(Modifier),Input()->KeyName(KeyID), KeyID); else - str_format(aBuf, sizeof(aBuf), "bound %s (%d) = %s", Input()->KeyName(KeyID), KeyID, m_aaKeyBindings[KeyID]); + str_format(aBuf, sizeof(aBuf), "bound %s%s (%d) = %s", GetModifierName(Modifier),Input()->KeyName(KeyID), KeyID, m_aaaKeyBindings[KeyID][Modifier]); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf); } +bool CBinds::CBindsSpecial::OnInput(IInput::CEvent Event) +{ + int Mask = 0; + // since we only handle one modifier, when doing ctrl+q and shift+q, execute both + Mask |= Input()->KeyIsPressed(KEY_LSHIFT) << MODIFIER_SHIFT; + Mask |= Input()->KeyIsPressed(KEY_RSHIFT) << MODIFIER_SHIFT; + Mask |= Input()->KeyIsPressed(KEY_LCTRL) << MODIFIER_CTRL; + Mask |= Input()->KeyIsPressed(KEY_RCTRL) << MODIFIER_CTRL; + Mask |= Input()->KeyIsPressed(KEY_LALT) << MODIFIER_ALT; + if(Mask == 0) + Mask = 1; // if no modifier, flag with MODIFIER_NONE + bool rtn = false; + + // don't handle invalid events and keys that aren'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))) + return false; + + for(int m = 0; m < MODIFIER_COUNT; m++) + { + if((Mask&(1 << m)) && m_pBinds->m_aaaKeyBindings[Event.m_Key][m][0] != 0) + { + int Stroke = 0; + if(Event.m_Flags&IInput::FLAG_PRESS) + Stroke = 1; + + m_pBinds->GetConsole()->ExecuteLineStroked(Stroke, m_pBinds->m_aaaKeyBindings[Event.m_Key][m]); + rtn = true; + } + } + return rtn; +} 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_aaKeyBindings[e.m_Key][0] == 0) + int Mask = 0; + // since we only handle one modifier, when doing ctrl+q and shift+q, execute both + Mask |= Input()->KeyIsPressed(KEY_LSHIFT) << MODIFIER_SHIFT; + Mask |= Input()->KeyIsPressed(KEY_RSHIFT) << MODIFIER_SHIFT; + Mask |= Input()->KeyIsPressed(KEY_LCTRL) << MODIFIER_CTRL; + Mask |= Input()->KeyIsPressed(KEY_RCTRL) << MODIFIER_CTRL; + Mask |= Input()->KeyIsPressed(KEY_LALT) << MODIFIER_ALT; + if(Mask == 0) + Mask = 1; // if no modifier, flag with MODIFIER_NONE + + // don't handle invalid events and keys that aren't set to anything + if(e.m_Key <= 0 || e.m_Key >= KEY_LAST) return false; - if(e.m_Flags&IInput::FLAG_PRESS) - Console()->ExecuteLineStroked(1, m_aaKeyBindings[e.m_Key]); - if(e.m_Flags&IInput::FLAG_RELEASE) - Console()->ExecuteLineStroked(0, m_aaKeyBindings[e.m_Key]); - return true; + bool rtn = false; + for(int m = 0; m < MODIFIER_COUNT; m++) + { + if((Mask&(1 << m)) && m_aaaKeyBindings[e.m_Key][m][0] == 0) + continue; + + if(e.m_Flags&IInput::FLAG_PRESS) + Console()->ExecuteLineStroked(1, m_aaaKeyBindings[e.m_Key][m]); + if(e.m_Flags&IInput::FLAG_RELEASE) + Console()->ExecuteLineStroked(0, m_aaaKeyBindings[e.m_Key][m]); + rtn = true; + } + return rtn; } void CBinds::UnbindAll() { for(int i = 0; i < KEY_LAST; i++) - m_aaKeyBindings[i][0] = 0; + for(int m = 0; m < MODIFIER_COUNT; m++) + m_aaaKeyBindings[i][m][0] = 0; } -const char *CBinds::Get(int KeyID) +const char *CBinds::Get(int KeyID, int Modifier) { if(KeyID > 0 && KeyID < KEY_LAST) - return m_aaKeyBindings[KeyID]; + return m_aaaKeyBindings[KeyID][Modifier]; return ""; } -const char *CBinds::GetKey(const char *pBindStr) +void CBinds::GetKey(const char *pBindStr, char aBuf[64]) { - for(int KeyId = 0; KeyId < KEY_LAST; KeyId++) + aBuf[0] = 0; + for(int KeyID = 0; KeyID < KEY_LAST; KeyID++) { - const char *pBind = Get(KeyId); - if(!pBind[0]) - continue; + for(int m = 0; m < MODIFIER_COUNT; m++) + { + const char *pBind = Get(KeyID, m); + if(!pBind[0]) + continue; - if(str_comp(pBind, pBindStr) == 0) - return Input()->KeyName(KeyId); + if(str_comp(pBind, pBindStr) == 0) + str_format(aBuf, 64, "key %s%s not found", Input()->KeyName(KeyID), GetModifierName(m)); + } } - - return ""; } void CBinds::SetDefaults() @@ -110,7 +147,7 @@ void CBinds::SetDefaults() const int count = sizeof(s_aDefaultBindKeys)/sizeof(int); dbg_assert(count == sizeof(s_aaDefaultBindValues)/32, "the count of bind keys differs from that of bind values!"); for(int i = 0; i < count; i++) - Bind(s_aDefaultBindKeys[i], s_aaDefaultBindValues[i]); + Bind(s_aDefaultBindKeys[i], MODIFIER_NONE, s_aaDefaultBindValues[i]); } void CBinds::OnConsoleInit() @@ -133,7 +170,8 @@ void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData) { CBinds *pBinds = (CBinds *)pUserData; const char *pKeyName = pResult->GetString(0); - int id = pBinds->GetKeyID(pKeyName); + int modifier; + int id = pBinds->DecodeBindString(pKeyName, &modifier); if(!id) { @@ -143,7 +181,7 @@ void CBinds::ConBind(IConsole::IResult *pResult, void *pUserData) return; } - pBinds->Bind(id, pResult->GetString(1)); + pBinds->Bind(id, modifier, pResult->GetString(1)); } @@ -151,7 +189,8 @@ void CBinds::ConUnbind(IConsole::IResult *pResult, void *pUserData) { CBinds *pBinds = (CBinds *)pUserData; const char *pKeyName = pResult->GetString(0); - int id = pBinds->GetKeyID(pKeyName); + int modifier; + int id = pBinds->DecodeBindString(pKeyName, &modifier); if(!id) { @@ -161,7 +200,7 @@ void CBinds::ConUnbind(IConsole::IResult *pResult, void *pUserData) return; } - pBinds->Bind(id, ""); + pBinds->Bind(id, modifier, ""); } @@ -178,15 +217,40 @@ void CBinds::ConDumpBinds(IConsole::IResult *pResult, void *pUserData) char aBuf[1024]; for(int i = 0; i < KEY_LAST; i++) { - if(pBinds->m_aaKeyBindings[i][0] == 0) - continue; - str_format(aBuf, sizeof(aBuf), "%s (%d) = %s", pBinds->Input()->KeyName(i), i, pBinds->m_aaKeyBindings[i]); - pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf); + for(int m = 0; m < MODIFIER_COUNT; m++) + { + if(pBinds->m_aaaKeyBindings[i][m][0] == 0) + continue; + str_format(aBuf, sizeof(aBuf), "%s%s (%d) = %s", GetModifierName(m), pBinds->Input()->KeyName(i), i, pBinds->m_aaaKeyBindings[i][m]); + pBinds->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "binds", aBuf); + } } } -int CBinds::GetKeyID(const char *pKeyName) +int CBinds::DecodeBindString(const char *pKeyName, int* pModifier) { + // check for modifier of type xxx+xxx + char aBuf[64]; + str_copy(aBuf, pKeyName, sizeof(aBuf)); + const char* pStr = str_find(aBuf, "+"); + *pModifier = 0; + if(pStr && *(pStr+1)) // make sure the '+' isn't the last character + { + aBuf[pStr-aBuf] = 0; // *pStr=0 (split the string where the + is) + char* pModifierStr = aBuf; + if(str_comp(pModifierStr, "shift") == 0) + *pModifier = MODIFIER_SHIFT; + else if(str_comp(pModifierStr, "ctrl") == 0) + *pModifier = MODIFIER_CTRL; + else if(str_comp(pModifierStr, "alt") == 0) + *pModifier = MODIFIER_ALT; + else + return 0; + pKeyName = pStr + 1; + if(!pKeyName) + return 0; + } + // check for numeric if(pKeyName[0] == '&') { @@ -205,6 +269,24 @@ int CBinds::GetKeyID(const char *pKeyName) return 0; } + +const char *CBinds::GetModifierName(int m) +{ + switch(m) + { + case 0: + return ""; + case MODIFIER_SHIFT: + return "shift+"; + case MODIFIER_CTRL: + return "ctrl+"; + case MODIFIER_ALT: + return "alt+"; + default: + return ""; + } +} + void CBinds::ConfigSaveCallback(IConfig *pConfig, void *pUserData) { CBinds *pSelf = (CBinds *)pUserData; @@ -213,31 +295,35 @@ void CBinds::ConfigSaveCallback(IConfig *pConfig, void *pUserData) char *pEnd = aBuffer+sizeof(aBuffer)-8; for(int i = 0; i < KEY_LAST; i++) { - if(pSelf->m_aaKeyBindings[i][0] == 0) - continue; - - str_format(aBuffer, sizeof(aBuffer), "bind %s ", pSelf->Input()->KeyName(i)); - - // process the string. we need to escape some characters - const char *pSrc = pSelf->m_aaKeyBindings[i]; - char *pDst = aBuffer + str_length(aBuffer); - *pDst++ = '"'; - while(*pSrc && pDst < pEnd) + for(int m = 0; m < MODIFIER_COUNT; m++) { - if(*pSrc == '"' || *pSrc == '\\') // escape \ and " - *pDst++ = '\\'; - *pDst++ = *pSrc++; - } - *pDst++ = '"'; - *pDst++ = 0; + if(pSelf->m_aaaKeyBindings[i][m][0] == 0) + continue; - pConfig->WriteLine(aBuffer); + str_format(aBuffer, sizeof(aBuffer), "bind %s%s ", GetModifierName(m), pSelf->Input()->KeyName(i)); + + // process the string. we need to escape some characters + const char *pSrc = pSelf->m_aaaKeyBindings[i][m]; + char *pDst = aBuffer + str_length(aBuffer); + *pDst++ = '"'; + while(*pSrc && pDst < pEnd) + { + if(*pSrc == '"' || *pSrc == '\\') // escape \ and " + *pDst++ = '\\'; + *pDst++ = *pSrc++; + } + *pDst++ = '"'; + *pDst++ = 0; + + pConfig->WriteLine(aBuffer); + } } + // default binds can only be non-composed right now, so only check for that for(unsigned j = 0; j < sizeof(s_aDefaultBindKeys)/sizeof(int); j++) { const int i = s_aDefaultBindKeys[j]; - if(pSelf->m_aaKeyBindings[i][0] == 0) + if(pSelf->m_aaaKeyBindings[i][0][0] == 0) { // explicitly unbind keys that were unbound by the user str_format(aBuffer, sizeof(aBuffer), "unbind %s ", pSelf->Input()->KeyName(i)); diff --git a/src/game/client/components/binds.h b/src/game/client/components/binds.h index 3beb3d30b..c701d3933 100644 --- a/src/game/client/components/binds.h +++ b/src/game/client/components/binds.h @@ -7,9 +7,8 @@ class CBinds : public CComponent { - char m_aaKeyBindings[KEY_LAST][128]; - - int GetKeyID(const char *pKeyName); + int DecodeBindString(const char *pKeyName, int* pModifier); + static const char *GetModifierName(int m); static void ConBind(IConsole::IResult *pResult, void *pUserData); static void ConUnbind(IConsole::IResult *pResult, void *pUserData); @@ -29,18 +28,28 @@ public: virtual bool OnInput(IInput::CEvent Event); }; + enum + { + MODIFIER_NONE=0, + MODIFIER_SHIFT, + MODIFIER_CTRL, + MODIFIER_ALT, + MODIFIER_COUNT + }; + CBindsSpecial m_SpecialBinds; - void Bind(int KeyID, const char *pStr); + void Bind(int KeyID, int Modifier, const char *pStr); void SetDefaults(); void UnbindAll(); - const char *Get(int KeyID); - const char *GetKey(const char *pBindStr); + const char *Get(int KeyID, int Modifier); + void GetKey(const char *pBindStr, char aBuf[64]); virtual void OnConsoleInit(); virtual bool OnInput(IInput::CEvent Event); -private: +private: + char m_aaaKeyBindings[KEY_LAST][MODIFIER_COUNT][128]; static const int s_aDefaultBindKeys[]; static const char s_aaDefaultBindValues[][32]; }; diff --git a/src/game/client/components/hud.cpp b/src/game/client/components/hud.cpp index 276f6e718..37af1572f 100644 --- a/src/game/client/components/hud.cpp +++ b/src/game/client/components/hud.cpp @@ -436,13 +436,14 @@ void CHud::RenderVoting() CUIRect Base = {5, 88, 100, 4}; m_pClient->m_pVoting->RenderBars(Base, false); - const char *pYesKey = m_pClient->m_pBinds->GetKey("vote yes"); - const char *pNoKey = m_pClient->m_pBinds->GetKey("vote no"); - str_format(aBuf, sizeof(aBuf), "%s - %s", pYesKey, Localize("Vote yes")); + char aBufYes[64], aBufNo[64]; + m_pClient->m_pBinds->GetKey("vote yes", aBufYes); + m_pClient->m_pBinds->GetKey("vote no", aBufNo); + str_format(aBuf, sizeof(aBuf), "%s - %s", aBufYes, Localize("Vote yes")); Base.y += Base.h+1; UI()->DoLabel(&Base, aBuf, 6.0f, CUI::ALIGN_LEFT); - str_format(aBuf, sizeof(aBuf), "%s - %s", Localize("Vote no"), pNoKey); + str_format(aBuf, sizeof(aBuf), "%s - %s", Localize("Vote no"), aBufNo); UI()->DoLabel(&Base, aBuf, 6.0f, CUI::ALIGN_RIGHT); } diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index fd3c59d91..6369b1e63 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -184,6 +184,7 @@ void CGameClient::OnConsoleInit() m_All.Add(m_pEffects); // doesn't render anything, just updates effects m_All.Add(m_pParticles); // doesn't render anything, just updates all the particles m_All.Add(m_pBinds); + m_All.Add(&m_pBinds->m_SpecialBinds); m_All.Add(m_pControls); m_All.Add(m_pCamera); m_All.Add(m_pSounds);